geertjanw closed pull request #533: [NETBEANS-694] : Support convert to var for diamond operator and other fixes URL: https://github.com/apache/incubator-netbeans/pull/533
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHint.java b/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHint.java index e5d13e21b..8245d9e74 100644 --- a/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHint.java +++ b/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHint.java @@ -19,7 +19,9 @@ package org.netbeans.modules.java.hints.jdk; import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.Scope; +import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.Tree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; @@ -43,6 +45,8 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; +import javax.tools.Diagnostic.Kind; +import org.netbeans.modules.java.hints.errors.Utilities; /** * Hint will convert explicit type of local variable to 'var'. Supported: JDK 10 @@ -67,20 +71,10 @@ public static ErrorDescription computeExplicitToVarType(HintContext ctx) { return null; } - TreePath treePath = ctx.getPath(); - - TreePath initTreePath = ctx.getVariables().get("$init"); //NOI18N - ExpressionTree t = ctx.getInfo().getTreeUtilities().parseExpression(initTreePath.getLeaf().toString(), null); - Scope s = ctx.getInfo().getTrees().getScope(ctx.getPath()); - TypeMirror initTypeMirror = ctx.getInfo().getTreeUtilities().attributeTree(t, s); - - TypeMirror VariableTypeMiror = ctx.getInfo().getTrees().getElement(treePath).asType(); - - // variable initializer type should be same as variable type. - if (!ctx.getInfo().getTypes().isSameType(VariableTypeMiror, initTypeMirror)) { + if(!isValidVarType(ctx)) { return null; } - + return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), Bundle.MSG_ConvertibleToVarType(), new JavaFixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix()); } @@ -106,20 +100,36 @@ protected void performRewrite(TransformationContext tc) throws Exception { WorkingCopy wc = tc.getWorkingCopy(); TreePath statementPath = tc.getPath(); TreeMaker make = wc.getTreeMaker(); - + if (statementPath.getLeaf().getKind() == Tree.Kind.VARIABLE) { VariableTree oldVariableTree = (VariableTree) statementPath.getLeaf(); - + ExpressionTree initializerTree = oldVariableTree.getInitializer(); + if(initializerTree == null) { + return; + } + //check if initializer with diamond operator + if (initializerTree.getKind() == Tree.Kind.NEW_CLASS) { + NewClassTree nct = (NewClassTree)initializerTree; + if (nct.getIdentifier().getKind() == Tree.Kind.PARAMETERIZED_TYPE) { + if(oldVariableTree.getType().getKind() == Tree.Kind.PARAMETERIZED_TYPE) { + ParameterizedTypeTree ptt = (ParameterizedTypeTree) oldVariableTree.getType(); + ParameterizedTypeTree nue = (ParameterizedTypeTree)nct.getIdentifier(); + if(nue.getTypeArguments().isEmpty() && ptt.getTypeArguments().size() > 0) { + //replace diamond operator with type params from lhs + wc.rewrite(nue, ptt); + } + } + } + } VariableTree newVariableTree = make.Variable( oldVariableTree.getModifiers(), oldVariableTree.getName(), make.Type("var"), - oldVariableTree.getInitializer() + initializerTree ); - tc.getWorkingCopy().rewrite(oldVariableTree, newVariableTree); + wc.rewrite(oldVariableTree, newVariableTree); } } - } /** @@ -143,7 +153,7 @@ private static boolean preConditionChecker(HintContext ctx) { return false; } - if (isDiagnosticCodeTobeSkipped(ctx.getInfo())) { + if (isDiagnosticCodeTobeSkipped(ctx.getInfo(), treePath.getLeaf())) { return false; } @@ -156,8 +166,55 @@ private static boolean preConditionChecker(HintContext ctx) { * @param info : compilationInfo * @return true if Diagnostic Code is present in SKIPPED_ERROR_CODES */ - private static boolean isDiagnosticCodeTobeSkipped(CompilationInfo info) { + private static boolean isDiagnosticCodeTobeSkipped(CompilationInfo info, Tree tree) { + long startPos = info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tree); + long endPos = info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tree); + List<Diagnostic> diagnosticsList = info.getDiagnostics(); - return diagnosticsList.stream().anyMatch((d) -> (SKIPPED_ERROR_CODES.contains(d.getCode()))); + if (diagnosticsList.stream().anyMatch((d) + -> ((d.getKind() == Kind.ERROR) && ((d.getStartPosition() >= startPos) && (d.getEndPosition() <= endPos)) && (SKIPPED_ERROR_CODES.contains(d.getCode()))))) { + return true; + } + return false; + } + + private static boolean isValidVarType(HintContext ctx) { + TreePath treePath = ctx.getPath(); + TreePath initTreePath = ctx.getVariables().get("$init"); //NOI18N + + if (initTreePath != null) { + Tree.Kind kind = initTreePath.getLeaf().getKind(); + switch (kind) { + case NEW_CLASS: + NewClassTree nct = (NewClassTree) (initTreePath.getLeaf()); + //anonymous class type + if (nct.getClassBody() != null) { + return false; + } + break; + case NEW_ARRAY: + NewArrayTree nat = (NewArrayTree) ((VariableTree) treePath.getLeaf()).getInitializer(); + //array initializer expr type + if (nat.getType() == null) { + return false; + } + break; + case LAMBDA_EXPRESSION: + return false; + default: + break; + } + } else { + return false; + } + // variable initializer type should be same as variable type. + TypeMirror initTypeMirror = ctx.getInfo().getTrees().getTypeMirror(initTreePath); + TypeMirror variableTypeMirror = ctx.getInfo().getTrees().getElement(treePath).asType(); + + if ((!Utilities.isValidType(initTypeMirror)) || (!ctx.getInfo().getTypes().isSameType(variableTypeMirror, Utilities.resolveCapturedType(ctx.getInfo(), initTypeMirror)))) { + return false; + } + + return true; } } diff --git a/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHintTest.java b/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHintTest.java index 408bcc631..af3a65914 100644 --- a/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHintTest.java +++ b/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToVarHintTest.java @@ -120,6 +120,22 @@ public void testLambdaExprRefToVar() throws Exception { .assertNotContainsWarnings(VAR_CONV_DESC); } + + @Test + public void testArrayInitializerVar() throws Exception { + + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " void m2() {\n" + + " int[] i = {1,2,3};\n" + + " }\n" + + "}\n") + .sourceLevel("1.10") + .run(ConvertToVarHint.class) + .assertNotContainsWarnings(VAR_CONV_DESC); + + } @Test public void testAnonymusObjRefToVar() throws Exception { @@ -191,17 +207,16 @@ public void testArrayRefToVar() throws Exception { @Test public void testDiamondInterfaceRefToVar() throws Exception { HintTest.create() - .setCaretMarker('^') .input("package test;\n" + "import java.util.HashMap;\n" + "public class Test {\n" + " void m1() {\n" - + " final HashMap<String, String> map = new HashMap<>^();\n" + + " final HashMap<String, String> map = new HashMap<>();\n" + " }\n" + "}") .sourceLevel("1.10") .run(ConvertToVarHint.class) - .assertNotContainsWarnings(VAR_CONV_DESC); + .assertContainsWarnings("4:8-4:60:"+VAR_CONV_WARNING); } @Test @@ -326,33 +341,156 @@ public void testMethodAssignToVar() throws Exception { + " }\n" + "}"); } - + @Test - public void testMethod2AssignToVar() throws Exception { + public void testMethodAssignToVar2() throws Exception { HintTest.create() .setCaretMarker('^') .input("package test;\n" - + "import java.util.Collections;\n" - + "import java.util.List;\n" + "import java.util.ArrayList;\n" + "public class Test {\n" + " public static void main(String[] args) {\n" - + " List<String> list = Collections.unmodifiableList(new ArrayList<String>())^;\n" + + " Object obj = m1()^;\n" + + " }\n" + + " static Object m1()\n" + + " {\n" + + " return new ArrayList<String>();\n" + " }\n" + "}") .sourceLevel("1.10") .run(ConvertToVarHint.class) - .findWarning("6:8-6:82:" + VAR_CONV_WARNING) + .findWarning("4:8-4:26:" + VAR_CONV_WARNING) .applyFix() .assertCompilable() .assertVerbatimOutput("package test;\n" - + "import java.util.Collections;\n" - + "import java.util.List;\n" + "import java.util.ArrayList;\n" + "public class Test {\n" + " public static void main(String[] args) {\n" - + " var list = Collections.unmodifiableList(new ArrayList<String>());\n" + + " var obj = m1();\n" + + " }\n" + + " static Object m1()\n" + + " {\n" + + " return new ArrayList<String>();\n" + + " }\n" + + "}"); + } + + @Test + public void testCapturedTypeTypeParamsAssignToVar() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " public void m() {\n" + + " Class<? extends String> aClass = \"x\".getClass();\n" + + " }\n" + + "}") + .sourceLevel("1.10") + .run(ConvertToVarHint.class) + .findWarning("3:8-3:56:" + VAR_CONV_WARNING) + .applyFix() + .assertCompilable() + .assertVerbatimOutput("package test;\n" + + "public class Test {\n" + + " public void m() {\n" + + " var aClass = \"x\".getClass();\n" + + " }\n" + + "}"); + } + + @Test + public void testConvertToVarForCapturedType() throws Exception { + HintTest.create() + .input("package test;\n" + + "import java.util.List;\n" + + "public class Test {\n" + + " void m1() {\n" + + " List<? extends String> ls = null;\n" + + " String s = ls.get(0);\n" + + " }\n" + + "}") + .sourceLevel("1.10") + .run(ConvertToVarHint.class) + .findWarning("5:8-5:29:" + VAR_CONV_WARNING) + .applyFix() + .assertCompilable() + .assertVerbatimOutput("package test;\n" + + "import java.util.List;\n" + + "public class Test {\n" + + " void m1() {\n" + + " List<? extends String> ls = null;\n" + + " var s = ls.get(0);\n" + + " }\n" + + "}"); + } + + @Test + public void testConvertToVarWithDiamondOperator1() throws Exception { + HintTest.create() + .input("package test;\n" + + "import java.util.HashMap;\n" + + "public class Test {\n" + + " void m1() {\n" + + " HashMap<String, String> list = new HashMap<>();\n" + + " }\n" + + "}") + .sourceLevel("1.10") + .run(ConvertToVarHint.class) + .findWarning("4:8-4:55:" + VAR_CONV_WARNING) + .applyFix() + .assertCompilable() + .assertVerbatimOutput("package test;\n" + + "import java.util.HashMap;\n" + + "public class Test {\n" + + " void m1() {\n" + + " var list = new HashMap<String, String>();\n" + + " }\n" + + "}"); + } + + @Test + public void testConvertToVarWithDiamondOperator2() throws Exception { + HintTest.create() + .input("package test;\n" + + "import java.util.ArrayList;\n" + + "public class Test {\n" + + " void m1() {\n" + + " ArrayList<java.util.LinkedList<?>> list = new ArrayList<>();\n" + + " }\n" + + "}") + .sourceLevel("1.10") + .run(ConvertToVarHint.class) + .findWarning("4:8-4:68:" + VAR_CONV_WARNING) + .applyFix() + .assertCompilable() + .assertVerbatimOutput("package test;\n" + + "import java.util.ArrayList;\n" + + "public class Test {\n" + + " void m1() {\n" + + " var list = new ArrayList<java.util.LinkedList<?>>();\n" + + " }\n" + + "}"); + } + + @Test + public void testConvertToVarWithDiamondOperator3() throws Exception { + HintTest.create() + .input("package test;\n" + + "public class Test {\n" + + " void m1() {\n" + + " java.util.HashMap<String, String> list = new java.util.HashMap<>();\n" + + " }\n" + + "}") + .sourceLevel("1.10") + .run(ConvertToVarHint.class) + .findWarning("3:8-3:75:" + VAR_CONV_WARNING) + .applyFix() + .assertCompilable() + .assertVerbatimOutput("package test;\n" + + "public class Test {\n" + + " void m1() {\n" + + " var list = new java.util.HashMap<String, String>();\n" + " }\n" + "}"); } + } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@netbeans.apache.org For additional commands, e-mail: notifications-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists