[NETBEANS-497] Fix for 'var' compound declaration error hints (#521)
* Netbeans-497 issue
* [NETBEANS-497] JDK10-LVTI: Fix for 'var' compound declaration error hints
* [Netbeans-497] Fix for 'var' compound declaration error hints
* [NETBEANS-497] Add isTreeEndsWithComma() API method
* [NETBEANS-497] Update API version
* [Netbeans-497] Change API name
* [NETBEANS-759] Fix Hints of Split into declaration and assignment
* [NETBEANS-497] JDK10-LVTI: Changes method location
* [NETBEANS-497] Add test cases for CasualDiff changes
diff --git a/java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties b/java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties
index cbea9b8..4b69f81 100644
--- a/java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties
+++ b/java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties
@@ -196,3 +196,4 @@
# {0} - the display name of the element whose access should be upgraded to package private
FIX_AccessError_PACKAGE_PRIVATE=Make {0} package private
ImportClassCustomizer.organizeImports.text=Format and sort imports
+FIX_VarCompDeclaration=Split compound declaration
diff --git a/java.hints/src/org/netbeans/modules/java/hints/errors/VarCompDeclaration.java b/java.hints/src/org/netbeans/modules/java/hints/errors/VarCompDeclaration.java
new file mode 100644
index 0000000..9706480
--- /dev/null
+++ b/java.hints/src/org/netbeans/modules/java/hints/errors/VarCompDeclaration.java
@@ -0,0 +1,169 @@
+/*
+ * 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.BlockTree;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePath;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+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.spi.ErrorRule;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.openide.util.NbBundle;
+
+/**
+ * Handle error rule "compiler.err.var.not.allowed.compound"
+ * and provide the fix.
+ * @author vkprabha
+ */
+public class VarCompDeclaration implements ErrorRule<Void> {
+
+ private static final Set<String> ERROR_CODES = new HashSet<String>(Arrays.asList(
+ "compiler.err.var.not.allowed.compound")); // NOI18N
+
+ @Override
+ public Set<String> getCodes() {
+ return Collections.unmodifiableSet(ERROR_CODES);
+ }
+
+ @Override
+ public List<Fix> run(CompilationInfo info, String diagnosticKey, int offset, TreePath treePath, Data<Void> data) {
+
+ Tree.Kind parentKind = treePath.getParentPath().getLeaf().getKind();
+ if (parentKind != Tree.Kind.BLOCK && parentKind != Tree.Kind.CASE) {
+ return null;
+ }
+
+ return Collections.<Fix>singletonList(new VarCompDeclaration.FixImpl(info, treePath).toEditorFix());
+ }
+
+ @Override
+ public String getId() {
+ return VarCompDeclaration.class.getName();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return NbBundle.getMessage(VarCompDeclaration.class, "FIX_VarCompDeclaration"); // NOI18N
+ }
+
+ public String getDescription() {
+ return NbBundle.getMessage(VarCompDeclaration.class, "FIX_VarCompDeclaration"); // NOI18N
+ }
+
+ @Override
+ public void cancel() {
+ }
+
+ private static final class FixImpl extends JavaFix {
+
+ CompilationInfo info;
+ TreePath path;
+
+ public FixImpl(CompilationInfo info, TreePath path) {
+ super(info, path);
+ this.info = info;
+ this.path = path;
+ }
+
+ @Override
+ protected String getText() {
+ return NbBundle.getMessage(VarCompDeclaration.class, "FIX_VarCompDeclaration"); // NOI18N
+ }
+
+ public String toDebugString() {
+ return NbBundle.getMessage(VarCompDeclaration.class, "FIX_VarCompDeclaration"); // NOI18N
+ }
+
+ @Override
+ protected void performRewrite(TransformationContext ctx) throws Exception {
+ TreePath statementPath = ctx.getPath();
+ Tree parent = statementPath.getParentPath().getLeaf();
+ List<? extends StatementTree> statements = null;
+ switch (parent.getKind()) {
+ case BLOCK:
+ statements = ((BlockTree) parent).getStatements();
+ break;
+ case CASE:
+ statements = ((CaseTree) parent).getStatements();
+ break;
+ default:
+ // Ignore other scenario
+ break;
+ }
+ WorkingCopy wc = ctx.getWorkingCopy();
+ TreeMaker make = wc.getTreeMaker();
+ int pos = statements.indexOf(statementPath.getLeaf());
+ List<StatementTree> newStatements = new ArrayList<>();
+ if (pos > 0) {
+ newStatements.addAll(statements.subList(0, pos));
+ }
+
+ int current = 0;
+ for (current = pos; current < statements.size(); current++) {
+ StatementTree t = (StatementTree) statements.get(current);
+ if (t instanceof VariableTree) {
+ VariableTree oldVariableTree = (VariableTree) t;
+ VariableTree newVariableTree = make.Variable(
+ oldVariableTree.getModifiers(),
+ oldVariableTree.getName(),
+ make.Type("var"), // NOI18N
+ oldVariableTree.getInitializer()
+ );
+ newStatements.add(make.asReplacementOf(newVariableTree, oldVariableTree));
+
+ // Check variable tree seperated with ","
+ if(info.getTreeUtilities().isEndOfCompoundVariableDeclaration(t)) break;
+ }
+ }
+ if (current + 1 < statements.size()) {
+ newStatements.addAll(statements.subList(current + 1, statements.size()));
+ }
+
+ Tree target = null;
+
+ switch (parent.getKind()) {
+ case BLOCK:
+ target = make.Block(newStatements, ((BlockTree) parent).isStatic());
+ break;
+ case CASE:
+ target = make.Case(((CaseTree) parent).getExpression(), newStatements);
+ break;
+ default:
+ // Ignore other scenario
+ break;
+ }
+
+ wc.rewrite(parent, target);
+ }
+
+ }
+
+}
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 8ba4c79..6f98b8f 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
@@ -147,6 +147,7 @@
<folder name="errors">
<file name="org-netbeans-modules-java-hints-errors-ImportClass.instance"/>
<file name="org-netbeans-modules-java-hints-errors-AddCast.instance"/>
+ <file name="org-netbeans-modules-java-hints-errors-VarCompDeclaration.instance"/>
<file name="org-netbeans-modules-java-hints-errors-CreateElement.instance"/>
<file name="org-netbeans-modules-java-hints-errors-ChangeMethodParameters.instance"/>
<file name="org-netbeans-modules-java-hints-errors-RenameConstructor.instance"/>
diff --git a/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/Bundle_test.properties b/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/Bundle_test.properties
index 2148f0b..334ec9c 100644
--- a/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/Bundle_test.properties
+++ b/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/Bundle_test.properties
@@ -51,6 +51,7 @@
FIX_AccessError_PUBLIC=FIX_AccessError_PUBLIC:{0}
FIX_AccessError_PROTECTED=FIX_AccessError_PROTECTED:{0}
FIX_AccessError_PACKAGE_PRIVATE=FIX_AccessError_PACKAGE_PRIVATE:{0}
+FIX_VarCompDeclaration=FIX_VarCompDeclaration
LBL_Impl_Abstract_Methods=LBL_Impl_Abstract_Methods
ERR_CannotOverrideAbstractMethods=ERR_CannotOverrideAbstractMethods
diff --git a/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/VarCompDeclarationTest.java b/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/VarCompDeclarationTest.java
new file mode 100644
index 0000000..6851b7d
--- /dev/null
+++ b/java.hints/test/unit/src/org/netbeans/modules/java/hints/errors/VarCompDeclarationTest.java
@@ -0,0 +1,276 @@
+/*
+ * 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.List;
+import java.util.Set;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.modules.java.hints.infrastructure.ErrorHintsTestBase;
+import org.netbeans.modules.java.source.parsing.JavacParser;
+import org.netbeans.spi.editor.hints.Fix;
+import org.openide.util.NbBundle;
+
+/**
+ * Test cases for handing the 'var' compound declaration errors.
+ * @author vkprabha
+ */
+public class VarCompDeclarationTest extends ErrorHintsTestBase {
+
+ public VarCompDeclarationTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ sourceLevel = "1.10";
+ JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
+ }
+
+ public void testCase1() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 1, v1 = 10;\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 1;\n" +
+ " var v1 = 10;\n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase2() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 1, /*comment*/ v1 = 10;\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 1; /*comment*/ \n" +
+ " var v1 = 10;\n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase3() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10, v1 = \"test\";\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10; \n" +
+ " var v1 = \"test\";\n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase4() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10, v1 = 11, test_123 = new Object();\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10; \n" +
+ " var v1 = 11; \n" +
+ " var test_123 = new Object(); \n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase5() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10, v1 = new Runnable(){ \n" +
+ " @Override \n" +
+ " public void run() { \n" +
+ " var x = 10; \n" +
+ " } \n" +
+ " }; \n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10; \n" +
+ " var v1 = new Runnable(){ \n" +
+ " @Override \n" +
+ " public void run() { \n" +
+ " var x = 10; \n" +
+ " } \n" +
+ " }; \n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase6() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10, v1 = 11\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " var v = 10; \n" +
+ " var v1 = 11;} \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase7() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " final @DA var x = 10, y = 11\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " @DA final var x = 10; \n" +
+ " @DA final var y = 11;} \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase8() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " @DA final var v = 1, v1 = 10;\n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " @DA final var v = 1;\n" +
+ " @DA final var v1 = 10;\n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase9() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " var v = 1, v1 = 10;\n" +
+ " } \n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " var v = 1;\n" +
+ " var v1 = 10;\n" +
+ " } \n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ public void testCase10() throws Exception {
+ performFixTest("test/Test.java",
+ "package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " final var v = 1, v1 = 10;\n" +
+ " } \n" +
+ " } \n" +
+ "}",
+ -1,
+ NbBundle.getMessage(VarCompDeclarationTest.class, "FIX_VarCompDeclaration"),
+ ("package test; \n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " final var v = 1;\n" +
+ " final var v1 = 10;\n" +
+ " } \n" +
+ " } \n" +
+ "}").replaceAll("[\\s]+", " "));
+ }
+
+ @Override
+ protected List<Fix> computeFixes(CompilationInfo info, int pos, TreePath path) throws Exception {
+ return new VarCompDeclaration().run(info, null, pos, path, null);
+ }
+
+ @Override
+ protected Set<String> getSupportedErrorKeys() {
+ return new VarCompDeclaration().getCodes();
+ }
+
+ @Override
+ protected String toDebugString(CompilationInfo info, Fix f) {
+ return f.getText();
+ }
+}
diff --git a/java.hints/test/unit/src/org/netbeans/modules/java/hints/suggestions/TinyTest.java b/java.hints/test/unit/src/org/netbeans/modules/java/hints/suggestions/TinyTest.java
index c968302..acb5986 100644
--- a/java.hints/test/unit/src/org/netbeans/modules/java/hints/suggestions/TinyTest.java
+++ b/java.hints/test/unit/src/org/netbeans/modules/java/hints/suggestions/TinyTest.java
@@ -268,6 +268,76 @@
"}\n");
}
+ public void testSplitDeclaration4() throws Exception {
+ HintTest
+ .create()
+ .setCaretMarker('|')
+ .input("package test;\n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " int k =| -1,j = 1;\n" +
+ " break; \n" +
+ " } \n" +
+ " }\n" +
+ "}\n")
+ .sourceLevel("1.7")
+ .run(Tiny.class)
+ .findWarning("6:19-6:19:hint:ERR_splitDeclaration")
+ .applyFix("FIX_splitDeclaration")
+ .assertCompilable()
+ .assertOutput("package test;\n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " int k;\n" +
+ " k = -1;\n" +
+ " int j = 1;\n" +
+ " break; \n" +
+ " } \n" +
+ " }\n" +
+ "}\n");
+ }
+
+ public void testSplitDeclaration5() throws Exception {
+ HintTest
+ .create()
+ .setCaretMarker('|')
+ .input("package test;\n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " final int k =| -1,j = 1;\n" +
+ " break; \n" +
+ " } \n" +
+ " }\n" +
+ "}\n")
+ .sourceLevel("1.7")
+ .run(Tiny.class)
+ .findWarning("6:25-6:25:hint:ERR_splitDeclaration")
+ .applyFix("FIX_splitDeclaration")
+ .assertCompilable()
+ .assertOutput("package test;\n" +
+ "public class Test {\n" +
+ " private void test() { \n" +
+ " int i = 1; \n" +
+ " switch(i){ \n" +
+ " case 1: \n" +
+ " final int k;\n" +
+ " k = -1;\n" +
+ " final int j = 1;\n" +
+ " break; \n" +
+ " } \n" +
+ " }\n" +
+ "}\n");
+ }
+
public void testSplitDeclarationForVar1() throws Exception {
HintTest
.create()
diff --git a/java.source.base/apichanges.xml b/java.source.base/apichanges.xml
index 74d7046..ae8601b 100644
--- a/java.source.base/apichanges.xml
+++ b/java.source.base/apichanges.xml
@@ -50,6 +50,18 @@
</description>
<class name="TreeUtilities" package="org.netbeans.api.java.source"/>
</change>
+ <change id="TreeUtilities.isEndOfCompoundVariableDeclaration">
+ <api name="javasource_base"/>
+ <summary>Check the tree is the end of compound declaration.</summary>
+ <version major="1" minor="2.33"/>
+ <date day="3" month="5" year="2018"/>
+ <author login="vikasprabhakar"/>
+ <compatibility addition="yes" binary="compatible" source="compatible"/>
+ <description>
+ Check the tree end with comma.
+ </description>
+ <class name="TreeUtilities" package="org.netbeans.api.java.source"/>
+ </change>
<change id="ElementHandle.createModuleElementHandle">
<api name="javasource_base"/>
<summary>Added a method to create an <code>ElementHandle</code> for module</summary>
diff --git a/java.source.base/nbproject/project.properties b/java.source.base/nbproject/project.properties
index 4204ad4..8e4b7dd 100644
--- a/java.source.base/nbproject/project.properties
+++ b/java.source.base/nbproject/project.properties
@@ -23,7 +23,7 @@
javadoc.title=Java Source Base
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
-spec.version.base=2.32.0
+spec.version.base=2.33.0
test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/nb-javac-api.jar
test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\
${o.n.core.dir}/lib/boot.jar:\
diff --git a/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java b/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java
index 01438ca..b429dda 100644
--- a/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java
+++ b/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java
@@ -1867,6 +1867,21 @@
}
return false;
}
+
+ /**Check the tree is the end of compound declaration. {@link Tree}.
+ *
+ * @param tree the tree {@link Tree}
+ * @return the true if tree is end of compound declaration else return false
+ * @since 2.33.0
+ */
+ public boolean isEndOfCompoundVariableDeclaration(@NonNull Tree tree) {
+ TokenSequence<JavaTokenId> tokenSequence = tokensFor(tree);
+ tokenSequence.moveEnd();
+ if (tokenSequence.movePrevious() && tokenSequence.token().id() != JavaTokenId.COMMA) {
+ return true;
+ }
+ return false;
+ }
private static final class NBScope implements Scope {
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 c9b89b6..4cef162 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
@@ -1825,15 +1825,21 @@
return bounds[1];
}
PositionEstimator est = EstimatorFactory.statements(
- oldT.getStatements(),
- newT.getStatements(),
+ filterHidden(oldT.stats),
+ filterHidden(newT.stats),
diffContext
);
- localPointer = diffList(oldT.stats, newT.stats, localPointer, est, Measure.MEMBER, printer);
-
- copyTo(localPointer, bounds[1]);
-
- return bounds[1];
+ int old = printer.indent();
+ localPointer = diffInnerComments(oldT, newT, localPointer);
+ JCClassDecl oldEnclosing = printer.enclClass;
+ printer.enclClass = null;
+ localPointer = diffList(filterHidden(oldT.stats), filterHidden(newT.stats), localPointer, est, Measure.MEMBER, printer);
+ printer.enclClass = oldEnclosing;
+ if (localPointer < endPos(oldT)) {
+ copyTo(localPointer, localPointer = endPos(oldT));
+ }
+ printer.undent(old);
+ return localPointer;
}
protected int diffSynchronized(JCSynchronized oldT, JCSynchronized newT, int[] bounds) {
@@ -3728,7 +3734,7 @@
if (!fieldGroup.isEmpty()) {
int oldPos = getOldPos(fieldGroup.get(0));
- if (oldPos != (-1) && oldPos != NOPOS && oldPos == getOldPos(var) && fieldGroup.get(0).getModifiers() == var.getModifiers()) {
+ if (oldPos != (-1) && oldPos != NOPOS && oldPos == getOldPos(var) && fieldGroup.get(0).getModifiers() == var.getModifiers() && !isVarTypeVariable(var)) {
//seems like a field group:
fieldGroup.add(var);
} else {
@@ -4027,6 +4033,16 @@
}
/**
+ * Check the JCVariableDecl tree has var type
+ * @param tree instance of JCVariableDecl
+ * @return true if tree contains var type else return false
+ */
+ private static boolean isVarTypeVariable(JCVariableDecl tree){
+ if(tree == null) return false;
+ return tree.getType() instanceof JCIdent && ((JCIdent)tree.getType()).name.contentEquals("var"); // NOI18N
+ }
+
+ /**
* Retrieves comment set for the specified tree t. The FieldGroupTree is handled specially:
* preceding commenst are taken from the FG's first item, following comments from the last item
* <p/>
diff --git a/java.source.base/test/unit/src/org/netbeans/api/java/source/TreeUtilitiesTest.java b/java.source.base/test/unit/src/org/netbeans/api/java/source/TreeUtilitiesTest.java
index ca0ccbb..dc882e9 100644
--- a/java.source.base/test/unit/src/org/netbeans/api/java/source/TreeUtilitiesTest.java
+++ b/java.source.base/test/unit/src/org/netbeans/api/java/source/TreeUtilitiesTest.java
@@ -584,4 +584,12 @@
}
}, true);
}
+
+ public void testIsEndOfCompoundVariableDeclaration() throws Exception {
+ prepareTest("Test", "package test; public class Test {public Test(){int i = 10, j = 11;}}");
+ TreePath tp = info.getTreeUtilities().pathFor(47);
+ BlockTree bt = (BlockTree) tp.getLeaf();
+ assertFalse(info.getTreeUtilities().isEndOfCompoundVariableDeclaration(bt.getStatements().get(1)));
+ assertTrue(info.getTreeUtilities().isEndOfCompoundVariableDeclaration(bt.getStatements().get(2)));
+ }
}
diff --git a/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/TreeRewriteTestBase.java b/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/TreeRewriteTestBase.java
new file mode 100644
index 0000000..0682a39
--- /dev/null
+++ b/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/TreeRewriteTestBase.java
@@ -0,0 +1,119 @@
+/*
+ * 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 java.io.File;
+import java.io.IOException;
+import javax.swing.JEditorPane;
+import static junit.framework.TestCase.assertNotNull;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.SourceUtilsTestUtil;
+import org.netbeans.api.java.source.TestUtilities;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.core.startup.Main;
+import org.netbeans.modules.editor.java.JavaKit;
+import org.netbeans.modules.java.source.TestUtil;
+import org.netbeans.modules.java.source.save.Reindenter;
+import org.netbeans.modules.java.source.usages.IndexUtil;
+import org.netbeans.modules.parsing.api.indexing.IndexingManager;
+import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+/**
+ *
+ * @author arusinha
+ *
+ * Base test class to check tree rewrite for specific JDK source level.
+ */
+public class TreeRewriteTestBase extends NbTestCase {
+
+ // Default Source level
+ protected String sourceLevel = "1.8"; // NOI18N
+ private File testFile;
+
+ public TreeRewriteTestBase(String testName) {
+ super(testName);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ clearWorkDir();
+
+ // ensure JavaKit is present, so that NbEditorDocument is eventually created.
+ // it handles PositionRefs differently than PlainDocument/PlainEditorKit.
+ MockMimeLookup.setInstances(MimePath.get("text/x-java"),
+ new Reindenter.Factory(), new JavaKit());
+
+ SourceUtilsTestUtil.prepareTest(
+ new String[]{
+ "org/netbeans/modules/java/project/ui/layer.xml",
+ "org/netbeans/modules/project/ui/resources/layer.xml"
+ },
+ new Object[]{}
+ );
+
+ JEditorPane.registerEditorKitForContentType("text/x-java", "org.netbeans.modules.editor.java.JavaKit");
+ File cacheFolder = new File(getWorkDir(), "var/cache/index");
+ cacheFolder.mkdirs();
+ IndexUtil.setCacheFolder(cacheFolder);
+
+ TestUtil.setupEditorMockServices();
+ Main.initializeURLFactory();
+
+ }
+
+ protected void prepareTest(String filename, String code) throws Exception {
+ File work = getWorkDir();
+ FileObject workFO = FileUtil.toFileObject(work);
+
+ assertNotNull(workFO);
+
+ FileObject sourceRoot = workFO.createFolder("src");
+ FileObject buildRoot = workFO.createFolder("build");
+ FileObject packageRoot = sourceRoot.createFolder("test");
+
+ FileObject testSource = packageRoot.createData(filename + ".java");
+
+ assertNotNull(testSource);
+
+ testFile = FileUtil.toFile(testSource);
+
+ TestUtilities.copyStringToFile(FileUtil.toFile(testSource), code);
+
+ SourceUtilsTestUtil.setSourceLevel(testSource, sourceLevel);
+ SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, CacheFolder.getCacheFolder(), new FileObject[0]);
+ //re-index, in order to find classes-living-elsewhere
+ IndexingManager.getDefault().refreshIndexAndWait(sourceRoot.getURL(), null);
+
+ }
+
+ File getTestFile() {
+ assertNotNull(testFile);
+ return testFile;
+ }
+
+ JavaSource getJavaSource() throws IOException {
+ FileObject testSourceFO = FileUtil.toFileObject(getTestFile());
+ return JavaSource.forFileObject(testSourceFO);
+ }
+}
diff --git a/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/VarCompoundDeclarationTest.java b/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/VarCompoundDeclarationTest.java
new file mode 100644
index 0000000..2ef7ffc
--- /dev/null
+++ b/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/VarCompoundDeclarationTest.java
@@ -0,0 +1,274 @@
+/*
+ * 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.BlockTree;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.SwitchTree;
+import com.sun.source.tree.VariableTree;
+import java.io.IOException;
+import java.util.List;
+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;
+
+/**
+ *
+ * @author vkprabha
+ */
+public class VarCompoundDeclarationTest extends TreeRewriteTestBase {
+
+ public VarCompoundDeclarationTest(String testName) {
+ super(testName);
+ }
+
+ public static NbTestSuite suite() {
+ NbTestSuite suite = new NbTestSuite();
+ suite.addTestSuite(VarCompoundDeclarationTest.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 testVarCompoundDeclaration1() throws Exception {
+
+ String code = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " final var x = 10, y = 11;\n"
+ + " }\n"
+ + "}\n";
+ String golden = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " final var x = 10;\n"
+ + " final var y = 11;\n"
+ + " }\n"
+ + "}\n";
+
+ prepareTest("Test", code);
+
+ rewriteBlockStatement();
+ String res = TestUtilities.copyFileToString(getTestFile());
+ System.err.println(res);
+ assertEquals(golden, res);
+
+ }
+
+ public void testVarCompoundDeclaration2() throws Exception {
+
+ String code = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " @DA final var v = 1, v1 = 10;\n"
+ + " }\n"
+ + "}\n";
+
+ String golden = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " @DA\n"
+ + " final var v = 1;\n"
+ + " @DA\n"
+ + " final var v1 = 10;\n"
+ + " }\n"
+ + "}\n";
+
+ prepareTest("Test", code);
+
+ rewriteBlockStatement();
+ String res = TestUtilities.copyFileToString(getTestFile());
+ System.err.println(res);
+ assertEquals(golden, res);
+ }
+
+ public void testVarCompoundDeclaration3() throws Exception {
+ String code = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " int i = 1;\n"
+ + " switch(i){\n"
+ + " case 1:\n"
+ + " var v = 1, v1 = 10;\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+ String golden = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " int i = 1;\n"
+ + " switch(i){\n"
+ + " case 1:\n"
+ + " var v = 1;\n"
+ + " var v1 = 10;\n\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+
+ prepareTest("Test", code);
+
+ rewriteCaseStatement();
+ String res = TestUtilities.copyFileToString(getTestFile());
+ System.err.println(res);
+ assertEquals(golden, res);
+ }
+
+ public void testVarCompoundDeclaration4() throws Exception {
+
+ String code = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " int i = 1;\n"
+ + " switch(i){\n"
+ + " case 1:\n"
+ + " final var v = 1, v1 = 10;\n"
+ + " break;\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+ String golden = "package test;\n"
+ + "public class Test {\n"
+ + " private void test() {\n"
+ + " int i = 1;\n"
+ + " switch(i){\n"
+ + " case 1:\n"
+ + " final var v = 1;\n"
+ + " final var v1 = 10;\n"
+ + " break;\n\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+
+ prepareTest("Test", code);
+
+ rewriteCaseStatement();
+ String res = TestUtilities.copyFileToString(getTestFile());
+ System.err.println(res);
+ assertEquals(golden, res);
+ }
+
+ /**
+ * Fix compound variable declaration in block statement.
+ *
+ * @throws IOException
+ */
+ private void rewriteBlockStatement() 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);
+
+ List<? extends StatementTree> statements = ((BlockTree) method.getBody()).getStatements();
+
+ for (int current = 0; current < statements.size(); current++) {
+ StatementTree t = (StatementTree) statements.get(current);
+ if (t instanceof VariableTree) {
+ VariableTree oldVariableTree = (VariableTree) t;
+ VariableTree newVariableTree = make.Variable(
+ oldVariableTree.getModifiers(),
+ oldVariableTree.getName(),
+ make.Type("var"), // NOI18N
+ oldVariableTree.getInitializer()
+ );
+ workingCopy.rewrite(oldVariableTree, newVariableTree);
+
+ }
+
+ }
+ }
+ };
+
+ js.runModificationTask(task).commit();
+ }
+
+ /**
+ * Fix compound variable declaration in switch-case statement.
+ * array type.
+ * @throws IOException
+ */
+ private void rewriteCaseStatement() 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);
+ SwitchTree st = (SwitchTree) method.getBody().getStatements().get(1);
+
+ CaseTree ct = st.getCases().get(0);
+ List<? extends StatementTree> statements = ct.getStatements();
+
+ for (int current = 0; current < statements.size(); current++) {
+ StatementTree t = (StatementTree) statements.get(current);
+ if (t instanceof VariableTree) {
+ VariableTree oldVariableTree = (VariableTree) t;
+ VariableTree newVariableTree = make.Variable(
+ oldVariableTree.getModifiers(),
+ oldVariableTree.getName(),
+ make.Type("var"), // NOI18N
+ oldVariableTree.getInitializer()
+ );
+ workingCopy.rewrite(oldVariableTree, newVariableTree);
+
+ }
+
+ }
+ }
+ };
+
+ js.runModificationTask(task).commit();
+ }
+
+}