changeset 60377:34a4b316d61a

8248641: Trees.getScope returns incorrect results for code inside a rule case Summary: Ensuring rule cases are copied correctly by TreeCopier. Reviewed-by: vromero
author jlahoda
date Wed, 29 Jul 2020 11:34:24 +0200
parents 9bb80c58c1f2
children 4da240bc298b
files src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java test/langtools/tools/javac/api/TestGetScopeResult.java
diffstat 2 files changed, 110 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Jul 29 10:26:39 2020 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Jul 29 11:34:24 2020 +0200
@@ -154,7 +154,13 @@
         JCCase t = (JCCase) node;
         List<JCExpression> pats = copy(t.pats, p);
         List<JCStatement> stats = copy(t.stats, p);
-        JCTree body = copy(t.body, p);
+        JCTree body;
+        if (node.getCaseKind() == CaseTree.CaseKind.RULE) {
+            body = t.body instanceof JCExpression && t.stats.head.hasTag(Tag.YIELD)
+                    ? ((JCYield) t.stats.head).value : t.stats.head;
+        } else {
+            body = null;
+        }
         return M.at(t.pos).Case(t.caseKind, pats, stats, body);
     }
 
--- a/test/langtools/tools/javac/api/TestGetScopeResult.java	Wed Jul 29 10:26:39 2020 +0100
+++ b/test/langtools/tools/javac/api/TestGetScopeResult.java	Wed Jul 29 11:34:24 2020 +0200
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8205418 8207229 8207230 8230847 8245786 8247334
+ * @bug 8205418 8207229 8207230 8230847 8245786 8247334 8248641
  * @summary Test the outcomes from Trees.getScope
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.comp
@@ -34,6 +34,7 @@
 import java.io.IOException;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import javax.lang.model.element.Element;
@@ -60,11 +61,14 @@
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePathScanner;
 import com.sun.source.util.Trees;
+import com.sun.tools.javac.api.JavacScope;
 
 import com.sun.tools.javac.api.JavacTool;
 import com.sun.tools.javac.comp.Analyzer;
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.tree.JCTree;
+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;
@@ -82,6 +86,7 @@
         new TestGetScopeResult().testCircular();
         new TestGetScopeResult().testRecord();
         new TestGetScopeResult().testLocalRecordAnnotation();
+        new TestGetScopeResult().testRuleCases();
     }
 
     public void run() throws IOException {
@@ -636,6 +641,103 @@
         }
     }
 
+    void testRuleCases() throws IOException {
+        JavacTool c = JavacTool.create();
+        try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) {
+            String code = """
+                          class Test {
+                              void t(int i) {
+                                  long local;
+                                  System.err.println(switch (i) {
+                                    case 0 -> {
+                                        String var;
+                                        int scopeHere;
+                                        yield "";
+                                    }
+                                    default -> {
+                                        String var;
+                                        int scopeHere;
+                                        yield "";
+                                    }
+                                  });
+                                  switch (i) {
+                                    case 0 -> {
+                                        String var;
+                                        int scopeHere;
+                                    }
+                                    default -> {
+                                        String var;
+                                        int scopeHere;
+                                    }
+                                  };
+                                  switch (i) {
+                                    case 0: {
+                                        int checkTree;
+                                    }
+                                  }
+                              }
+                          }
+                          """;
+            class MyFileObject extends SimpleJavaFileObject {
+                MyFileObject() {
+                    super(URI.create("myfo:///Test.java"), SOURCE);
+                }
+                @Override
+                public String getCharContent(boolean ignoreEncodingErrors) {
+                    return code;
+                }
+            }
+            Context ctx = new Context();
+            TestAnalyzer.preRegister(ctx);
+            List<String> options = List.of("--enable-preview",
+                                           "-source", System.getProperty("java.specification.version"));
+            JavacTask t = (JavacTask) c.getTask(null, fm, null, options, null,
+                                                List.of(new MyFileObject()), ctx);
+            CompilationUnitTree cut = t.parse().iterator().next();
+            t.analyze();
+
+            List<List<String>> actual = new ArrayList<>();
+
+            new TreePathScanner<Void, Void>() {
+                @Override
+                public Void visitVariable(VariableTree node, Void p) {
+                    if (node.getName().contentEquals("scopeHere")) {
+                        Scope scope = Trees.instance(t).getScope(getCurrentPath());
+                        actual.add(dumpScope(scope));
+                        JCTree body = getCaseBody(scope);
+                        if (body == null) {
+                            throw new AssertionError("Unexpected null body.");
+                        }
+                    } else if (node.getName().contentEquals("checkTree")) {
+                        Scope scope = Trees.instance(t).getScope(getCurrentPath());
+                        JCTree body = getCaseBody(scope);
+                        if (body != null) {
+                            throw new AssertionError("Unexpected body tree: " + body);
+                        }
+                    }
+                    return super.visitVariable(node, p);
+                }
+                JCTree getCaseBody(Scope scope) {
+                    return ((JCCase) ((JavacScope) scope).getEnv().next.next.tree).body;
+                }
+            }.scan(cut, null);
+
+            List<List<String>> expected =
+                    Collections.nCopies(4,
+                                        List.of("scopeHere:int",
+                                                "var:java.lang.String",
+                                                "local:long",
+                                                "i:int",
+                                                "super:java.lang.Object",
+                                                "this:Test"
+                                            ));
+
+            if (!expected.equals(actual)) {
+                throw new AssertionError("Unexpected Scope content: " + actual);
+            }
+        }
+    }
+
     private List<String> dumpScope(Scope scope) {
         List<String> content = new ArrayList<>();
         while (scope.getEnclosingClass() != null) {