From 03c54d4288dfd70190c3f306a44a8424f268f787 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 12:26:58 +0000 Subject: [PATCH] 8365689: Elements.getFileObjectOf fails with a NullPointerException when an erroneous Element is passed in Reviewed-by: darcy, vromero --- .../sun/tools/javac/model/JavacElements.java | 3 +- .../model/element/TestFileObjectOf.java | 159 +++++++++++++++++- 2 files changed, 159 insertions(+), 3 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index 73219ca38ae..c9bb6cf4182 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -800,6 +800,7 @@ public class JavacElements implements Elements { yield msym.module_info.classfile; } case TYP -> ((ClassSymbol) sym).classfile; + case ERR -> null; default -> sym.enclClass().classfile; }; } diff --git a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java index ad7c701fa5e..4f9703bc428 100644 --- a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java +++ b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8224922 + * @bug 8224922 8365689 * @summary Verify the behavior of the Elements.getFileObjectOf * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -33,6 +33,8 @@ * @run main TestFileObjectOf */ +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; import java.nio.file.Path; @@ -49,6 +51,7 @@ import javax.lang.model.util.Elements; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; import toolbox.JarTask; import toolbox.JavacTask; @@ -592,4 +595,156 @@ public class TestFileObjectOf extends TestRunner { } + @Test //JDK-8365689 + public void testUndefined(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + module m { + requires undefined1; //as module + exports undefined2; //as package + exports test; + } + """, + """ + package test; + public class TestClass { + void t() { + undefined3.call(); + this.undefined4(); + } + } + """); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + //from source, implicit: + { + List log; + + log = new JavacTask(tb) + .options("-XDshould-stop.at=FLOW", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UndefinedPrintFiles.class.getName(), + "-sourcepath", src.toString()) + .outdir(classes) + .classes("java.lang.Object") + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "undefined1: " + "", + "undefined2: " + "", + "undefined3: " + "", + "undefined4: " + "" + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + tb.cleanDirectory(classes); + + //from source, explicit: + { + List log; + + log = new JavacTask(tb) + .options("-XDshould-stop.at=FLOW", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UndefinedPrintFiles.class.getName()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "undefined1: " + "", + "undefined2: " + "", + "undefined3: " + "", + "undefined4: " + "" + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("fromClass") + public static final class UndefinedPrintFiles extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) + return false; + + Elements elements = processingEnv.getElementUtils(); + Trees trees = Trees.instance(processingEnv); + + Queue q = new ArrayDeque<>(); + q.add(elements.getModuleElement("m")); + + while (!q.isEmpty()) { + Element currentElement = q.remove(); + + switch (currentElement.getKind()) { + case MODULE -> { + ElementFilter.exportsIn(((ModuleElement) currentElement).getDirectives()) + .stream() + .map(ed -> ed.getPackage()) + .forEach(q::add); + } + case PACKAGE -> { + currentElement.getEnclosedElements() + .stream() + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) + .forEach(q::add); + continue; + } + default -> {} + } + + TreePath tp = trees.getPath(currentElement); + + new TreePathScanner<>() { + @Override + public Object visitIdentifier(IdentifierTree node, Object p) { + if (node.getName().toString().startsWith("undefined")) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + } + return super.visitIdentifier(node, p); + } + + @Override + public Object visitMemberSelect(MemberSelectTree node, Object p) { + if (node.getIdentifier().toString().startsWith("undefined")) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + } + return super.visitMemberSelect(node, p); + } + }.scan(tp, null); + } + + return false; + } + + void handleDeclaration(Element el) { + Elements elements = processingEnv.getElementUtils(); + JavaFileObject fileObjects = elements.getFileObjectOf(el); + System.out.println(el.getSimpleName() + ": " + (fileObjects != null ? fileObjects.toUri().toString() : "")); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + } }