You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ge...@apache.org on 2018/05/11 18:30:44 UTC
[incubator-netbeans] branch master updated: [NETBEANS-498]
JDK10-LVTI: Provide fix hint to convert var to explicit type (#509)
This is an automated email from the ASF dual-hosted git repository.
geertjan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new a43f54b [NETBEANS-498] JDK10-LVTI: Provide fix hint to convert var to explicit type (#509)
a43f54b is described below
commit a43f54baae947db08387a61e2416724355f38dc2
Author: Reema Taneja <32...@users.noreply.github.com>
AuthorDate: Sat May 12 00:00:42 2018 +0530
[NETBEANS-498] JDK10-LVTI: Provide fix hint to convert var to explicit type (#509)
* [NETBEANS-498] Provide fix hint to convert var to explicit type
* Corrected license info
* corrected hint related display strings
* addressed review comments
* Incorporated review comments, prevent conversion of intersection types
* moved version check outside of TreeUtilities api
* minor change
* Replaced redudant check with specific check for Intersection type
---
.../modules/java/hints/jdk/Bundle.properties | 2 +
.../java/hints/jdk/ConvertVarToExplicitType.java | 170 ++++++++++
.../hints/jdk/ConvertVarToExplicitTypeTest.java | 355 +++++++++++++++++++++
.../modules/java/source/save/CasualDiff.java | 30 +-
4 files changed, 555 insertions(+), 2 deletions(-)
diff --git a/java.hints/src/org/netbeans/modules/java/hints/jdk/Bundle.properties b/java.hints/src/org/netbeans/modules/java/hints/jdk/Bundle.properties
index df35377..6491679 100644
--- a/java.hints/src/org/netbeans/modules/java/hints/jdk/Bundle.properties
+++ b/java.hints/src/org/netbeans/modules/java/hints/jdk/Bundle.properties
@@ -102,3 +102,5 @@ DESC_ConvertIfToSwitch_EmptyDefault=If checked, the hint will generate an empty
DN_CanUseVarForExplicitType=Convert Explicit Type to Var
DESC_CanUseVarForExplicitType=Converts explicit type of local variable to var.
+DN_ConvertVarToExplicitType=Convert Var to Explicit Type
+DESC_ConvertVarToExplicitType=Converts var type local variable to explicit type.
diff --git a/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitType.java b/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitType.java
new file mode 100644
index 0000000..9a09945
--- /dev/null
+++ b/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitType.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.hints.jdk;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePath;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.modules.java.hints.errors.Utilities;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.JavaFix.TransformationContext;
+import org.netbeans.spi.java.hints.TriggerPattern;
+import org.openide.util.NbBundle.Messages;
+
+/**
+ * Hint to convert type in local variable declaration from 'var' to explicit
+ * type
+ *
+ * @author rtaneja
+ */
+@Hint(displayName = "#DN_ConvertVarToExplicitType", description = "#DESC_ConvertVarToExplicitType", category = "rules15", minSourceVersion = "10")
+@Messages("MSG_ConvertibleToExplicitType=Convert var to explicit type")
+public class ConvertVarToExplicitType {
+
+ @TriggerPattern("$mods$ $type $var = $init") //NOI18N
+ public static ErrorDescription convertVarToExplicitType(HintContext ctx) {
+
+ if (!isLocalVarType(ctx)) {
+ return null;
+ }
+ TreePath treePath = ctx.getPath();
+ if (hasDiagnosticErrors(ctx.getInfo(), treePath.getLeaf())) {
+ return null;
+ }
+
+ if (!isValidType(ctx)) {
+ return null;
+ }
+
+ return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), Bundle.MSG_ConvertibleToExplicitType(),
+ new JavaFixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix());
+ }
+
+ /**
+ * Fix for converting local 'var' type to explicit variable type
+ *
+ */
+ private static final class JavaFixImpl extends JavaFix {
+
+ public JavaFixImpl(CompilationInfo info, TreePath tp) {
+ super(info, tp);
+ }
+
+ @Override
+ @Messages("FIX_convertVarToExplicitType=Replace var with explicit type")
+ protected String getText() {
+ return Bundle.FIX_convertVarToExplicitType();
+ }
+
+ @Override
+ protected void performRewrite(TransformationContext tc) throws Exception {
+ WorkingCopy wc = tc.getWorkingCopy();
+ CompilationUnitTree cut = wc.getCompilationUnit();
+ TreePath statementPath = tc.getPath();
+
+ TreeMaker make = wc.getTreeMaker();
+
+ if (statementPath.getLeaf().getKind() == Tree.Kind.VARIABLE) {
+ VariableTree oldVariableTree = (VariableTree) statementPath.getLeaf();
+ TypeMirror type = wc.getTrees().getTypeMirror(statementPath);
+ VariableTree newVariableTree = make.Variable(
+ oldVariableTree.getModifiers(),
+ oldVariableTree.getName(),
+ make.Type(type),
+ oldVariableTree.getInitializer()
+ );
+ wc.rewrite(oldVariableTree, newVariableTree);
+ }
+ }
+
+ }
+
+ /**
+ *
+ * @param ctx : HintContext
+ * @return true if pre-conditions for hint to be enable is meet
+ */
+ private static boolean isLocalVarType(HintContext ctx) {
+
+ CompilationInfo info = ctx.getInfo();
+
+ if (info.getSourceVersion().compareTo(SourceVersion.RELEASE_9) < 1) {
+ return false;
+ }
+
+ TreePath treePath = ctx.getPath();
+
+ // should be local variable
+ if (info.getTrees().getElement(treePath).getKind() != ElementKind.LOCAL_VARIABLE) {
+ return false;
+ }
+
+ // variable declaration of type 'var'
+ return info.getTreeUtilities().isVarType(treePath);
+ }
+
+ private static boolean hasDiagnosticErrors(CompilationInfo info, Tree tree) {
+ long startPos = info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tree);
+ long endPos = info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tree);
+
+ for (Diagnostic<?> d : info.getDiagnostics()) {
+ if (d.getKind() == Kind.ERROR) {
+ if ((d.getPosition() >= startPos) && (d.getPosition() <= endPos)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ //filter anonymous class and intersection types
+ private static boolean isValidType(HintContext ctx) {
+ TreePath treePath = ctx.getPath();
+ TreePath initTreePath = ctx.getVariables().get("$init"); //NOI18N
+
+ if (initTreePath.getLeaf().getKind() == Tree.Kind.NEW_CLASS) {
+ NewClassTree nct = ((NewClassTree) initTreePath.getLeaf());
+ if (nct.getClassBody() != null) {
+ return false;
+ }
+ }
+
+ TypeMirror variableTypeMirror = ctx.getInfo().getTrees().getElement(treePath).asType();
+
+ if (!Utilities.isValidType(variableTypeMirror) ||(variableTypeMirror.getKind() == TypeKind.INTERSECTION)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitTypeTest.java b/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitTypeTest.java
new file mode 100644
index 0000000..3942ee7
--- /dev/null
+++ b/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitTypeTest.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.hints.jdk;
+
+import org.junit.Test;
+import org.netbeans.modules.java.hints.test.api.HintTest;
+
+/**
+ *
+ * @author rtaneja
+ */
+public class ConvertVarToExplicitTypeTest {
+ private static final String VAR_CONV_DESC = "Convert var to explicit type";//NOI18N
+ private static final String VAR_CONV_WARNING = "verifier:" + VAR_CONV_DESC; //NOI18N
+
+ @Test
+ public void testConvertVartoIntType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m1() {\n"
+ + " @Deprecated /*some var*/final /*s*/var var = 10;//s\n"
+ + " }\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("3:8-3:56:"+ VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "public class Test {\n"
+ + " void m1() {\n"
+ + " @Deprecated /*some var*/final /*s*/int var = 10;//s\n"
+ + " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testConvertVarToString() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m1() {\n"
+ + " var str = \"Hello\";\n"
+ + " }\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("3:8-3:26:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "public class Test {\n"
+ + " void m1() {\n"
+ + " String str = \"Hello\";\n"
+ + " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testVartoHashMap() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "import java.util.HashMap;\n"
+ + "public class Test {\n"
+ + " {\n"
+ + " final var map = new HashMap<String, String>();\n"
+ + " }\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("4:8-4:54:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "import java.util.HashMap;\n"
+ + "public class Test {\n"
+ + " {\n"
+ + " final HashMap<String, String> map = new HashMap<String, String>();\n"
+ + " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testNoVarHintForAnonymousObjType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m1() {\n"
+ + " var r = new Runnable() {\n"
+ + " @Override\n"
+ + " public void run() {\n"
+ + " }\n"
+ + " };\n"
+ + " }\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .assertNotContainsWarnings(VAR_CONV_DESC);
+ }
+
+ @Test
+ public void testVarToObjType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m1(){\n"
+ + " var obj = new Object();\n"
+ + " }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("3:8-3:31:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "public class Test {\n"
+ + " void m1(){\n"
+ + " Object obj = new Object();\n"
+ + " }\n"
+ + "}");
+ }
+
+ @Test
+ public void testVarToArrayType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m1(){\n"
+ + " var arr = new int[4][];\n"
+ + " }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("3:8-3:31:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "public class Test {\n"
+ + " void m1(){\n"
+ + " int[][] arr = new int[4][];\n"
+ + " }\n"
+ + "}");
+ }
+
+ @Test
+ public void testVarToIntInsideForLoop() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m2() {\n"
+ + " for (var i = 0; i < 10; i++) {\n"
+ + " i = i + 2;\n"
+ + " }\n"
+ + " }\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("3:13-3:22:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "public class Test {\n"
+ + " void m2() {\n"
+ + " for (int i = 0; i < 10; i++) {\n"
+ + " i = i + 2;\n"
+ + " }\n"
+ + " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testNoHintForExplicitType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + "void m1(){\n"
+ + " int k = 20;\n"
+ + "}\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .assertNotContainsWarnings(VAR_CONV_DESC);
+ }
+
+ @Test
+ public void testVarToMethodRetType1() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "import java.util.ArrayList;\n"
+ + "public class Test {\n"
+ + " public void m() {\n"
+ + " var obj = t();\n"
+ + " }\n"
+ + " Object t()\n"
+ + " {\n"
+ + " return new ArrayList<String>();\n"
+ + " }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("4:8-4:22:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "import java.util.ArrayList;\n"
+ + "public class Test {\n"
+ + " public void m() {\n"
+ + " Object obj = t();\n"
+ + " }\n"
+ + " Object t()\n"
+ + " {\n"
+ + " return new ArrayList<String>();\n"
+ + " }\n"
+ + "}");
+ }
+
+ @Test
+ public void testVarToMethodRetType2() throws Exception {
+ HintTest.create()
+ .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"
+ + " var list = Collections.unmodifiableList(new ArrayList<String>());\n"
+ + " }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("6:8-6:73:" + 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"
+ + " List<String> list = Collections.unmodifiableList(new ArrayList<String>());\n"
+ + " }\n"
+ + "}");
+ }
+
+ @Test
+ public void testNoVarHintForIntersectionType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " var v = get();\n"
+ + " }\n"
+ + " <Z extends Runnable & CharSequence> Z get() { return null; }\n"
+ + "}\n")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .assertNotContainsWarnings(VAR_CONV_DESC);
+ }
+
+ @Test
+ public void testVarToGenericWildCardType() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "import java.util.List;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " List<? extends String> ll = null;\n"
+ + " var l = ll.get(0);\n"
+ + " }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("5:8-5:26:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "import java.util.List;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " List<? extends String> ll = null;\n"
+ + " String l = ll.get(0);\n"
+ + " }\n"
+ + "}");
+ }
+
+ @Test
+ public void testVarToGenericWildCardType2() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "import java.util.List;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " List<?> ll = null;\n"
+ + " var l = ll.get(0);\n"
+ + " }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("5:8-5:26:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "import java.util.List;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " List<?> ll = null;\n"
+ + " Object l = ll.get(0);\n"
+ + " }\n"
+ + "}");
+ }
+
+ @Test
+ public void testVarToGenericType2() throws Exception {
+ HintTest.create()
+ .input("package test;\n"
+ + "import java.util.List;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " var l = listOf(\"\");\n"
+ + " }\n"
+ + " <Z> List<Z> listOf(Z z) { return null; }\n"
+ + "}")
+ .sourceLevel("1.10")
+ .run(ConvertVarToExplicitType.class)
+ .findWarning("4:8-4:27:" + VAR_CONV_WARNING)
+ .applyFix()
+ .assertCompilable()
+ .assertVerbatimOutput("package test;\n"
+ + "import java.util.List;\n"
+ + "public class Test {\n"
+ + " void m() {\n"
+ + " List<String> l = listOf(\"\");\n"
+ + " }\n"
+ + " <Z> List<Z> listOf(Z z) { return null; }\n"
+ + "}");
+ }
+
+}
diff --git a/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java b/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
index e3f2356..c9b89b6 100644
--- a/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
+++ b/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
@@ -1443,7 +1443,12 @@ public class CasualDiff {
int addDimensions = 0;
if (diffContext.syntheticTrees.contains(oldT.vartype)) {
if (!diffContext.syntheticTrees.contains(newT.vartype)) {
- copyTo(localPointer, localPointer = oldT.pos);
+ int varOffset = skipExtraVarKeywordIfPresent(localPointer, oldT.pos);
+
+ if (varOffset == -1) {
+ copyTo(localPointer, oldT.pos);
+ }
+ localPointer = oldT.pos;
printer.suppressVariableType = suppressParameterTypes;
int l = printer.out.length();
printer.print(newT.vartype);
@@ -6027,5 +6032,26 @@ public class CasualDiff {
} catch (Exception ex) {}
return sb.toString();
}
-
+
+ private int skipExtraVarKeywordIfPresent(int start, int end) {
+ int varoffset = -1;
+ int newStart = -1;
+ tokenSequence.move(start);
+ tokenSequence.moveNext();
+ while (tokenSequence.offset() < end) {
+ JavaTokenId token = tokenSequence.token().id();
+ if (token == JavaTokenId.VAR) {
+ varoffset = tokenSequence.offset();
+ copyTo(start, varoffset);
+ } else if (varoffset > -1) {
+ if (token != JavaTokenId.WHITESPACE) {
+ newStart = tokenSequence.offset();
+ copyTo(newStart, end);
+ break;
+ }
+ }
+ tokenSequence.moveNext();
+ }
+ return varoffset;
+ }
}
--
To stop receiving notification emails like this one, please contact
geertjan@apache.org.
---------------------------------------------------------------------
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