From 133ad8e1734f002f013dd3c73d496e323e9e881e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 9 Dec 2022 11:11:46 +0000 Subject: [PATCH] 8297988: NPE in JavacTypes.getOverriddenMethods from doclint Reviewed-by: vromero, jjg --- .../sun/tools/javac/main/JavaCompiler.java | 15 ++- .../tools/javac/modules/EdgeCases.java | 104 +++++++++++++++++- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 8f1cb2df1b5..47e70f5321f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -608,13 +608,22 @@ public CharSequence readSource(JavaFileObject filename) { * @param content The characters to be parsed. */ protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) { + return parse(filename, content, false); + } + + /** Parse contents of input stream. + * @param filename The name of the file from which input stream comes. + * @param content The characters to be parsed. + * @param silent true if TaskListeners should not be notified + */ + private JCCompilationUnit parse(JavaFileObject filename, CharSequence content, boolean silent) { long msec = now(); JCCompilationUnit tree = make.TopLevel(List.nil()); if (content != null) { if (verbose) { log.printVerbose("parsing.started", filename); } - if (!taskListener.isEmpty()) { + if (!taskListener.isEmpty() && !silent) { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename); taskListener.started(e); keepComments = true; @@ -630,7 +639,7 @@ protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) tree.sourcefile = filename; - if (content != null && !taskListener.isEmpty()) { + if (content != null && !taskListener.isEmpty() && !silent) { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree); taskListener.finished(e); } @@ -1800,7 +1809,7 @@ private Name parseAndGetName(JavaFileObject fo, DiagnosticHandler dh = new DiscardDiagnosticHandler(log); JavaFileObject prevSource = log.useSource(fo); try { - JCTree.JCCompilationUnit t = parse(fo, fo.getCharContent(false)); + JCTree.JCCompilationUnit t = parse(fo, fo.getCharContent(false), true); return tree2Name.apply(t); } catch (IOException e) { return null; diff --git a/test/langtools/tools/javac/modules/EdgeCases.java b/test/langtools/tools/javac/modules/EdgeCases.java index 5d699b04b10..ae142f32ccd 100644 --- a/test/langtools/tools/javac/modules/EdgeCases.java +++ b/test/langtools/tools/javac/modules/EdgeCases.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8154283 8167320 8171098 8172809 8173068 8173117 8176045 8177311 8241519 + * @bug 8154283 8167320 8171098 8172809 8173068 8173117 8176045 8177311 8241519 8297988 * @summary tests for multi-module mode compilation * @library /tools/lib * @modules @@ -65,10 +65,13 @@ import javax.tools.ToolProvider; import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; //import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symtab; +import java.util.ArrayList; import toolbox.JarTask; import toolbox.JavacTask; @@ -1047,4 +1050,103 @@ public void testMisnamedModuleInfoClass(Path base) throws Exception { throw new Exception("expected output not found: " + log); } + @Test //JDK-8297988 + public void testExportedNameCheckFromSourceNoEvent(Path base) throws Exception { + //when validating "exports", javac may parse source(s) from the package to check their + //package name. The AST produced by this parse are thrown away, so listeners should not + //be notified: + Path src = base.resolve("src"); + Path m = src.resolve("m"); + tb.writeJavaFiles(m, + """ + module m { + exports test; + } + """, + """ + package test; + public class Test {} + """, + """ + package impl; + public class Impl { + void t() { + test.Test t; + } + } + """); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + record TestCase(Path[] files, String... expectedLog){} + + TestCase[] testCases = new TestCase[] { + new TestCase(new Path[] {m.resolve("module-info.java")}, + "COMPILATION:started:", + "PARSE:started:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "PARSE:finished:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ENTER:started:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ENTER:finished:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ANALYZE:started:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ANALYZE:finished:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "COMPILATION:finished:"), + new TestCase(new Path[] {m.resolve("module-info.java"), + m.resolve("impl").resolve("Impl.java")}, + "COMPILATION:started:", + "PARSE:started:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "PARSE:finished:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "PARSE:started:testExportedNameCheckFromSourceNoEvent/src/m/impl/Impl.java", + "PARSE:finished:testExportedNameCheckFromSourceNoEvent/src/m/impl/Impl.java", + "ENTER:started:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ENTER:started:testExportedNameCheckFromSourceNoEvent/src/m/impl/Impl.java", + "ENTER:finished:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ENTER:finished:testExportedNameCheckFromSourceNoEvent/src/m/impl/Impl.java", + "ANALYZE:started:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ANALYZE:finished:testExportedNameCheckFromSourceNoEvent/src/m/module-info.java", + "ANALYZE:started:testExportedNameCheckFromSourceNoEvent/src/m/impl/Impl.java", + "PARSE:started:testExportedNameCheckFromSourceNoEvent/src/m/test/Test.java", + "PARSE:finished:testExportedNameCheckFromSourceNoEvent/src/m/test/Test.java", + "ENTER:started:testExportedNameCheckFromSourceNoEvent/src/m/test/Test.java", + "ENTER:finished:testExportedNameCheckFromSourceNoEvent/src/m/test/Test.java", + "ANALYZE:finished:testExportedNameCheckFromSourceNoEvent/src/m/impl/Impl.java", + "ANALYZE:started:testExportedNameCheckFromSourceNoEvent/src/m/test/Test.java", + "ANALYZE:finished:testExportedNameCheckFromSourceNoEvent/src/m/test/Test.java", + "COMPILATION:finished:") + }; + + for (TestCase tc : testCases) { + List log = new ArrayList<>(); + + new JavacTask(tb) + .outdir(classes) + .options("--source-path", m.toString(), + "-XDshould-stop.ifNoError=FLOW") + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void started(TaskEvent e) { + record(e, "started"); + } + @Override + public void finished(TaskEvent e) { + record(e, "finished"); + } + private void record(TaskEvent e, String phase) { + JavaFileObject source = e.getSourceFile(); + String sourceName = source != null ? source.getName() : ""; + log.add(e.getKind() + ":" + phase + ":" + sourceName); + } + }); + }) + .files(tc.files) + .run() + .writeAll(); + + if (!List.of(tc.expectedLog).equals(log)) { + throw new AssertionError("Unexpected log, got: " + log + + ", expected: " + List.of(tc.expectedLog)); + } + } + } + }