You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@netbeans.apache.org by GitBox <gi...@apache.org> on 2018/06/18 04:38:51 UTC

[GitHub] jlahoda closed pull request #592: Backport/cherry-pick LVTI fixes for [NETBEANS-777], [NETBEANS-481], [NETBEANS-774], [NETBEANS-778] to release90 Branch

jlahoda closed pull request #592: Backport/cherry-pick LVTI fixes for [NETBEANS-777],[NETBEANS-481],[NETBEANS-774],[NETBEANS-778] to release90 Branch
URL: https://github.com/apache/incubator-netbeans/pull/592
 
 
   

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/errors/ConvertInvalidVarToExplicitArrayType.java b/java.hints/src/org/netbeans/modules/java/hints/errors/ConvertInvalidVarToExplicitArrayType.java
new file mode 100644
index 000000000..9568817dd
--- /dev/null
+++ b/java.hints/src/org/netbeans/modules/java/hints/errors/ConvertInvalidVarToExplicitArrayType.java
@@ -0,0 +1,172 @@
+/*
+ * 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.errors;
+
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.NewArrayTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.TreePath;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.Trees;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.modules.java.hints.spi.ErrorRule;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.openide.util.NbBundle.Messages;
+import javax.lang.model.util.Types;
+
+/**
+ *
+ * @author arusinha
+ */
+@Messages({
+    "DN_ConvertVarToExplicitType=Replace var with explicit type"
+})
+public class ConvertInvalidVarToExplicitArrayType implements ErrorRule<Void> {
+
+    private static final Set<String> CODES;
+
+    static {
+        Set<String> codes = new HashSet<>();
+        codes.add("compiler.err.cant.infer.local.var.type"); // NOI18N
+        CODES = Collections.unmodifiableSet(codes);
+    }
+
+    @Override
+    public Set<String> getCodes() {
+        return CODES;
+    }
+
+    @Override
+    public List<Fix> run(CompilationInfo compilationInfo, String diagnosticKey, int offset, TreePath treePath, Data<Void> data) {
+
+        if (treePath.getParentPath() == null) {
+            return null;
+        }
+
+        TypeMirror arrayType = null;
+        if (treePath.getLeaf().getKind() == Tree.Kind.VARIABLE) {
+            VariableTree oldVariableTree = (VariableTree) treePath.getLeaf();
+
+            ExpressionTree init = oldVariableTree.getInitializer();
+
+            if (init == null || init.getKind() != Tree.Kind.NEW_ARRAY) {
+                return null;
+            }
+
+            NewArrayTree arrayTree = (NewArrayTree) oldVariableTree.getInitializer();
+            List<? extends ExpressionTree> currentValues = arrayTree.getInitializers();
+
+            if (currentValues.isEmpty()) {
+                return null;
+            }
+
+            TreePath initArrayTreePath = new TreePath(treePath, arrayTree);
+            Types types = compilationInfo.getTypes();
+            Trees trees = compilationInfo.getTrees();
+
+            for (ExpressionTree tree : currentValues) {
+
+                TypeMirror etType = trees.getTypeMirror(new TreePath(initArrayTreePath, tree));
+
+                //skipped fix for invalid array member, anonymous class and parameterized array member.
+                if (etType == null || etType.getKind() == TypeKind.ERROR || (etType.getKind() == TypeKind.DECLARED
+                        && !((DeclaredType) etType).getTypeArguments().isEmpty()) || Utilities.isAnonymousType(etType)) {
+                    return null;
+                }
+
+                if (arrayType == null) {
+                    arrayType = etType;
+                } else if (!types.isAssignable(etType, arrayType)) {
+                    if (types.isAssignable(arrayType, etType)) {
+                        arrayType = etType;
+                    } else {
+                        return null; //the array is not sufficiently homogeneous.
+                    }
+                }
+            }
+            return Collections.<Fix>singletonList(new FixImpl(compilationInfo, treePath, arrayType).toEditorFix());
+        }
+        return Collections.<Fix>emptyList();
+
+    }
+
+    @Override
+    public String getId() {
+        return ConvertInvalidVarToExplicitArrayType.class.getName();
+    }
+
+    @Override
+    public String getDisplayName() {
+        return Bundle.DN_ConvertVarToExplicitType();
+    }
+
+    @Override
+    public void cancel() {
+    }
+
+    private static final class FixImpl extends JavaFix {
+
+        private TypeMirror arrayTypeMirror;
+
+        public FixImpl(CompilationInfo info, TreePath tp, TypeMirror arrayType) {
+            super(info, tp);
+            this.arrayTypeMirror = arrayType;
+        }
+
+        @Override
+        protected String getText() {
+            return Bundle.DN_ConvertVarToExplicitType();
+        }
+
+        @Override
+        protected void performRewrite(TransformationContext tc) throws Exception {
+            WorkingCopy wc = tc.getWorkingCopy();
+            wc.toPhase(JavaSource.Phase.RESOLVED);
+            TreePath statementPath = tc.getPath();
+            TreeMaker make = wc.getTreeMaker();
+            VariableTree oldVariableTree = null;
+
+            if (statementPath.getLeaf().getKind() == Tree.Kind.VARIABLE) {
+                oldVariableTree = (VariableTree) statementPath.getLeaf();
+
+                arrayTypeMirror = Utilities.resolveCapturedType(wc, arrayTypeMirror);
+
+                VariableTree newVariableTree = make.Variable(
+                        oldVariableTree.getModifiers(),
+                        oldVariableTree.getName(),
+                        make.ArrayType(make.Type(arrayTypeMirror)),
+                        oldVariableTree.getInitializer()
+                );
+                tc.getWorkingCopy().rewrite(oldVariableTree, newVariableTree);
+            }
+        }
+    }
+}
diff --git a/java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java b/java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java
index 4fb6e5f81..414fa5f8d 100644
--- a/java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java
+++ b/java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java
@@ -138,6 +138,7 @@
 import com.sun.tools.javac.util.Log;
 import java.net.URI;
 import java.util.concurrent.Callable;
+import javax.lang.model.element.NestingKind;
 import javax.lang.model.type.ErrorType;
 import javax.lang.model.type.UnionType;
 import javax.tools.Diagnostic;
@@ -2995,4 +2996,15 @@ public static FileObject getModuleInfo(CompilationInfo info) {
     public static boolean isModular(CompilationInfo info) {
         return getModuleInfo(info) != null;
     }
+    
+    public static boolean isAnonymousType(TypeMirror type) {
+        if (type.getKind() == TypeKind.DECLARED) {
+            DeclaredType dt = (DeclaredType) type;
+            TypeElement typeElem = (TypeElement) dt.asElement();
+            if (typeElem.getNestingKind() == NestingKind.ANONYMOUS) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
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
index 9a0994580..db826e7f3 100644
--- a/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitType.java
+++ b/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertVarToExplicitType.java
@@ -19,12 +19,12 @@
 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.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.tools.Diagnostic;
@@ -151,17 +151,21 @@ private static boolean hasDiagnosticErrors(CompilationInfo info, Tree tree) {
     //filter anonymous class and intersection types
     private static boolean isValidType(HintContext ctx) {
         TreePath treePath = ctx.getPath();
-        TreePath initTreePath = ctx.getVariables().get("$init");  //NOI18N
+        TypeMirror variableTypeMirror = ctx.getInfo().getTrees().getElement(treePath).asType();
 
-        if (initTreePath.getLeaf().getKind() == Tree.Kind.NEW_CLASS) {
-            NewClassTree nct = ((NewClassTree) initTreePath.getLeaf());
-            if (nct.getClassBody() != null) {
-                return false;
+        if (Utilities.isAnonymousType(variableTypeMirror)) {
+            return false;
+        } else if (variableTypeMirror.getKind() == TypeKind.DECLARED) {
+            DeclaredType dt = (DeclaredType) variableTypeMirror;
+            if (dt.getTypeArguments().size() > 0) {
+                for (TypeMirror paramType : dt.getTypeArguments()) {
+                    if (Utilities.isAnonymousType(paramType)) {
+                        return false;
+                    }
+                }
             }
         }
 
-        TypeMirror variableTypeMirror = ctx.getInfo().getTrees().getElement(treePath).asType();
-
         if (!Utilities.isValidType(variableTypeMirror) ||(variableTypeMirror.getKind() == TypeKind.INTERSECTION)) {
             return false;
         }
diff --git a/java.hints/src/org/netbeans/modules/java/hints/resources/layer.xml b/java.hints/src/org/netbeans/modules/java/hints/resources/layer.xml
index 6f98b8f5a..aa9d4e91d 100644
--- a/java.hints/src/org/netbeans/modules/java/hints/resources/layer.xml
+++ b/java.hints/src/org/netbeans/modules/java/hints/resources/layer.xml
@@ -182,6 +182,7 @@
                 <file name="org-netbeans-modules-java-hints-errors-ExtraCatch.instance"/>
                 <file name="org-netbeans-modules-java-hints-errors-TypeErroneous.instance"/>
                 <file name="org-netbeans-modules-java-hints-project-IncompleteClassPath.instance"/>
+                <file name="org-netbeans-modules-java-hints-errors-ConvertInvalidVarToExplicitArrayType.instance"/>
                 <folder name="text">
                     <folder name="x-jsp">
                         <file name="org-netbeans-modules-java-hints-errors-ImportClass.instance"/>
diff --git a/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/ConvertInvalidVarToExplicitArrayTypeTest.java b/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/ConvertInvalidVarToExplicitArrayTypeTest.java
new file mode 100644
index 000000000..a5d79cbee
--- /dev/null
+++ b/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/ConvertInvalidVarToExplicitArrayTypeTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.errors;
+
+import com.sun.source.util.TreePath;
+import java.util.LinkedList;
+import java.util.List;
+import org.netbeans.modules.java.hints.infrastructure.ErrorHintsTestBase;
+import org.netbeans.spi.editor.hints.Fix;
+import org.openide.util.NbBundle;
+import org.netbeans.modules.java.source.parsing.JavacParser;
+import org.netbeans.api.java.source.CompilationInfo;
+
+/**
+ *
+ * @author arusinha
+ */
+public class ConvertInvalidVarToExplicitArrayTypeTest extends ErrorHintsTestBase {
+
+    private static final String FIX_MSG = "Replace var with explicit type"; // NOI18N
+
+    public ConvertInvalidVarToExplicitArrayTypeTest(String name) throws Exception {
+        super(name, ConvertInvalidVarToExplicitArrayType.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        sourceLevel = "1.10";
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = false;
+        super.tearDown();
+    }
+
+        public void testEmptyArrayAsInitializer() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; public class Test {{final var j = {};}}",
+                -1);
+    }
+        
+    public void testInvalidArrayAsInitializer() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; public class Test {{final var j = {int1,var1,\"hello\"};}}",
+                -1);
+    }
+    
+    public void testAnonymousClassTypeArray() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; public class Test {{var j = {new Object(){}};}}",
+                -1);
+    }
+
+    public void testParameterizedElements() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; public class Test {{final var j = {new java.util.ArrayList<String>(),new java.util.ArrayList<String>()};}}",
+                -1);
+    }
+
+    public void testParameterizedElements2() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; import java.util.ArrayList; import java.util.Arrays; public class Test"
+                + "{{ \n"
+                + "     ArrayList<ArrayList<String>> l = new ArrayList<ArrayList<String>>(); \n"
+                + "     ArrayList<String> places = new ArrayList<String>(Arrays.asList(\"New York\", \"Tokyo\"));\n"
+                + "     l.add(places); "
+                + "     final var j = {l.get(0)};"
+                + "}}",
+                -1);
+    }
+
+    public void testMethodInvocation() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; import java.util.ArrayList; import java.util.Arrays; public class Test"
+                + " {{ \n"
+                + "     ArrayList<String> places = new ArrayList<String>(Arrays.asList(\"New York\", \"Tokyo\"));\n"
+                + "     final var j = {places.get(0)};\n"
+                + "}}",
+                -1, FIX_MSG);
+    }
+
+    public void testMethodInvocation2() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test"
+                + " {{ \n"
+                + "     final var arr = {m3()};}"
+                + "     static String m3(){ return new String(\"hello\") ;}"
+                + "}",
+                -1, FIX_MSG, "package test; public class Test {{ final String[] arr = {m3()};} static String m3(){ return new String(\"hello\") ;}}");
+    }
+
+    public void testArrayHetrogeneousElements() throws Exception {
+        performAnalysisTest("test/Test.java",
+                "package test; public class Test {{final/*comment1*/ var/**comment2**/ j/*comment3*/ = /*comment4*/{new java.util.ArrayList(),new java.util.HashMap()};}}",
+                -1);
+    }
+
+    public void testArrayObjectElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{final/*comment1*/ var/**comment2**/ j/*comment3*/ = /*comment4*/{new java.util.ArrayList(),new java.util.ArrayList()};}}",
+                -1, FIX_MSG,
+                "package test; import java.util.ArrayList; public class Test {{final/*comment1*/ ArrayList[]/**comment2**/ j/*comment3*/ = /*comment4*/{new java.util.ArrayList(),new java.util.ArrayList()};}}");
+    }
+
+    public void testArrayPrimitiveNumericElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{final var j = {1,2.1,3f};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{final double[] j = {1,2.1,3f};}}");
+    }
+
+    public void testArrayPrimitiveNumeric2ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{final var j = {(short)1,(byte)2};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{final short[] j = {(short)1,(byte)2};}}");
+    }
+
+    public void testArrayStringElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{/*comment1*/ /*comment2*/@NotNull final var j = {\"hello\",\"world\"};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{/*comment1*/ /*comment2*/@NotNull final String[] j = {\"hello\",\"world\"};}}");
+    }
+
+    public void testArrayObject1ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{@NotNull final var j = {new Object(),new Object()};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{@NotNull final Object[] j = {new Object(),new Object()};}}");
+    }
+
+    public void testArrayObject2ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{@NotNull var j = {new Object(),new Object()};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{@NotNull Object[] j = {new Object(),new Object()};}}");
+    }
+
+    public void testArrayObject3ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{final @NotNull var j = {new Object(),new Object()};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{final @NotNull Object[] j = {new Object(),new Object()};}}");
+    }
+
+    public void testArrayObject4ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{final/*comment1*/var a = {new Object(),new Object()};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{final/*comment1*/Object[] a = {new Object(),new Object()};}}");
+    }
+
+    public void testArrayObject5ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{final/*comment1*/var /*comment2*/ a = {2,3.1f};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{final/*comment1*/float[] /*comment2*/ a = {2,3.1f};}}");
+    }
+
+    public void testArrayObject6ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{/*comment1*/var/*comment2*/ a = {2,3.1f};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{/*comment1*/float[]/*comment2*/ a = {2,3.1f};}}");
+    }
+
+    public void testArrayObject7ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{var/*comment1*/ a = {2,3.1f};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{float[]/*comment1*/ a = {2,3.1f};}}");
+    }
+
+    public void testArrayObject8ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{@NotNull var j = {new Object(),new Object()};}}",
+                -1,
+                FIX_MSG,
+                "package test; public class Test {{@NotNull Object[] j = {new Object(),new Object()};}}");
+    }
+
+    public void testArrayObject9ElementsFix() throws Exception {
+        performFixTest("test/Test.java",
+                "package test; public class Test {{var/*comment1*/ k = {1,'c'};}}",
+                -1, FIX_MSG,
+                "package test; public class Test {{int[]/*comment1*/ k = {1,'c'};}}");
+    }
+
+    protected List<Fix> computeFixes(CompilationInfo info, int pos, TreePath path) {
+        List<Fix> fixes = new ConvertInvalidVarToExplicitArrayType().run(info, null, pos, path, null);
+        List<Fix> result = new LinkedList<Fix>();
+
+        for (Fix f : fixes) {
+            if (f instanceof Fix) {
+                result.add(f);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    protected String toDebugString(CompilationInfo info, Fix f) {
+        return (f.getText());
+    }
+
+    static {
+        NbBundle.setBranding("test");
+    }
+
+}
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
index 3942ee7f5..69bbe476f 100644
--- 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
@@ -350,6 +350,23 @@ public void testVarToGenericType2() throws Exception {
                         + "    }\n"
                         + "    <Z> List<Z> listOf(Z z) { return null; }\n"
                         + "}");
-    }    
-
+    } 
+    
+    @Test
+    public void testNoVarHintForAnonymousType() throws Exception {
+        HintTest.create()
+                .input("package test;\n"
+                        + "public class Test {\n"
+                        + "void v() {\n"
+                        + "  var v = get(new Object(){});\n" 
+                        + "}\n"
+                        + "\n" 
+                        + "<Z> Z get(Z z) {\n" 
+                        + "  return z; \n"
+                        + "}"
+                        + "}")                        
+                .sourceLevel("1.10")
+                .run(ConvertVarToExplicitType.class)
+                .assertNotContainsWarnings(VAR_CONV_WARNING);
+    }
 }
diff --git a/java.lexer/src/org/netbeans/lib/java/lexer/JavaLexer.java b/java.lexer/src/org/netbeans/lib/java/lexer/JavaLexer.java
index 7aa0a6de8..d0a598df8 100644
--- a/java.lexer/src/org/netbeans/lib/java/lexer/JavaLexer.java
+++ b/java.lexer/src/org/netbeans/lib/java/lexer/JavaLexer.java
@@ -1052,9 +1052,9 @@ else if ('0' <= c && c <= '9') { // float literal
                                     if (AFTER_VAR_TOKENS.contains(next.id())) {
                                         do {
                                             next = nextToken();
-                                        } while (AFTER_VAR_TOKENS.contains(next.id()));
+                                        } while (next != null && AFTER_VAR_TOKENS.contains(next.id()));
 
-                                        varKeyword = next.id() == JavaTokenId.IDENTIFIER;
+                                        varKeyword = next != null && next.id() == JavaTokenId.IDENTIFIER;
                                     }
 
                                     input.backup(input.readLengthEOF()- len);
diff --git a/java.lexer/test/unit/src/org/netbeans/lib/java/lexer/JavaLexerBatchTest.java b/java.lexer/test/unit/src/org/netbeans/lib/java/lexer/JavaLexerBatchTest.java
index 927d2eb9a..b87cbddaf 100644
--- a/java.lexer/test/unit/src/org/netbeans/lib/java/lexer/JavaLexerBatchTest.java
+++ b/java.lexer/test/unit/src/org/netbeans/lib/java/lexer/JavaLexerBatchTest.java
@@ -634,4 +634,67 @@ public void testVarIdentWithStringVersion() {
         LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.INT_LITERAL, "0");
         LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.SEMICOLON, ";");
     }
+
+    public void testVarWithIncompleteBlockComment() {
+        String text = "var /* i = 0;";
+        InputAttributes attr = new InputAttributes();
+        attr.setValue(JavaTokenId.language(), "version", (Supplier<String>) () -> {
+            return "10";
+        }, true);
+        TokenHierarchy<?> hi = TokenHierarchy.create(text, false, JavaTokenId.language(), EnumSet.noneOf(JavaTokenId.class), attr);
+        TokenSequence<?> ts = hi.tokenSequence();
+
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.IDENTIFIER, "var");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.BLOCK_COMMENT, "/* i = 0;");
+    }
+
+    public void testVarWithIncompleteJavaDocComment() {
+        String text = "var /** i = 0;";
+        InputAttributes attr = new InputAttributes();
+        attr.setValue(JavaTokenId.language(), "version", (Supplier<String>) () -> {
+            return "10";
+        }, true);
+        TokenHierarchy<?> hi = TokenHierarchy.create(text, false, JavaTokenId.language(), EnumSet.noneOf(JavaTokenId.class), attr);
+        TokenSequence<?> ts = hi.tokenSequence();
+
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.IDENTIFIER, "var");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.JAVADOC_COMMENT, "/** i = 0;");
+    }
+
+    public void testVarWithInvalidComment() {
+        String text = "var */ i = 0;";
+        InputAttributes attr = new InputAttributes();
+        attr.setValue(JavaTokenId.language(), "version", (Supplier<String>) () -> {
+            return "10";
+        }, true);
+        TokenHierarchy<?> hi = TokenHierarchy.create(text, false, JavaTokenId.language(), EnumSet.noneOf(JavaTokenId.class), attr);
+        TokenSequence<?> ts = hi.tokenSequence();
+
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.IDENTIFIER, "var");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.INVALID_COMMENT_END, "*/");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.IDENTIFIER, "i");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.EQ, "=");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.INT_LITERAL, "0");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.SEMICOLON, ";");
+    }
+
+    public void testInvalidVarStatement() {
+        String text = "var ";
+        InputAttributes attr = new InputAttributes();
+        attr.setValue(JavaTokenId.language(), "version", (Supplier<String>) () -> {
+            return "10";
+        }, true);
+        TokenHierarchy<?> hi = TokenHierarchy.create(text, false, JavaTokenId.language(), EnumSet.noneOf(JavaTokenId.class), attr);
+        TokenSequence<?> ts = hi.tokenSequence();
+
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.IDENTIFIER, "var");
+        LexerTestUtilities.assertNextTokenEquals(ts, JavaTokenId.WHITESPACE, " ");
+    }
+
 }
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 4cef162a7..b5cb6bfea 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
@@ -166,6 +166,7 @@
 import org.openide.util.Exceptions;
 import org.openide.util.NbBundle;
 import org.openide.util.NbCollections;
+import javax.lang.model.type.TypeKind;
 
 public class CasualDiff {
 
@@ -1469,8 +1470,72 @@ private int diffVarDef(JCVariableDecl oldT, JCVariableDecl newT, int[] bounds) {
                 addDimensions = dimension(newT.vartype, -1);
                 cLikeArray = vartypeBounds[1] > oldT.pos;
                 cLikeArrayChange =  cLikeArray && dimension(oldT.vartype, oldT.pos) > addDimensions;
-                copyTo(localPointer, vartypeBounds[0]);
+
+                /**
+                 * Extracting modifier from oldTree using symbol position and
+                 * modifier positions when oldT.type is error and vartype
+                 * upperbound is not proper.
+                 */
+                if (oldT.type.getKind() == TypeKind.ERROR && vartypeBounds[1] == -1) {
+
+                    // returns -1 if modifiers not present.
+                    int modsUpperBound = getCommentCorrectedEndPos(oldT.mods);
+                    if (modsUpperBound > -1) {
+                        tokenSequence.move(modsUpperBound);
+
+                        // copying modifiers from oldTree
+                        if (tokenSequence.moveNext()) {
+                            copyTo(localPointer, localPointer = modsUpperBound);
+                        }
+
+                    }
+                    int offset = localPointer;
+                    JavaTokenId tokenId = null;
+                    tokenSequence.move(localPointer);
+
+                    //adding back all whitespaces/block-comment/javadoc-comments present in OldTree before variable type token.
+                    while (tokenSequence.moveNext()) {
+                        offset = tokenSequence.offset();
+                        tokenId = tokenSequence.token().id();
+
+                        if (!((tokenId == JavaTokenId.WHITESPACE || tokenId == JavaTokenId.BLOCK_COMMENT || tokenId == JavaTokenId.JAVADOC_COMMENT) && offset < oldT.sym.pos)) {
+                            break;
+                        }
+
+                    }
+                    copyTo(localPointer, localPointer = offset);
+
+                    // Correcting lower/upper bounds for oldT.vartype tree.
+                    vartypeBounds[1] = oldT.sym.pos;
+                    vartypeBounds[0] = offset;
+
+                } else {
+                    copyTo(localPointer, vartypeBounds[0]);
+
+                }
+
                 localPointer = diffTree(oldT.vartype, newT.vartype, vartypeBounds);
+
+                /**
+                 * For erroneous variable type sometime diffTree function return
+                 * wrong position. In that scenario only old variable type will
+                 * be replaced with new variable type leaving out succeeding
+                 * comments tokens present(if any). Below code copies successive
+                 * tokens after excluding variable type token which will be the
+                 * first token.
+                 */
+                if (oldT.type.getKind() == TypeKind.ERROR && localPointer == -1) {
+                    // moving to variable type token
+                    tokenSequence.move(vartypeBounds[0]);
+                    tokenSequence.moveNext();
+
+                    //moving to first token after variable type token.
+                    if (tokenSequence.moveNext()) {
+                        // copying tokens from vartype bounds after excluding variable type token.
+                        int offset = tokenSequence.offset();
+                        copyTo(offset, localPointer = vartypeBounds[1]);
+                    }
+                }
             }
         }
         if (nameChanged(oldT.name, newT.name)) {
diff --git a/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java b/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
index 20af39302..5b359c523 100644
--- a/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
+++ b/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
@@ -1196,9 +1196,15 @@ public Boolean visitVariable(VariableTree node, Void p) {
                 } else {
                     if (!insideForTryOrCatch)
                         continuationIndent = true;
-                    if (node.getType() == null || scan(node.getType(), p)) {
-                        if (node.getType() != null) {
+                    if (node.getType() == null || tokens.token().id() == JavaTokenId.VAR || scan(node.getType(), p)) {
+                        if (node.getType() != null && tokens.token().id() != JavaTokenId.VAR) {
                             spaces(1, fieldGroup);
+                        } else {
+                            if (tokens.token().id() == JavaTokenId.VAR) {
+                                //Add space after 'var' token
+                                addDiff(new Diff(tokens.offset() + 3, tokens.offset() + 3, " "));
+                                tokens.moveNext();
+                            }
                         }
                         if (!ERROR.contentEquals(node.getName()))
                             accept(IDENTIFIER, UNDERSCORE);
diff --git a/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTestUtil.java b/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTestUtil.java
index 8768ba003..f8214d5de 100644
--- a/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTestUtil.java
+++ b/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTestUtil.java
@@ -40,6 +40,7 @@
 import org.netbeans.editor.BaseDocument;
 import org.netbeans.junit.NbTestCase;
 import org.netbeans.modules.java.JavaDataLoader;
+import org.netbeans.modules.java.source.BootClassPathUtil;
 import org.netbeans.modules.java.source.TestUtil;
 import org.netbeans.modules.java.source.indexing.JavaCustomIndexer;
 import org.netbeans.modules.java.source.parsing.JavacParser;
@@ -280,9 +281,13 @@ public TestProxyClassPathProvider(FileObject sourceRoot, FileObject buildRoot, F
         
         public ClassPath findClassPath(FileObject file, String type) {
             try {
-            if (ClassPath.BOOT == type || JavaClassPathConstants.MODULE_BOOT_PATH.equals(type)) {
-                return ClassPathSupport.createClassPath(getBootClassPath().toArray(new URL[0]));
-            }
+                if (ClassPath.BOOT == type) {
+                   return ClassPathSupport.createClassPath(getBootClassPath().toArray(new URL[0]));
+                }
+             
+                if (JavaClassPathConstants.MODULE_BOOT_PATH == type) {
+                    return BootClassPathUtil.getModuleBootPath();
+                }
             
             if (ClassPath.SOURCE == type) {
                 return ClassPathSupport.createClassPath(new FileObject[] {
diff --git a/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InvalidVarToExplicitArrayConversionTest.java b/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InvalidVarToExplicitArrayConversionTest.java
new file mode 100644
index 000000000..c2c5d984b
--- /dev/null
+++ b/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InvalidVarToExplicitArrayConversionTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.api.java.source.gen;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.VariableTree;
+import java.io.IOException;
+import static junit.framework.TestCase.assertNotNull;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.java.source.TestUtilities;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.junit.NbTestSuite;
+import org.netbeans.modules.java.source.parsing.JavacParser;
+
+/**
+ * Tests conversion of invalid var type variable to explicit array type.
+ *
+ * @author arusinha
+ */
+public class InvalidVarToExplicitArrayConversionTest extends TreeRewriteTestBase {
+
+    public InvalidVarToExplicitArrayConversionTest(String testName) {
+        super(testName);
+    }
+
+    public static NbTestSuite suite() {
+        NbTestSuite suite = new NbTestSuite();
+        suite.addTestSuite(InvalidVarToExplicitArrayConversionTest.class);
+        return suite;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        sourceLevel = "1.10";
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
+
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = false;
+
+    }
+
+    public void testInvalidVarToExplicitArrayConversion() throws Exception {
+
+        String code = "package test;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        final /*comment1*/ var/*comment2*/ k = {1, 'C'};\n"
+                + "    }\n"
+                + "}\n";
+        String golden = "package test;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        final /*comment1*/ int[]/*comment2*/ k = {1, 'C'};\n"
+                + "    }\n"
+                + "}\n";
+
+        prepareTest("Test", code);
+
+        rewriteStatement("int");
+        String res = TestUtilities.copyFileToString(getTestFile());
+        System.err.println(res);
+        assertEquals(golden, res);
+
+    }
+
+    public void testInvalidVarToExplicitArray2Conversion() throws Exception {
+
+        String code = "package test;\n"
+                + "import java.util.ArrayList;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        /*comment1*/var k = {new ArrayList(), new ArrayList()};\n"
+                + "    }\n"
+                + "}\n";
+
+        String golden = "package test;\n"
+                + "import java.util.ArrayList;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        /*comment1*/ArrayList[] k = {new ArrayList(), new ArrayList()};\n"
+                + "    }\n"
+                + "}\n";
+
+        prepareTest("Test", code);
+
+        rewriteStatement("ArrayList");
+        String res = TestUtilities.copyFileToString(getTestFile());
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+
+    public void testInvalidVarToExplicitArray3Conversion() throws Exception {
+        String code = "package test;\n"
+                + "import java.util.ArrayList;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        @NotNull final var j = {\"hello\", \"world\"};\n"
+                + "    }\n"
+                + "}\n";
+        String golden = "package test;\n"
+                + "import java.util.ArrayList;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        @NotNull final String[] j = {\"hello\", \"world\"};\n"
+                + "    }\n"
+                + "}\n";
+
+        prepareTest("Test", code);
+
+        rewriteStatement("String");
+        String res = TestUtilities.copyFileToString(getTestFile());
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+
+    public void testInvalidVarToExplicitArray4Conversion() throws Exception {
+
+        String code = "package test;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        var/*comment2*/ k = {1, 'C'};\n"
+                + "    }\n"
+                + "}\n";
+        String golden = "package test;\n"
+                + "public class Test {\n"
+                + "    void m1() {\n"
+                + "        int[]/*comment2*/ k = {1, 'C'};\n"
+                + "    }\n"
+                + "}\n";
+
+        prepareTest("Test", code);
+
+        rewriteStatement("int");
+        String res = TestUtilities.copyFileToString(getTestFile());
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+
+    /**
+     * Replaces invalid var type array initialization statement with explicit
+     * array type.
+     *
+     * @param arrayType : target explicit array type.
+     * @throws IOException
+     */
+    private void rewriteStatement(String arrayType) throws IOException {
+
+        JavaSource js = getJavaSource();
+        assertNotNull(js);
+
+        Task<WorkingCopy> task = new Task<WorkingCopy>() {
+
+            public void run(WorkingCopy workingCopy) throws IOException {
+                workingCopy.toPhase(JavaSource.Phase.RESOLVED);
+                CompilationUnitTree cut = workingCopy.getCompilationUnit();
+                TreeMaker make = workingCopy.getTreeMaker();
+                ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
+                MethodTree method = (MethodTree) clazz.getMembers().get(1);
+
+                VariableTree oldVariableTree = (VariableTree) method.getBody().getStatements().get(0);
+                VariableTree newVariableTree = make.Variable(
+                        oldVariableTree.getModifiers(),
+                        oldVariableTree.getName(),
+                        make.ArrayType(make.Type(arrayType)),
+                        oldVariableTree.getInitializer()
+                );
+                // converts var type to explicit array type
+                workingCopy.rewrite(oldVariableTree, newVariableTree);
+            }
+        };
+        js.runModificationTask(task).commit();
+    }
+
+}
diff --git a/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java b/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
index 59e8969eb..cda1c9f66 100644
--- a/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
+++ b/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
@@ -4457,6 +4457,64 @@ public void testForNoCondition() throws Exception {
         reformat(doc, content, golden);
     }
 
+    public void testForVar1() throws Exception {
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        String oldLevel = JavaSourceTest.SourceLevelQueryImpl.sourceLevel;
+        JavaSourceTest.SourceLevelQueryImpl.sourceLevel = "1.10";
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public static void main(String[] args) {\n"
+                + "            var    v    =   10; \n"
+                + "    }\n"
+                + "}\n";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public static void main(String[] args) {\n"
+                + "        var v = 10;\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+        JavaSourceTest.SourceLevelQueryImpl.sourceLevel = oldLevel;
+    }
+
+    public void testForVar2() throws Exception {
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        String oldLevel = JavaSourceTest.SourceLevelQueryImpl.sourceLevel;
+        JavaSourceTest.SourceLevelQueryImpl.sourceLevel = "1.10";
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public static void main(String[] args) {\n"
+                + "           final   var    v    =   10; \n"
+                + "    }\n"
+                + "}\n";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public static void main(String[] args) {\n"
+                + "        final var v = 10;\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+        JavaSourceTest.SourceLevelQueryImpl.sourceLevel = oldLevel;
+    }
+
     private void reformat(Document doc, String content, String golden) throws Exception {
         reformat(doc, content, golden, 0, content.length());
     }


 

----------------------------------------------------------------
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:
users@infra.apache.org


With regards,
Apache Git Services

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

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