Skip to content

Commit

Permalink
Fixing handling of pattern matching in instanceof in code generator (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
jlahoda authored Jul 30, 2021
1 parent ee3624e commit 19be548
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public static Tree getBindingPatternType(Tree node) {
}

@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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
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;
Expand Down Expand Up @@ -1958,6 +1959,23 @@ protected int diffSwitchExpression(Tree oldT, Tree newT, int[] bounds) {
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);
Expand Down Expand Up @@ -5730,6 +5748,10 @@ private int diffTreeImpl0(JCTree oldT, JCTree newT, JCTree parent /*used only fo
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
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;
Expand All @@ -48,9 +48,12 @@
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
Expand Down Expand Up @@ -119,9 +122,11 @@ public void release() {
/** 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) {
Expand Down Expand Up @@ -1134,9 +1139,13 @@ protected final TypeCastTree rewriteChildren(TypeCastTree tree) {

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);
Expand Down Expand Up @@ -1405,4 +1414,17 @@ private Tree rewriteChildren(UsesTree tree) {
}
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@
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;
Expand Down Expand Up @@ -197,11 +198,64 @@ public void run(WorkingCopy workingCopy) throws IOException {
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,27 @@ public void testRenameRecordPropa() throws Exception {

}

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>() {
Expand Down Expand Up @@ -1557,4 +1578,14 @@ public void run(CompilationController javac) throws Exception {

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;
}
}
}

0 comments on commit 19be548

Please sign in to comment.