Skip to content

Commit 6d50915

Browse files
authored
Merge pull request #4279 from jlerbsc/master
fix: issue 4240 Calling resolve on catch block parameter throws exception
2 parents 59e3785 + a6f2559 commit 6d50915

2 files changed

Lines changed: 228 additions & 18 deletions

File tree

javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/JavaSymbolSolver.java

Lines changed: 123 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323

2424
import static com.github.javaparser.resolution.Navigator.demandParentNode;
2525

26+
import java.util.Optional;
27+
2628
import com.github.javaparser.ast.CompilationUnit;
2729
import com.github.javaparser.ast.Node;
2830
import com.github.javaparser.ast.body.*;
2931
import com.github.javaparser.ast.expr.*;
32+
import com.github.javaparser.ast.stmt.CatchClause;
3033
import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
3134
import com.github.javaparser.ast.type.Type;
3235
import com.github.javaparser.ast.type.TypeParameter;
@@ -36,9 +39,11 @@
3639
import com.github.javaparser.resolution.UnsolvedSymbolException;
3740
import com.github.javaparser.resolution.declarations.*;
3841
import com.github.javaparser.resolution.model.SymbolReference;
42+
import com.github.javaparser.resolution.model.Value;
3943
import com.github.javaparser.resolution.types.ResolvedPrimitiveType;
4044
import com.github.javaparser.resolution.types.ResolvedType;
4145
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
46+
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
4247
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*;
4348

4449
/**
@@ -241,23 +246,51 @@ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
241246
throw new UnsolvedSymbolException("We are unable to find the constructor declaration corresponding to " + node);
242247
}
243248
}
244-
if (node instanceof Parameter) {
245-
if (ResolvedParameterDeclaration.class.equals(resultClass)) {
246-
Parameter parameter = (Parameter) node;
247-
CallableDeclaration callableDeclaration = node.findAncestor(CallableDeclaration.class).get();
248-
ResolvedMethodLikeDeclaration resolvedMethodLikeDeclaration;
249-
if (callableDeclaration.isConstructorDeclaration()) {
250-
resolvedMethodLikeDeclaration = callableDeclaration.asConstructorDeclaration().resolve();
251-
} else {
252-
resolvedMethodLikeDeclaration = callableDeclaration.asMethodDeclaration().resolve();
253-
}
254-
for (int i = 0; i < resolvedMethodLikeDeclaration.getNumberOfParams(); i++) {
255-
if (resolvedMethodLikeDeclaration.getParam(i).getName().equals(parameter.getNameAsString())) {
256-
return resultClass.cast(resolvedMethodLikeDeclaration.getParam(i));
257-
}
258-
}
259-
}
260-
}
249+
if (node instanceof Parameter) {
250+
if (ResolvedParameterDeclaration.class.equals(resultClass)) {
251+
Parameter parameter = (Parameter) node;
252+
Optional<Node> parentNode = node.getParentNode();
253+
if (!parentNode.isPresent()) {
254+
throw new UnsolvedSymbolException(
255+
"We are unable to resolve the parameter declaration corresponding to " + node);
256+
}
257+
Node parent = (Node) parentNode.get();
258+
if (parent instanceof ConstructorDeclaration) {
259+
Optional<ResolvedParameterDeclaration> resolvedParameterDeclaration = resolveParameterDeclaration(
260+
((ConstructorDeclaration) parent).resolve(), parameter);
261+
return resolvedParameterDeclaration.map(rpd -> resultClass.cast(rpd))
262+
.orElseThrow(() -> new UnsolvedSymbolException(
263+
"We are unable to resolve the parameter declaration corresponding to " + node));
264+
} else if (parent instanceof MethodDeclaration) {
265+
Optional<ResolvedParameterDeclaration> resolvedParameterDeclaration = resolveParameterDeclaration(
266+
((MethodDeclaration) parent).resolve(), parameter);
267+
return resolvedParameterDeclaration.map(rpd -> resultClass.cast(rpd))
268+
.orElseThrow(() -> new UnsolvedSymbolException(
269+
"We are unable to resolve the parameter declaration corresponding to " + node));
270+
} else if (parent instanceof RecordDeclaration) {
271+
Optional<ResolvedParameterDeclaration> resolvedParameterDeclaration = resolveParameterDeclaration(
272+
((RecordDeclaration) parent).resolve(), parameter);
273+
return resolvedParameterDeclaration.map(rpd -> resultClass.cast(rpd))
274+
.orElseThrow(() -> new UnsolvedSymbolException(
275+
"We are unable to resolve the parameter declaration corresponding to " + node));
276+
} else if (parent instanceof LambdaExpr) {
277+
Optional<ResolvedParameterDeclaration> resolvedParameterDeclaration = resolveParameterDeclaration(
278+
parameter);
279+
return resolvedParameterDeclaration.map(rpd -> resultClass.cast(rpd))
280+
.orElseThrow(() -> new UnsolvedSymbolException(
281+
"We are unable to resolve the parameter declaration corresponding to " + node));
282+
} else if (parent instanceof CatchClause) {
283+
Optional<ResolvedParameterDeclaration> resolvedParameterDeclaration = resolveParameterDeclaration(
284+
parameter);
285+
return resolvedParameterDeclaration.map(rpd -> resultClass.cast(rpd))
286+
.orElseThrow(() -> new UnsolvedSymbolException(
287+
"We are unable to resolve the parameter declaration corresponding to " + node));
288+
} else {
289+
throw new UnsolvedSymbolException(
290+
"We are unable to resolve the parameter declaration corresponding to " + node);
291+
}
292+
}
293+
}
261294
if (node instanceof AnnotationExpr) {
262295
SymbolReference<ResolvedAnnotationDeclaration> result = JavaParserFacade.get(typeSolver).solve((AnnotationExpr) node);
263296
if (result.isSolved()) {
@@ -281,7 +314,80 @@ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
281314
throw new UnsupportedOperationException("Unable to find the declaration of type " + resultClass.getSimpleName()
282315
+ " from " + node.getClass().getSimpleName());
283316
}
317+
318+
/*
319+
* Resolves constructor or method parameter
320+
*/
321+
private Optional<ResolvedParameterDeclaration> resolveParameterDeclaration(
322+
ResolvedMethodLikeDeclaration resolvedMethodLikeDeclaration, Parameter parameter) {
323+
for (int i = 0; i < resolvedMethodLikeDeclaration.getNumberOfParams(); i++) {
324+
if (resolvedMethodLikeDeclaration.getParam(i).getName().equals(parameter.getNameAsString())) {
325+
return Optional.of(resolvedMethodLikeDeclaration.getParam(i));
326+
}
327+
}
328+
return Optional.empty();
329+
}
330+
331+
/*
332+
* Resolves record parameter
333+
*/
334+
private Optional<ResolvedParameterDeclaration> resolveParameterDeclaration(
335+
ResolvedReferenceTypeDeclaration resolvedReferenceTypeDeclaration, Parameter parameter) {
336+
ResolvedFieldDeclaration rfd = resolvedReferenceTypeDeclaration.getField(parameter.getNameAsString());
337+
if (rfd == null) return Optional.empty();
338+
ResolvedParameterDeclaration resolvedParameterDeclaration = new ResolvedParameterDeclaration() {
339+
340+
@Override
341+
public ResolvedType getType() {
342+
return rfd.getType();
343+
}
344+
345+
@Override
346+
public String getName() {
347+
return parameter.getNameAsString();
348+
}
349+
350+
@Override
351+
public boolean isVariadic() {
352+
return parameter.isVarArgs();
353+
}
354+
355+
};
356+
return Optional.of(resolvedParameterDeclaration);
357+
}
358+
359+
/*
360+
* Resolves lambda expression parameters and catch clause parameters
361+
*/
362+
private Optional<ResolvedParameterDeclaration> resolveParameterDeclaration(Parameter parameter) {
363+
ResolvedParameterDeclaration resolvedParameterDeclaration = new ResolvedParameterDeclaration() {
364+
365+
@Override
366+
public ResolvedType getType() {
367+
Node parentNode = parameter.getParentNode().get();
368+
if (parameter.getType().isUnknownType() && parentNode instanceof LambdaExpr) {
369+
Optional<Value> value = JavaParserFactory.getContext(parentNode, typeSolver)
370+
.solveSymbolAsValue(parameter.getNameAsString());
371+
return value.map(v -> v.getType()).orElseThrow(() -> new UnsolvedSymbolException(
372+
"We are unable to resolve the parameter declaration corresponding to " + parameter));
373+
}
374+
return JavaParserFacade.get(typeSolver).convertToUsage(parameter.getType());
375+
}
376+
377+
@Override
378+
public String getName() {
379+
return parameter.getNameAsString();
380+
}
381+
382+
@Override
383+
public boolean isVariadic() {
384+
return parameter.isVarArgs();
385+
}
284386

387+
};
388+
return Optional.of(resolvedParameterDeclaration);
389+
}
390+
285391
@Override
286392
public <T> T toResolvedType(Type javaparserType, Class<T> resultClass) {
287393
ResolvedType resolvedType = JavaParserFacade.get(typeSolver).convertToUsage(javaparserType);

javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/JavaParserAPIIntegrationTest.java

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
package com.github.javaparser.symbolsolver;
2323

2424
import com.github.javaparser.JavaParser;
25+
import com.github.javaparser.JavaParserAdapter;
2526
import com.github.javaparser.ParseStart;
2627
import com.github.javaparser.ParserConfiguration;
28+
import com.github.javaparser.ParserConfiguration.LanguageLevel;
2729
import com.github.javaparser.ast.CompilationUnit;
2830
import com.github.javaparser.ast.body.*;
2931
import com.github.javaparser.resolution.TypeSolver;
@@ -44,6 +46,8 @@
4446

4547
import static com.github.javaparser.Providers.provider;
4648
import static org.junit.jupiter.api.Assertions.assertEquals;
49+
import static org.junit.jupiter.api.Assertions.assertThrows;
50+
import static org.junit.jupiter.api.Assertions.assertTrue;
4751

4852
class JavaParserAPIIntegrationTest extends AbstractSymbolResolutionTest {
4953

@@ -175,5 +179,105 @@ void parameterDeclarationResolve() throws IOException {
175179
Parameter declaration = methodDeclaration.getParameter(0);
176180
ResolvedParameterDeclaration resolvedDeclaration = declaration.resolve();
177181
}
178-
182+
183+
@Test
184+
void resolveParameterDeclarationOnConstructor() throws IOException {
185+
String code =
186+
"class Foo {\n"
187+
+ " String baz;\n"
188+
+ " Foo(String baz){\n"
189+
+ " this.baz = baz;\n"
190+
+ " }"
191+
+ "}";
192+
ParserConfiguration parserConfiguration = new ParserConfiguration();
193+
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
194+
JavaParserAdapter parser = JavaParserAdapter.of(new JavaParser(parserConfiguration));
195+
CompilationUnit cu = parser.parse(code);
196+
Parameter parameter = cu.findFirst(Parameter.class).get();
197+
ResolvedParameterDeclaration resolvedParameterDeclaration = parameter.resolve();
198+
assertEquals("java.lang.String",resolvedParameterDeclaration.describeType());
199+
assertTrue(resolvedParameterDeclaration.isParameter());
200+
}
201+
202+
@Test
203+
void resolveParameterDeclarationOnMethodDeclaration() throws IOException {
204+
String code =
205+
"class Foo {\n"
206+
+ " void m(String bar) {}\n"
207+
+ "}";
208+
ParserConfiguration parserConfiguration = new ParserConfiguration();
209+
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
210+
JavaParserAdapter parser = JavaParserAdapter.of(new JavaParser(parserConfiguration));
211+
CompilationUnit cu = parser.parse(code);
212+
Parameter parameter = cu.findFirst(Parameter.class).get();
213+
ResolvedParameterDeclaration resolvedParameterDeclaration = parameter.resolve();
214+
assertEquals("java.lang.String",resolvedParameterDeclaration.describeType());
215+
assertTrue(resolvedParameterDeclaration.isParameter());
216+
}
217+
218+
@Test()
219+
void resolveParameterDeclarationOnRecordDeclaration() throws IOException {
220+
String code = "record Point(Integer x) { }";
221+
ParserConfiguration parserConfiguration = new ParserConfiguration().setLanguageLevel(LanguageLevel.JAVA_16);
222+
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
223+
JavaParserAdapter parser = JavaParserAdapter.of(new JavaParser(parserConfiguration));
224+
CompilationUnit cu = parser.parse(code);
225+
Parameter parameter = cu.findFirst(Parameter.class).get();
226+
// TODO Fixme when the record declarations are resolved.
227+
assertThrows(UnsupportedOperationException.class, () -> parameter.resolve());
228+
// assertEquals("java.lang.Integer",parameter.resolve().describeType());
229+
}
230+
231+
@Test()
232+
void resolveParameterDeclarationOnCatchClauseExpr() throws IOException {
233+
String code =
234+
"class Foo {\n"
235+
+ " void m() {\n"
236+
+ " try {\n"
237+
+ " throw new java.io.FileNotFoundException();\n"
238+
+ " } catch (java.io.IOException ioe) {}\n"
239+
+ " }\n"
240+
+ "}";
241+
ParserConfiguration parserConfiguration = new ParserConfiguration();
242+
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
243+
JavaParserAdapter parser = JavaParserAdapter.of(new JavaParser(parserConfiguration));
244+
CompilationUnit cu = parser.parse(code);
245+
Parameter parameter = cu.findFirst(Parameter.class).get();
246+
ResolvedParameterDeclaration resolvedParameterDeclaration = parameter.resolve();
247+
assertEquals("java.io.IOException",resolvedParameterDeclaration.describeType());
248+
assertTrue(resolvedParameterDeclaration.isParameter());
249+
}
250+
251+
@Test()
252+
void resolveParameterDeclarationOnLambdaExprWithTypeInference() throws IOException {
253+
String code =
254+
"class Foo {\n"
255+
+ " java.util.function.Consumer<Integer> consumer = item -> {};\n"
256+
+ "}";
257+
ParserConfiguration parserConfiguration = new ParserConfiguration();
258+
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
259+
JavaParserAdapter parser = JavaParserAdapter.of(new JavaParser(parserConfiguration));
260+
CompilationUnit cu = parser.parse(code);
261+
Parameter parameter = cu.findFirst(Parameter.class).get();
262+
ResolvedParameterDeclaration resolvedParameterDeclaration = parameter.resolve();
263+
assertEquals("java.lang.Integer",resolvedParameterDeclaration.describeType());
264+
assertTrue(resolvedParameterDeclaration.isParameter());
265+
}
266+
267+
@Test()
268+
void resolveParameterDeclarationOnLambdaExprWithoutTypeInference() throws IOException {
269+
String code =
270+
"class Foo {\n"
271+
+ " java.util.function.Consumer<Long> consumer = (Long a) -> { System.out.println(a); };\n"
272+
+ "}";
273+
ParserConfiguration parserConfiguration = new ParserConfiguration();
274+
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
275+
JavaParserAdapter parser = JavaParserAdapter.of(new JavaParser(parserConfiguration));
276+
CompilationUnit cu = parser.parse(code);
277+
Parameter parameter = cu.findFirst(Parameter.class).get();
278+
ResolvedParameterDeclaration resolvedParameterDeclaration = parameter.resolve();
279+
assertEquals("java.lang.Long",resolvedParameterDeclaration.describeType());
280+
assertTrue(resolvedParameterDeclaration.isParameter());
281+
}
282+
179283
}

0 commit comments

Comments
 (0)