From 5a45de5e1ec5ab3e6ed1f5cefa7b320353bb523f Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 31 Jan 2025 07:56:13 +0000 Subject: [PATCH] 8347989: Trees.getScope may crash for not-yet attributed source Reviewed-by: asotona --- .../com/sun/tools/javac/comp/Enter.java | 4 +- .../tools/javac/api/TestGetScopeResult.java | 91 ++++++++++++++++++- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java index a5744c65f20..c0d955f89a1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -546,7 +546,7 @@ public class Enter extends JCTree.Visitor { // Assert.checkNonNull(c.modle, c.sourcefile.toString()); - result = c.type; + result = tree.type = c.type; } //where /** Does class have the same name as the file it appears in? diff --git a/test/langtools/tools/javac/api/TestGetScopeResult.java b/test/langtools/tools/javac/api/TestGetScopeResult.java index babc7a79170..533c640096e 100644 --- a/test/langtools/tools/javac/api/TestGetScopeResult.java +++ b/test/langtools/tools/javac/api/TestGetScopeResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 8205418 8207229 8207230 8230847 8245786 8247334 8248641 8240658 8246774 8274347 + * @bug 8205418 8207229 8207230 8230847 8245786 8247334 8248641 8240658 8246774 8274347 8347989 * @summary Test the outcomes from Trees.getScope * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.comp @@ -52,6 +52,7 @@ import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.LambdaExpressionTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; +import com.sun.source.tree.ReturnTree; import com.sun.source.tree.Scope; import com.sun.source.tree.Tree; import com.sun.source.tree.VariableTree; @@ -73,7 +74,12 @@ import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context.Factory; +import java.util.Objects; import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; @@ -93,6 +99,7 @@ public class TestGetScopeResult { new TestGetScopeResult().testRuleCases(); new TestGetScopeResult().testNestedSwitchExpression(); new TestGetScopeResult().testModuleImportScope(); + new TestGetScopeResult().testClassTypeSetInEnterGetScope(); } public void run() throws IOException { @@ -885,6 +892,80 @@ public class TestGetScopeResult { } } + //JDK-8347989 + void testClassTypeSetInEnterGetScope() throws IOException { + JavacTool c = JavacTool.create(); + try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { + String code = """ + import java.util.*; + class Test extends ArrayList + implements List { + private int test(boolean b) { + int v = b ? test(!b) : 0; + return v; + } + } + """; + Context ctx = new Context(); + TestAnalyzer.preRegister(ctx); + JavaFileObject input = + SimpleJavaFileObject.forSource(URI.create("myfo:///Test.java"), code); + JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, + List.of(input), + ctx); + Trees trees = Trees.instance(t); + List> actual = new ArrayList<>(); + + t.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ENTER) { + return ; + } + + new TreePathScanner() { + @Override + public Void visitClass(ClassTree node, Void p) { + TypeMirror type = trees.getTypeMirror(getCurrentPath()); + if (type == null) { + throw new AssertionError("Expected class type 'Test', but got: null"); + } + assertEquals(TypeKind.DECLARED, type.getKind()); + DeclaredType decl = (DeclaredType) type; + TypeVariable tvar = (TypeVariable) decl.getTypeArguments().get(0); + assertEquals("T", tvar.asElement().getSimpleName().toString()); + assertEquals("Test&java.lang.CharSequence", tvar.getUpperBound().toString()); + TypeElement clazz = (TypeElement) decl.asElement(); + assertEquals("java.util.ArrayList", clazz.getSuperclass().toString().toString()); + assertEquals("java.util.List", clazz.getInterfaces().toString().toString()); + return super.visitClass(node, p); + } + @Override + public Void visitReturn(ReturnTree rt, Void p) { + Scope scope = trees.getScope(getCurrentPath()); + actual.add(dumpScope(scope)); + return super.visitReturn(rt, p); + } + }.scan(e.getCompilationUnit(), null); + } + }); + + t.analyze(); + + List> expected = + List.of(List.of("v:int", + "b:boolean", + "super:java.util.ArrayList", + "this:Test", + "T:T" + )); + + if (!expected.equals(actual)) { + throw new AssertionError("Unexpected Scope content: " + actual); + } + } + } + private List dumpScope(Scope scope) { List content = new ArrayList<>(); while (scope.getEnclosingClass() != null) { @@ -908,4 +989,10 @@ public class TestGetScopeResult { ", but it is missing."); } + private void assertEquals(Object expected, Object actual) { + if (!Objects.equals(expected, actual)) { + throw new AssertionError("Expected: '" + expected + "', " + + "but got: '" + actual + "'"); + } + } }