Skip to content

Commit

Permalink
Merge pull request apache#2791 from mishrasandeep/netbeans-4447-2
Browse files Browse the repository at this point in the history
[NETBEANS:4447]:Fixed NullPointerException while computing switch expression
  • Loading branch information
Akshay-Gupta-19 committed Apr 8, 2021
2 parents 0677ccc + 09a0405 commit 7a9d8b2
Show file tree
Hide file tree
Showing 3 changed files with 326 additions and 1 deletion.
Expand Up @@ -875,6 +875,71 @@ public void testSwitch2SwitchExpressionNestedInnerSwitchStatement() throws Excep
" }\n" +
"}\n");
}

public void testSwitchToRuleSwitchFormattingMultiple() throws Exception {
if(!ConvertSwitchToRuleSwitchTest.isJDK14())
return;
HintTest.create()
.input("package test;" +
"public class Test {\n" +
" private void test(int p) {\n" +
" String result;\n" +
" switch (p) {\n" +
" case 0:\n" +
" case 1:\n" +
" case 2:\n" +
" case 3: result=\"a\"; break;\n" +
" default: System.err.println(\"No.\"); break;" +
" }\n" +
" }\n" +
"}\n")
.sourceLevel(SourceVersion.latest().name())
.run(ConvertSwitchToRuleSwitch.class)
.findWarning("3:9-3:15:verifier:" + Bundle.ERR_ConvertSwitchToRuleSwitch())
.applyFix()
.assertCompilable()
.assertVerbatimOutput("package test;" +
"public class Test {\n" +
" private void test(int p) {\n" +
" String result;\n" +
" switch (p) {\n" +
" case 0, 1, 2, 3 -> result=\"a\";\n" +
" default -> System.err.println(\"No.\");\n" +
" }\n" +
" }\n" +
"}\n");
}

public void testSwitchToRuleSwitchFormattingSimple() throws Exception {
if(!ConvertSwitchToRuleSwitchTest.isJDK14())
return;
HintTest.create()
.input("package test;" +
"public class Test {\n" +
" private void test(int p) {\n" +
" String result;\n" +
" switch (p) {\n" +
" case 0: result = \"a\"; break;\n" +
" default: System.err.println(\"No.\"); break;\n" +
" }\n" +
" }\n" +
"}\n")
.sourceLevel(SourceVersion.latest().name())
.run(ConvertSwitchToRuleSwitch.class)
.findWarning("3:9-3:15:verifier:" + Bundle.ERR_ConvertSwitchToRuleSwitch())
.applyFix()
.assertCompilable()
.assertVerbatimOutput("package test;" +
"public class Test {\n" +
" private void test(int p) {\n" +
" String result;\n" +
" switch (p) {\n" +
" case 0 -> result = \"a\";\n" +
" default -> System.err.println(\"No.\");\n" +
" }\n" +
" }\n" +
"}\n");
}

public static Test suite() {
TestSuite suite = new TestSuite();
Expand Down
Expand Up @@ -1904,7 +1904,7 @@ protected int diffSwitch(JCSwitch oldT, JCSwitch newT, int[] bounds) {
copyTo(localPointer, localPointer = tokenSequence.offset());
PositionEstimator est = EstimatorFactory.cases(oldT.getCases(), newT.getCases(), diffContext);
localPointer = diffList(oldT.cases, newT.cases, localPointer, est, Measure.MEMBER, printer);

List<JCCase> cases = newT.cases;
if (cases.size() != 0) {
String caseKind = String.valueOf(CasualDiff.getCaseKind(cases.get(0)));
Expand Down Expand Up @@ -1966,6 +1966,9 @@ protected int diffCase(JCCase oldT, JCCase newT, int[] bounds) {
endpos = endPos(oldPatterns.get(oldPatterns.size() - 1));

if (newPatterns.isEmpty()) {
moveFwdToOneOfTokens(tokenSequence, bounds[0], EnumSet.of(JavaTokenId.CASE));
copyTo = tokenSequence.offset();
copyTo(localPointer, copyTo);
localPointer = copyTo = posHint = endpos;
printer.print("default");
}
Expand Down Expand Up @@ -4163,6 +4166,7 @@ private int diffList(
match = wasInFieldGroup;
for (Iterator<JCTree> it = deletedItems.iterator(); !match && it.hasNext(); ) {
ld = it.next();
// The condition inside if is meant to be an assignment operation and not a comparison
if (match = treesMatch(item.element, ld, false)) {
it.remove();
}
Expand Down
@@ -0,0 +1,256 @@
/*
* 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.ExpressionTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.SwitchTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.tree.JCTree;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.swing.event.ChangeListener;
import static junit.framework.TestCase.assertEquals;
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.TreeShims;
import org.netbeans.modules.java.source.parsing.JavacParser;
import org.netbeans.spi.java.queries.CompilerOptionsQueryImplementation;
import org.openide.filesystems.FileObject;
import org.openide.util.lookup.ServiceProvider;

/**
* Test cases for SwitchExpression
*
*/
public class SwitchRuleFormattingTest extends TreeRewriteTestBase {

private static final List<String> EXTRA_OPTIONS = new ArrayList<>();

public SwitchRuleFormattingTest(String testName) {
super(testName);
}

public static NbTestSuite suite() {
NbTestSuite suite = new NbTestSuite();
suite.addTestSuite(SwitchRuleFormattingTest.class);
return suite;
}

@Override
protected void setUp() throws Exception {
super.setUp();
sourceLevel = "1.13";
JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
EXTRA_OPTIONS.add("--enable-preview");
}

@Override
protected void tearDown() throws Exception {
super.tearDown();
JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = false;

}

@ServiceProvider(service = CompilerOptionsQueryImplementation.class, position = 100)
public static class TestCompilerOptionsQueryImplementation implements CompilerOptionsQueryImplementation {

@Override
public CompilerOptionsQueryImplementation.Result getOptions(FileObject file) {
return new CompilerOptionsQueryImplementation.Result() {
@Override
public List<? extends String> getArguments() {
return EXTRA_OPTIONS;
}

@Override
public void addChangeListener(ChangeListener listener) {
}

@Override
public void removeChangeListener(ChangeListener listener) {
}
};
}

}

public void testSwitchRuleFormatting1() throws Exception {
try {
SourceVersion.valueOf("RELEASE_13");
} catch (IllegalArgumentException ex) {
//OK, skip test
return ;
}

String code = "package test;" +
"public class Test {\n" +
" private void test(int p) {\n" +
" switch (p) {\n" +
" case 0:\n" +
" case 1:\n" +
" case 2:\n" +
" case 3: result=\"a\"; break;\n" +
" default: System.err.println(\"No.\"); break;" +
" }\n" +
" }\n" +
"}\n";
String golden = "package test;" +
"public class Test {\n" +
" private void test(int p) {\n" +
" switch (p) {\n" +
" case 0, 1, 2, 3 -> result=\"a\";\n" +
" default -> System.err.println(\"No.\");\n" +
" }\n" +
" }\n" +
"}\n";

prepareTest("Test", code);

rewriteSwitch();
String res = TestUtilities.copyFileToString(getTestFile());
assertEquals(golden, res);

}

public void testSwitchRuleFormatting2() throws Exception {
try {
SourceVersion.valueOf("RELEASE_13");
} catch (IllegalArgumentException ex) {
//OK, skip test
return ;
}

String code = "package test; \n"
+ "public class Test {\n"
+ " private void test(int p) {\n"
+ " switch (p) {\n" +
" case 0: result = \"a\"; break;\n" +
" case 1: result = \"b\"; break;\n" +
" default: System.err.println(\"No.\"); break;\n"
+ " }\n"
+ " }\n"
+ "}\n";
String golden = "package test; \n"
+ "public class Test {\n"
+ " private void test(int p) {\n"
+ " switch (p) {\n"
+ " case 0 -> result = \"a\";\n" +
" case 1 -> result = \"b\";\n" +
" default -> System.err.println(\"No.\");\n" +
" }\n"
+ " }\n"
+ "}\n";

prepareTest("Test", code);

rewriteSwitch();
String res = TestUtilities.copyFileToString(getTestFile());
assertEquals(golden, res);

}

/**
* Rewrite Switch Expression cases.
*
* @throws IOException
*/
private void rewriteSwitch() 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<CaseTree> newCases = new ArrayList<>();
SwitchTree switchBlock = (SwitchTree) ((BlockTree) method.getBody()).getStatements().get(0);
List<? extends CaseTree> cases;
List<ExpressionTree> patterns = new ArrayList<>();
if(switchBlock!=null){
boolean switchExpressionFlag = switchBlock.getKind().toString().equals(TreeShims.SWITCH_EXPRESSION);
if (switchExpressionFlag) {
cases = TreeShims.getCases(switchBlock);
} else {
cases = ((SwitchTree) switchBlock).getCases();
}
for (Iterator<? extends CaseTree> it = cases.iterator(); it.hasNext();) {
CaseTree ct = it.next();
patterns.addAll(TreeShims.getExpressions(ct));
List<StatementTree> statements;
if (ct.getStatements() == null) {
statements = new ArrayList<>(((JCTree.JCCase) ct).stats);
} else {
statements = new ArrayList<>(ct.getStatements());
if(!statements.isEmpty() && statements.get(statements.size()-1) instanceof JCTree.JCBreak){
statements.remove(statements.size()-1);
}
}
if (statements.isEmpty()) {
if (it.hasNext()) {
continue;
}
}
Set<Element> seenVariables = new HashSet<>();
int idx = 0;
for (StatementTree statement : new ArrayList<>(statements)) {
Tree body = make.Block(statements, false);
if (statements.size() == 1) {
if (statements.get(0).getKind() == Tree.Kind.EXPRESSION_STATEMENT
|| statements.get(0).getKind() == Tree.Kind.THROW
|| statements.get(0).getKind() == Tree.Kind.BLOCK) {
body = statements.get(0);
}
}
newCases.add(make.Case(patterns, body));
patterns = new ArrayList<>();
}
}

workingCopy.rewrite((SwitchTree) switchBlock , make.Switch(((SwitchTree) switchBlock).getExpression(), newCases));
}
}

};

js.runModificationTask(task).commit();
}

}

0 comments on commit 7a9d8b2

Please sign in to comment.