InstanceOfTest.java
/*
* Copyright (C) 2013-2024 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package com.github.javaparser.symbolsolver.resolution;
import static org.junit.jupiter.api.Assertions.*;
import com.github.javaparser.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.BinaryExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.resolution.Navigator;
import com.github.javaparser.resolution.TypeSolver;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
public class InstanceOfTest {
private CompilationUnit parse(String code) {
TypeSolver typeSolver = new ReflectionTypeSolver();
ParserConfiguration parserConfiguration = new ParserConfiguration();
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
parserConfiguration.setLanguageLevel(ParserConfiguration.LanguageLevel.BLEEDING_EDGE);
return new JavaParser(parserConfiguration).parse(code).getResult().get();
}
protected final TypeSolver typeSolver = new ReflectionTypeSolver();
/**
* Locations:
* - Local variables
* - If conditionals
* <p>
* - Usage after declaration
* - Usage before declaration
* <p>
* Simple:
* - A && B Resolves instanceof String s && s
* - A || B Not instanceof String s || s
* <p>
* Negated:
* - !A && B Not
* <p>
* If/Else If/Else Blocks
* - if(A) { Resolves }
* - if(!A) { Not }
* <p>
* - if() {} else if (A) { Resolves }
* - if() {} else if (!A) { Not }
*/
protected final String sourceCode = "" + "import java.util.List;\n"
+ "\n"
+ "class X {\n"
+ "\n"
+ " public void localVariable_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " boolean condition = obj instanceof String s;\n"
+ " boolean result = s.contains(\"fails - not in scope\");\n"
+ " }\n"
+ "\n"
+ " public void localVariable_shouldNotResolve_usageFollowsDeclaration_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " boolean condition = obj instanceof String s;\n"
+ " boolean result;\n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " }\n"
+ "\n"
+ " public void localVariable_shouldNotResolve_usagePreceedsDeclaration_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " boolean result;\n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " boolean condition = obj instanceof String s;\n"
+ " }\n"
+ "\n"
+ " public void localVariable_shouldNotResolve_logicalAnd_shouldResolve() {\n"
+ " String obj = \"abc\";\n"
+ " boolean condition = obj instanceof String s && s.contains(\"in scope\");\n"
+ " }\n"
+ "\n"
+ " public void localVariable_shouldNotResolve_logicalOr_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " boolean condition = obj instanceof String s || s.contains(\"fails - not in scope\");\n"
+ " }\n"
+ "\n"
+ " public void if_conditional_emptyBlock_logicalAnd_shouldResolve() {\n"
+ " String obj = \"abc\";\n"
+ " if (obj instanceof String s && s.contains(\"in scope\")) {\n"
+ " // Empty BlockStmt\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void if_conditional_emptyBlock_logicalOr_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " if (obj instanceof String s || s.contains(\"fails - not in scope\")) {\n"
+ " // Empty BlockStmt\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void if_conditional_negated_shouldResolveToLocalVariableNotPattern() {\n"
+ " List<Integer> s;\n"
+ " boolean result;\n"
+ " String obj = \"abc\";\n"
+ " if (!(obj instanceof String s) && true) {\n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void if_else_conditional_mixedResolveResults() {\n"
+ " boolean result;\n"
+ " String obj = \"abc\";\n"
+ " if ((obj instanceof String s) && true) {\n"
+ " result = s.contains(\"in scope\");\n"
+ " } else {\n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void if_else_conditional_negated_mixedResolveResults() {\n"
+ " boolean result;\n"
+ " String obj = \"abc\";\n"
+ " if (!(obj instanceof String s) && true) {\n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " } else {\n"
+ " result = s.contains(\"in scope\");\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void if_conditional_usageBeforeDeclaration_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " if(s.contains(\"fails - not in scope\") && obj instanceof String s) {\n"
+ " // Empty BlockStmt\n"
+ " }\n"
+ " \n"
+ " }\n"
+ "\n"
+ " public void if_conditional_1_mixedResolveResults() {\n"
+ " boolean result;\n"
+ " String obj = \"abc\";\n"
+ " if ((obj instanceof String s) && true) {\n"
+ " result = s.contains(\"in scope\");\n"
+ " } else {\n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void if_conditional_negated_no_braces_on_if_shouldResolveToLocalVariableNotPattern() {\n"
+ " List<Integer> s;\n"
+ " boolean result;\n"
+ " String obj = \"abc\";\n"
+ " if (!(obj instanceof String s) && true) \n"
+ " result = s.contains(\"fails - not in scope\");\n"
+ " \n"
+ " }\n"
+ "\n"
+ " public void if_conditional_OR_shouldNotResolve() {\n"
+ " String obj = \"abc\";\n"
+ " if(obj instanceof String s || s.contains(\"fails - not in scope\")) {\n"
+ " // Empty BlockStmt\n"
+ " }\n"
+ " }\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "}\n";
protected CompilationUnit compilationUnit;
@BeforeEach
public void setup() {
compilationUnit = parseWithTypeSolver(ParserConfiguration.LanguageLevel.JAVA_14_PREVIEW, sourceCode);
}
@Test
public void givenInstanceOfPattern_usingJdk13_thenExpectException() {
final String x = "" + "class X {\n"
+ " public X() {\n"
+ " boolean result;\n"
+ " String obj = \"abc\";\n"
+ " if (!(obj instanceof String s) && true) {\n"
+ " result = s.contains(\"b\");\n"
+ " }\n"
+ " }\n"
+ " }\n";
ParserConfiguration parserConfiguration = new ParserConfiguration();
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
parserConfiguration.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_13);
ParseResult<CompilationUnit> parseResult =
new JavaParser(parserConfiguration).parse(ParseStart.COMPILATION_UNIT, new StringProvider(x));
assertEquals(1, parseResult.getProblems().size());
assertEquals(
"Use of patterns with instanceof is not supported. Pay attention that this feature is supported starting from 'JAVA_14' language level. If you need that feature the language level must be configured in the configuration before parsing the source files.",
parseResult.getProblem(0).getMessage());
}
@Nested
class VariableInBlock {
@Test
public void variableInBlock_shouldNotResolveOnFollowingLines() {
MethodDeclaration methodDeclaration =
getMethodByName("localVariable_shouldNotResolve_usageFollowsDeclaration_shouldNotResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Expected to not be able to resolve s, as out of scope within an else block.
assertThrows(UnsolvedSymbolException.class, () -> {
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
});
}
@Test
public void variableInBlock_mustNotResolveBeforeDeclaration() {
MethodDeclaration methodDeclaration =
getMethodByName("localVariable_shouldNotResolve_usagePreceedsDeclaration_shouldNotResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Expected to not be able to resolve s, as it is declared after it is used.
assertThrows(
UnsolvedSymbolException.class,
() -> {
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
},
"Error: Variable defined within a pattern expression is used before it is declared - should not be resolved, but is.");
}
@Nested
class LogicalOperatorScope {
@Test
public void logicalAndShouldResolve() {
MethodDeclaration methodDeclaration =
getMethodByName("localVariable_shouldNotResolve_logicalAnd_shouldResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr inScopeMethodCall = methodCalls.get(0);
// Resolving the method call .contains()
final ResolvedMethodDeclaration resolve = inScopeMethodCall.resolve();
assertEquals("java.lang.String.contains(java.lang.CharSequence)", resolve.getQualifiedSignature());
assertEquals("boolean", resolve.getReturnType().describe());
assertEquals("contains", resolve.getName());
assertEquals(1, resolve.getNumberOfParams());
assertEquals("contains(java.lang.CharSequence)", resolve.getSignature());
// Resolving the variable `s`
assertTrue(inScopeMethodCall.hasScope());
final Expression expression = inScopeMethodCall.getScope().get();
final ResolvedType resolvedType = expression.calculateResolvedType();
assertEquals("java.lang.String", resolvedType.describe());
}
@Test
public void logicalOrShouldNotResolve() {
MethodDeclaration methodDeclaration =
getMethodByName("localVariable_shouldNotResolve_logicalOr_shouldNotResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Expected to not be able to resolve s, as it is on the right hand side of a logical or.
assertThrows(
UnsolvedSymbolException.class,
() -> {
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
},
"Error: Variable defined within a pattern expression should not be available on the right hand side of an || operator.");
}
}
}
@Nested
class IfElseIfElse {
@Nested
class Condition {
@Test
public void condition_rightBranch_logicalAndShouldResolveWithCorrectBreakdowns() {
MethodDeclaration methodDeclaration =
getMethodByName("if_conditional_emptyBlock_logicalAnd_shouldResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr inScopeMethodCall = methodCalls.get(0);
assertEquals("s.contains(\"in scope\")", inScopeMethodCall.toString());
// Resolving the method call .contains()
final ResolvedMethodDeclaration resolve = inScopeMethodCall.resolve();
assertEquals("java.lang.String.contains(java.lang.CharSequence)", resolve.getQualifiedSignature());
assertEquals("boolean", resolve.getReturnType().describe());
assertEquals("contains", resolve.getName());
assertEquals(1, resolve.getNumberOfParams());
assertEquals("contains(java.lang.CharSequence)", resolve.getSignature());
// Resolving the variable `s`
assertTrue(inScopeMethodCall.hasScope());
final Expression expression = inScopeMethodCall.getScope().get();
final ResolvedType resolvedType = expression.calculateResolvedType();
assertEquals("java.lang.String", resolvedType.describe());
}
/**
* This tests that the components on the right hand side resolve.
* Useful when debugging (e.g. if the variable resolves, but not the method call).
*/
@Test
public void condition_rightBranch_nameExprResolves() {
MethodDeclaration methodDeclaration =
getMethodByName("if_conditional_emptyBlock_logicalAnd_shouldResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
final List<BinaryExpr> binaryExprs = methodDeclaration.findAll(BinaryExpr.class);
assertEquals(1, binaryExprs.size());
BinaryExpr binaryExpr = binaryExprs.get(0);
List<NameExpr> nameExprs = binaryExpr.getRight().findAll(NameExpr.class);
assertEquals(1, nameExprs.size());
NameExpr nameExpr = nameExprs.get(0);
ResolvedValueDeclaration resolvedNameExpr = nameExpr.resolve();
}
/**
* This tests that the components on the right hand side resolve.
* Useful when debugging (e.g. if the variable resolves, but not the method call).
*/
@Test
public void condition_rightBranch_methodCallResolves() {
MethodDeclaration methodDeclaration =
getMethodByName("if_conditional_emptyBlock_logicalAnd_shouldResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
final List<BinaryExpr> binaryExprs = methodDeclaration.findAll(BinaryExpr.class);
assertEquals(1, binaryExprs.size());
BinaryExpr binaryExpr = binaryExprs.get(0);
List<MethodCallExpr> methodCallExprs = binaryExpr.getRight().findAll(MethodCallExpr.class);
assertEquals(1, methodCallExprs.size());
MethodCallExpr methodCallExpr = methodCallExprs.get(0);
ResolvedType resolvedType = methodCallExpr.calculateResolvedType();
ResolvedMethodDeclaration resolvedMethodDeclaration = methodCallExpr.resolve();
}
@Test
public void condition_leftBranchMethodCall_doesNotResolve() {
MethodDeclaration methodDeclaration =
getMethodByName("if_conditional_usageBeforeDeclaration_shouldNotResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Expected to not be able to resolve s, as out of scope within an else block.
assertThrows(UnsolvedSymbolException.class, () -> {
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
});
}
}
@Nested
class IfElseIfElseBlock {
@Test
public void givenInstanceOfPattern_thenCorrectNumberOfMethodCalls() {
MethodDeclaration methodDeclaration = getMethodByName("if_else_conditional_mixedResolveResults");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(2, methodCalls.size());
}
@Test
public void givenInstanceOfPattern_whenSolvingInvalidNotInScope_thenFails() {
MethodDeclaration methodDeclaration = getMethodByName("if_else_conditional_mixedResolveResults");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(2, methodCalls.size());
MethodCallExpr inScopeMethodCall = methodCalls.get(0);
MethodCallExpr outOfScopeMethodCall = methodCalls.get(1);
// Expected to not be able to resolve s, as out of scope within an else block.
assertThrows(UnsolvedSymbolException.class, () -> {
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
});
}
@Test
public void givenInstanceOfPattern_whenSolvingValidInScope_thenSuccessful() {
MethodDeclaration methodDeclaration = getMethodByName("if_else_conditional_mixedResolveResults");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(2, methodCalls.size());
MethodCallExpr inScopeMethodCall = methodCalls.get(0);
MethodCallExpr outOfScopeMethodCall = methodCalls.get(1);
// Resolving the method call .contains()
final ResolvedMethodDeclaration resolve = inScopeMethodCall.resolve();
assertEquals("java.lang.String.contains(java.lang.CharSequence)", resolve.getQualifiedSignature());
assertEquals("boolean", resolve.getReturnType().describe());
assertEquals("contains", resolve.getName());
assertEquals(1, resolve.getNumberOfParams());
assertEquals("contains(java.lang.CharSequence)", resolve.getSignature());
// Resolving the variable `s`
assertTrue(inScopeMethodCall.hasScope());
final Expression expression = inScopeMethodCall.getScope().get();
final ResolvedType resolvedType = expression.calculateResolvedType();
assertEquals("java.lang.String", resolvedType.describe());
}
}
@Test
public void givenInstanceOfPattern_andField_skipBraces_thenResolvesToPattern() {
MethodDeclaration methodDeclaration =
getMethodByName("if_conditional_negated_no_braces_on_if_shouldResolveToLocalVariableNotPattern");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Resolving the method call .contains()
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
// Should resolve to the field (List.contains()), not the pattern expression (String.contains())
assertEquals("java.util.List.contains(java.lang.Object)", resolve.getQualifiedSignature());
assertEquals("boolean", resolve.getReturnType().describe());
assertEquals("contains", resolve.getName());
assertEquals(1, resolve.getNumberOfParams());
assertEquals("contains(java.lang.Object)", resolve.getSignature());
}
@Test
public void givenInstanceOfPattern_andField_thenResolvesToField() {
MethodDeclaration methodDeclaration =
getMethodByName("if_conditional_negated_shouldResolveToLocalVariableNotPattern");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Resolving the method call .contains()
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
// Should resolve to the field (List.contains()), not the pattern expression (String.contains())
assertEquals("java.util.List.contains(java.lang.Object)", resolve.getQualifiedSignature());
assertEquals("boolean", resolve.getReturnType().describe());
assertEquals("contains", resolve.getName());
assertEquals(1, resolve.getNumberOfParams());
assertEquals("contains(java.lang.Object)", resolve.getSignature());
}
@Test
public void test_shouldFail() {
MethodDeclaration methodDeclaration = getMethodByName("if_conditional_OR_shouldNotResolve");
final List<MethodCallExpr> methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
assertEquals(1, methodCalls.size());
assertEquals(1, methodCalls.size());
MethodCallExpr outOfScopeMethodCall = methodCalls.get(0);
// Expected to not be able to resolve s, as out of scope within an else block.
assertThrows(UnsolvedSymbolException.class, () -> {
final ResolvedMethodDeclaration resolve = outOfScopeMethodCall.resolve();
});
}
}
@Nested
class PatternTest {
@Test
public void instanceOfWithRecordPatternShouldResolve() {
CompilationUnit cu = parse("class Test {\n" + " public void foo(Object o) {\n"
+ " if (o instanceof Box(InnerBox(Integer i), InnerBox(String s))) {\n"
+ " System.out.println(s);\n"
+ " };\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable1() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " return;\n"
+ " }\n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable2() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o) {\n"
+ " if (!(o instanceof String s)) {}\n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertThrows(UnsolvedSymbolException.class, () -> name.resolve());
}
@Test
public void ifIntroducesPatternVariable3() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " // do nothing\n"
+ " } else {\n"
+ " System.out.println(s);\n"
+ " }\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable4() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o) {\n"
+ " if (!(o instanceof String s) || false) {\n"
+ " // do nothing\n"
+ " } else {\n"
+ " System.out.println(s);\n"
+ " }\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable5() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o, boolean b) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " // do nothing\n"
+ " } else if (b) {\n"
+ " // do nothing\n"
+ " } else {\n"
+ " System.out.println(s);\n"
+ " }\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable6() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o, boolean b) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " // do nothing\n"
+ " } else if (b) {\n"
+ " // do nothing\n"
+ " } \n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertThrows(UnsolvedSymbolException.class, () -> name.resolve());
}
@Test
public void ifIntroducesPatternVariable7() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o, boolean b) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " return;\n"
+ " } else if (b) {\n"
+ " // do nothing\n"
+ " } \n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable8() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o, boolean b) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " return;\n"
+ " } else if (b) {\n"
+ " // do nothing\n"
+ " } else {}\n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable9() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o, boolean b) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " return;\n"
+ " } else if (b) {\n"
+ " // do nothing\n"
+ " } else {\n"
+ " return;\n"
+ " }\n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertEquals("java.lang.String", name.resolve().getType().describe());
}
@Test
public void ifIntroducesPatternVariable10() {
CompilationUnit cu = parse("public class Test {\n"
+ " public void foo(Object o, boolean b) {\n"
+ " if (!(o instanceof String s)) {\n"
+ " return;\n"
+ " } else if (b) {\n"
+ " throw new RuntimeException();\n"
+ " } else {\n"
+ " return;"
+ " }\n"
+ " System.out.println(s);\n"
+ " }\n"
+ "}");
NameExpr name = Navigator.findNameExpression(cu, "s").get();
assertThrows(UnsolvedSymbolException.class, () -> name.resolve());
}
}
@Nested
class Simpler {
@Test
public void test() {
MethodDeclaration methodDeclaration = getMethodByName("localVariable_shouldNotResolve");
List<NameExpr> nameExprs = methodDeclaration.findAll(NameExpr.class);
assertEquals(2, nameExprs.size());
NameExpr nameExpr = nameExprs.get(0);
ResolvedValueDeclaration resolvedNameExpr = nameExpr.resolve();
ResolvedType resolvedNameExprType = nameExpr.calculateResolvedType();
}
}
private MethodDeclaration getMethodByName(String name) {
return compilationUnit.findAll(MethodDeclaration.class).stream()
.filter(methodDeclaration -> methodDeclaration.getNameAsString().equals(name))
.findFirst()
.orElseThrow(RuntimeException::new);
}
private CompilationUnit parseWithTypeSolver(String code) {
return parseWithTypeSolver(null, code);
}
private CompilationUnit parseWithTypeSolver(ParserConfiguration.LanguageLevel languageLevel, String code) {
ParserConfiguration parserConfiguration = new ParserConfiguration();
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
if (languageLevel != null) {
parserConfiguration.setLanguageLevel(languageLevel);
}
return new JavaParser(parserConfiguration)
.parse(ParseStart.COMPILATION_UNIT, new StringProvider(code))
.getResult()
.get();
}
}