You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by sk...@apache.org on 2021/07/30 14:59:24 UTC

[netbeans] branch master updated: Fixing handling of pattern matching in instanceof in code generator (#3053)

This is an automated email from the ASF dual-hosted git repository.

skygo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 19be548  Fixing handling of pattern matching in instanceof in code generator (#3053)
19be548 is described below

commit 19be548f0bc53ecac53122e478a37e27ce344118
Author: Jan Lahoda <jl...@netbeans.org>
AuthorDate: Fri Jul 30 16:59:09 2021 +0200

    Fixing handling of pattern matching in instanceof in code generator (#3053)
---
 .../netbeans/modules/java/source/TreeShims.java    |  2 +-
 .../modules/java/source/save/CasualDiff.java       | 22 ++++++++
 .../source/transform/ImmutableTreeTranslator.java  | 34 +++++++++---
 .../api/java/source/gen/InstanceOfTest.java        | 62 ++++++++++++++++++++--
 .../modules/refactoring/java/test/RenameTest.java  | 31 +++++++++++
 5 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
index ed13513..4cb0807 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
@@ -256,7 +256,7 @@ public class TreeShims {
     }
 
     @SuppressWarnings("unchecked")
-    private static <T extends Throwable> RuntimeException throwAny(Throwable t) throws T {
+    public static <T extends Throwable> RuntimeException throwAny(Throwable t) throws T {
         throw (T) t;
     }
     public static boolean isRecord(Element el) {
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
index 7979b08..5b879c2 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
@@ -132,6 +132,7 @@ import com.sun.tools.javac.util.Position;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.*;
 import java.util.Map.Entry;
@@ -1958,6 +1959,23 @@ public class CasualDiff {
         return bounds[1];
     }
 
+    protected int diffBindingPattern(Tree oldT, Tree newT, int[] bounds) {
+        VariableTree oldVar = getBindingVariableTree(oldT);
+        VariableTree newVar = getBindingVariableTree(newT);
+
+        return diffTree((JCTree) oldVar, (JCTree) newVar, bounds);
+    }
+
+    @NbBundle.Messages("ERR_PatternMatchingInstanceOf=Transformation for pattern matching in instanceof not supported on this version of JDK. Please run on JDK 16 or newer, or install nb-javac.")
+    public static VariableTree getBindingVariableTree(Tree node) {
+        try {
+            Class bpt = Class.forName("com.sun.source.tree.BindingPatternTree"); //NOI18N
+            return (VariableTree)bpt.getDeclaredMethod("getVariable").invoke(node); //NOI18N
+        } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(Exceptions.attachLocalizedMessage(ex, Bundle.ERR_PatternMatchingInstanceOf()));
+        }
+    }
+
     protected int diffCase(JCCase oldT, JCCase newT, int[] bounds) {
         int localPointer = bounds[0];
         List<JCExpression> oldPatterns = getCasePatterns(oldT);
@@ -5730,6 +5748,10 @@ public class CasualDiff {
                   retVal = diffSwitchExpression(oldT, newT, elementBounds);
                   break;
               }
+              if(oldT.getKind().toString().equals(TreeShims.BINDING_PATTERN)){
+                  retVal = diffBindingPattern(oldT, newT, elementBounds);
+                  break;
+              }
               String msg = "Diff not implemented: " +
                   ((com.sun.source.tree.Tree)oldT).getKind().toString() +
                   " " + oldT.getClass().getName();
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java b/java/java.source.base/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java
index 85d1461..b490380 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java
@@ -24,10 +24,10 @@ import com.sun.source.tree.*;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.model.JavacElements;
-import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.tree.JCTree.JCLambda;
 import com.sun.tools.javac.tree.JCTree.JCModifiers;
 import com.sun.tools.javac.util.Context;
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -48,9 +48,12 @@ import org.netbeans.modules.java.source.builder.QualIdentTree;
 import org.netbeans.modules.java.source.builder.TreeFactory;
 import org.netbeans.modules.java.source.pretty.ImportAnalysis2;
 import org.netbeans.modules.java.source.query.CommentHandler;
+import org.netbeans.modules.java.source.save.CasualDiff;
 import org.netbeans.modules.java.source.save.ElementOverlay;
 
 import static org.netbeans.modules.java.source.save.PositionEstimator.*;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
 
 /** A subclass of Tree.Visitor, this class defines
  *  a general tree translator pattern. Translation proceeds recursively in
@@ -119,9 +122,11 @@ public class ImmutableTreeTranslator implements TreeVisitor<Tree,Object> {
     /** Visitor method: Translate a single node.
      */
     public Tree translate(Tree tree) {
-	if (tree == null)
+	if (tree == null) {
 	    return null;
-	else {
+        } else if (tree.getKind().name().equals(TreeShims.BINDING_PATTERN)) {
+            return rewriteChildrenBindingPattern(tree);
+        } else {
 	    Tree t = tree.accept(this, null);
             
             if (tree2Tag != null && tree != t && tmaker != null) {
@@ -1134,9 +1139,13 @@ public class ImmutableTreeTranslator implements TreeVisitor<Tree,Object> {
     
     protected final InstanceOfTree rewriteChildren(InstanceOfTree tree) {
 	ExpressionTree expr = (ExpressionTree)translate(tree.getExpression());
-	Tree clazz = translateClassRef(tree.getType());
-	if (expr!=tree.getExpression() || clazz!=tree.getType()) {
-	    InstanceOfTree n = make.InstanceOf(expr, clazz);
+        Tree origPattern = TreeShims.getPattern(tree);
+        if (origPattern == null) {
+            origPattern = tree.getType();
+        }
+	Tree newPattern = translate(origPattern);
+	if (expr!=tree.getExpression() || newPattern!=origPattern) {
+	    InstanceOfTree n = make.InstanceOf(expr, newPattern);
             model.setType(n, model.getType(tree));
 	    copyCommentTo(tree,n);
             copyPosTo(tree,n);
@@ -1405,4 +1414,17 @@ public class ImmutableTreeTranslator implements TreeVisitor<Tree,Object> {
 	}
 	return tree;
     }
+
+    private Tree rewriteChildrenBindingPattern(Tree tree) {
+        VariableTree var = CasualDiff.getBindingVariableTree(tree); //replace with tree.getVariable when javac supported is 16+:
+        VariableTree newVar = (VariableTree) translate(var);
+        if (newVar != var) {
+            Tree n = make.BindingPattern(newVar);
+            model.setType(n, model.getType(tree));
+            copyCommentTo(tree,n);
+            copyPosTo(tree,n);
+            tree = n;
+        }
+        return tree;
+    }
 }
diff --git a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java
index 19cc98d..aff6ea1 100644
--- a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java
+++ b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java
@@ -21,16 +21,17 @@ package org.netbeans.api.java.source.gen;
 import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.IfTree;
 import com.sun.source.tree.InstanceOfTree;
 import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.ParenthesizedTree;
+import com.sun.source.tree.Tree;
 import com.sun.source.tree.VariableTree;
-import com.sun.tools.javac.tree.JCTree;
+import com.sun.source.util.TreeScanner;
 import java.io.File;
 import java.io.IOException;
 import java.util.EnumSet;
-import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Modifier;
 import org.netbeans.api.java.source.Task;
 import org.netbeans.api.java.source.JavaSource;
@@ -197,11 +198,64 @@ public class InstanceOfTest extends GeneratorTestMDRCompat {
         assertEquals(golden, res);
     }
     
+    public void testRenamePatternMatchingType() throws Exception {
+        if (!typeTestPatternAvailable())
+            return ;
+
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile,
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public boolean taragui(Object o) {\n" +
+            "        return o instanceof Test t;\n" +
+            "    }\n" +
+            "}\n"
+            );
+        String golden =
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public boolean taragui(Object o) {\n" +
+            "        return o2 instanceof Test2 t;\n" +
+            "    }\n" +
+            "}\n";
+        JavaSource src = getJavaSource(testFile);
+
+        Task<WorkingCopy> task = new Task<WorkingCopy>() {
+
+            public void run(WorkingCopy workingCopy) throws IOException {
+                workingCopy.toPhase(Phase.RESOLVED);
+                CompilationUnitTree cut = workingCopy.getCompilationUnit();
+                TreeMaker make = workingCopy.getTreeMaker();
+                new TreeScanner<Void, Void>() {
+                    @Override
+                    public Void visitVariable(VariableTree node, Void p) {
+                        if (node.getName().contentEquals("t")) {
+                            workingCopy.rewrite(node.getType(), make.Identifier("Test2"));
+                        }
+                        return super.visitVariable(node, p);
+                    }
+                    @Override
+                    public Void visitIdentifier(IdentifierTree node, Void p) {
+                        if (node.getName().contentEquals("o")) {
+                            workingCopy.rewrite(node, workingCopy.getTreeMaker().setLabel(node, "o2"));
+                        }
+                        return super.visitIdentifier(node, p);
+                    }
+                }.scan(cut, null);
+            }
+
+        };
+        src.runModificationTask(task).commit();
+        String res = TestUtilities.copyFileToString(testFile);
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+
     private boolean typeTestPatternAvailable() {
         try {
-            Class.forName("com.sun.source.tree.BindingPatternTree", false, JCTree.class.getClassLoader());
+            Class.forName("com.sun.source.tree.BindingPatternTree", false, Tree.class.getClassLoader()).getDeclaredMethod("getVariable");
             return true;
-        } catch (ClassNotFoundException ex) {
+        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
             //OK
             return false;
         }
diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameTest.java b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameTest.java
index 0f2686f..f3d878d 100644
--- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameTest.java
+++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameTest.java
@@ -1483,6 +1483,27 @@ public class RenameTest extends RefactoringTestBase {
 
     }
 
+    public void testRenameBindingVariableType() throws Exception {
+        if (!typeTestPatternAvailable()) return; //only run the test when javac supports it
+        writeFilesAndWaitForScan(src,
+                new File("t/A.java", "package t;\n"
+                + "public class A {\n"
+                + "    public boolean taragui(Object o) {\n"
+                + "        return o instanceof A a && a.toString() != null;\n"
+                + "    }\n"
+                + "}"));
+        JavaRenameProperties props = new JavaRenameProperties();
+        performRename(src.getFileObject("t/A.java"), 25, "B", props, true);
+        verifyContent(src,
+                new File("t/A.java", "package t;\n"
+                + "public class B {\n"
+                + "    public boolean taragui(Object o) {\n"
+                + "        return o instanceof B a && a.toString() != null;\n"
+                + "    }\n"
+                + "}"));
+
+    }
+
     private void performRename(FileObject source, final int position, final int position2, final String newname, final JavaRenameProperties props, final boolean searchInComments, Problem... expectedProblems) throws Exception {
         final RenameRefactoring[] r = new RenameRefactoring[1];
         JavaSource.forFileObject(source).runUserActionTask(new Task<CompilationController>() {
@@ -1557,4 +1578,14 @@ public class RenameTest extends RefactoringTestBase {
 
         assertProblems(Arrays.asList(expectedProblems), problems);
     }
+
+    private boolean typeTestPatternAvailable() {
+        try {
+            Class.forName("com.sun.source.tree.BindingPatternTree", false, Tree.class.getClassLoader()).getDeclaredMethod("getVariable");
+            return true;
+        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+            //OK
+            return false;
+        }
+    }
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists