Skip to content

Commit bf4b8a6

Browse files
authored
Merge pull request javaparser#2966 from jlerbsc/master
Fix issue 1945 JavaParser choking on multiple generic method calls on the same line
2 parents 23f4ccf + 9403aa9 commit bf4b8a6

File tree

9 files changed

+212
-3
lines changed

9 files changed

+212
-3
lines changed

javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodCallExprContext.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
4040
import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration;
4141
import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
42-
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
4342
import com.github.javaparser.resolution.types.ResolvedArrayType;
4443
import com.github.javaparser.resolution.types.ResolvedLambdaConstraintType;
4544
import com.github.javaparser.resolution.types.ResolvedReferenceType;
@@ -238,7 +237,8 @@ private Optional<MethodUsage> solveMethodAsUsage(ResolvedReferenceType refType,
238237
}
239238

240239
ResolvedType returnType = refType.useThisTypeParametersOnTheGivenType(methodUsage.returnType());
241-
if (returnType != methodUsage.returnType()) {
240+
// we don't want to replace the return type in case of UNBOUNDED type (<?>)
241+
if (returnType != methodUsage.returnType() && !(returnType == ResolvedWildcard.UNBOUNDED)) {
242242
methodUsage = methodUsage.replaceReturnType(returnType);
243243
}
244244
for (int i = 0; i < methodUsage.getParamTypes().size(); i++) {
@@ -490,7 +490,7 @@ private Optional<MethodUsage> solveMethodAsUsage(ResolvedType type, String name,
490490
private ResolvedType usingParameterTypesFromScope(ResolvedType scope, ResolvedType type, Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes) {
491491
if (type.isReferenceType()) {
492492
for (Pair<ResolvedTypeParameterDeclaration, ResolvedType> entry : type.asReferenceType().getTypeParametersMap()) {
493-
if (entry.a.declaredOnType() && scope.asReferenceType().getGenericParameterByName(entry.a.getName()).isPresent()) {
493+
if (entry.a.declaredOnType() && scope.isReferenceType() && scope.asReferenceType().getGenericParameterByName(entry.a.getName()).isPresent()) {
494494
type = type.replaceTypeVariables(entry.a, scope.asReferenceType().getGenericParameterByName(entry.a.getName()).get(), inferredTypes);
495495
}
496496
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.github.javaparser.symbolsolver;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.nio.file.Path;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
import com.github.javaparser.ParserConfiguration;
13+
import com.github.javaparser.StaticJavaParser;
14+
import com.github.javaparser.ast.CompilationUnit;
15+
import com.github.javaparser.ast.expr.MethodCallExpr;
16+
import com.github.javaparser.symbolsolver.resolution.AbstractResolutionTest;
17+
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
18+
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
19+
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
20+
21+
public class Issue1945Test extends AbstractResolutionTest {
22+
23+
@Test()
24+
void test() {
25+
String code = "import issue1945.implementations.Sheep;\n" +
26+
"import issue1945.interfaces.HairType;\n" +
27+
"import issue1945.interfaces.HairTypeRenderer;\n" +
28+
"import issue1945.interfaces.HairyAnimal;\n" +
29+
"\n" +
30+
"public class MainIssue1945 {\n" +
31+
" \n" +
32+
" private final HairyAnimal sheep = new Sheep();\n" +
33+
" \n" +
34+
" public void chokes3() {\n" +
35+
" HairType<?> hairType = sheep.getHairType();\n" +
36+
" hairType.getRenderer().renderHair(sheep.getHairType(), sheep);\n" +
37+
" hairType.getRenderer();\n" +
38+
39+
" }\n" +
40+
" \n" +
41+
" public void chokes() {\n" +
42+
" sheep.getHairType().getRenderer().renderHair(sheep.getHairType(), sheep);\n" +
43+
" }\n" +
44+
" \n" +
45+
" public void chokes2() {\n" +
46+
" HairType<?> hairType = sheep.getHairType();\n" +
47+
" hairType.getRenderer().renderHair(hairType, sheep);\n" +
48+
" }\n" +
49+
"}";
50+
51+
ParserConfiguration config = new ParserConfiguration();
52+
Path srcDir = adaptPath("src/test/resources/issue1945");
53+
CombinedTypeSolver typeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(false), new JavaParserTypeSolver(srcDir));
54+
55+
config.setSymbolResolver(new JavaSymbolSolver(typeSolver));
56+
StaticJavaParser.setConfiguration(config);
57+
58+
// results by MathodCallExpr
59+
Map<String,String> resultsQualifiedName = new HashMap<>();
60+
resultsQualifiedName.put("sheep.getHairType()", "issue1945.interfaces.HairyAnimal.getHairType");
61+
resultsQualifiedName.put("hairType.getRenderer().renderHair(sheep.getHairType(), sheep)", "issue1945.interfaces.HairTypeRenderer.renderHair");
62+
resultsQualifiedName.put("hairType.getRenderer()", "issue1945.interfaces.HairType.getRenderer");
63+
resultsQualifiedName.put("sheep.getHairType().getRenderer().renderHair(sheep.getHairType(), sheep)", "issue1945.interfaces.HairTypeRenderer.renderHair");
64+
resultsQualifiedName.put("sheep.getHairType().getRenderer()", "issue1945.interfaces.HairType.getRenderer");
65+
resultsQualifiedName.put("hairType.getRenderer().renderHair(hairType, sheep)", "issue1945.interfaces.HairTypeRenderer.renderHair");
66+
Map<String,String> resultsResolvedType = new HashMap<>();
67+
resultsResolvedType.put("sheep.getHairType()", "issue1945.interfaces.HairType<?>");
68+
resultsResolvedType.put("hairType.getRenderer().renderHair(sheep.getHairType(), sheep)", "void");
69+
resultsResolvedType.put("hairType.getRenderer()", "R");
70+
resultsResolvedType.put("sheep.getHairType().getRenderer().renderHair(sheep.getHairType(), sheep)", "void");
71+
resultsResolvedType.put("sheep.getHairType().getRenderer()", "R");
72+
resultsResolvedType.put("hairType.getRenderer().renderHair(hairType, sheep)", "void");
73+
74+
CompilationUnit cu = StaticJavaParser.parse(code);
75+
List<MethodCallExpr> nodes = cu.findAll(MethodCallExpr.class);
76+
for (MethodCallExpr expr : nodes) {
77+
String qName = expr.resolve().getQualifiedName();
78+
String resolvedType = expr.calculateResolvedType().describe();
79+
assertEquals(resultsQualifiedName.get(expr.toString()), qName);
80+
assertEquals(resultsResolvedType.get(expr.toString()), resolvedType);
81+
}
82+
83+
}
84+
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package issue1945.implementations;
2+
import issue1945.interfaces.HairType;
3+
4+
public class HairTypeWool implements HairType<WoolRenderer> {
5+
6+
@Override
7+
public WoolRenderer getRenderer() {
8+
return WoolRenderer.INSTANCE;
9+
}
10+
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package issue1945.implementations;
2+
import issue1945.interfaces.HairType;
3+
import issue1945.interfaces.HairyAnimal;
4+
5+
public class Sheep implements HairyAnimal {
6+
7+
@Override
8+
public HairType<?> getHairType() {
9+
//simplified
10+
return new HairTypeWool();
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package issue1945.implementations;
2+
import issue1945.interfaces.HairTypeRenderer;
3+
import issue1945.interfaces.HairyAnimal;
4+
5+
public class WoolRenderer extends HairTypeRenderer<HairTypeWool> {
6+
7+
public final static WoolRenderer INSTANCE = new WoolRenderer();
8+
9+
private WoolRenderer() {
10+
//I'm a singleton
11+
}
12+
13+
@Override
14+
public void renderHair(HairTypeWool type, HairyAnimal animal) {
15+
//... snip ...
16+
}
17+
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package issue1945.interfaces;
2+
3+
public interface HairType<R extends HairTypeRenderer<?>> {
4+
5+
R getRenderer();
6+
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package issue1945.interfaces;
2+
3+
public abstract class HairTypeRenderer<T> {
4+
5+
protected abstract void renderHair(T typeInstance, HairyAnimal animal);
6+
7+
/**
8+
* A proxy method casting the <code>typeInstance</code> parameter to the appropriate type for this renderer.
9+
* This is necessary because the type that's retrieved by {@link HairyAnimal#getHairType()} is the generic {@link HairType} super interface.
10+
*/
11+
@SuppressWarnings("unchecked")
12+
public final void renderHair(HairType<?> typeInstance, HairyAnimal animal) {
13+
try {
14+
renderHair((T)typeInstance, animal);
15+
} catch (ClassCastException e) {
16+
throw new IllegalStateException("Renderer type and instance type don't match", e);
17+
}
18+
}
19+
20+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package issue1945.interfaces;
2+
3+
public interface HairyAnimal {
4+
5+
HairType<?> getHairType();
6+
7+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package issue1945.main;
2+
3+
import issue1945.implementations.Sheep;
4+
import issue1945.interfaces.HairType;
5+
import issue1945.interfaces.HairTypeRenderer;
6+
import issue1945.interfaces.HairyAnimal;
7+
8+
public class MainIssue1945 {
9+
10+
private final HairyAnimal sheep = new Sheep();
11+
12+
public void chokes() {
13+
sheep.getHairType().getRenderer().renderHair(sheep.getHairType(), sheep);
14+
}
15+
16+
public void chokes2() {
17+
HairType<?> hairType = sheep.getHairType();
18+
hairType.getRenderer().renderHair(hairType, sheep);
19+
}
20+
21+
public void chokes3() {
22+
HairType<?> hairType = sheep.getHairType();
23+
hairType.getRenderer().renderHair(sheep.getHairType(), sheep);
24+
}
25+
26+
27+
28+
29+
30+
public void works() {
31+
HairType<?> hairType = sheep.getHairType();
32+
HairTypeRenderer<?> hairTypeRenderer = hairType.getRenderer();
33+
34+
hairTypeRenderer.renderHair(hairType, sheep);
35+
}
36+
37+
public void works2() {
38+
HairTypeRenderer<?> hairTypeRenderer = sheep.getHairType().getRenderer();
39+
hairTypeRenderer.renderHair(sheep.getHairType(), sheep);
40+
}
41+
42+
public void works3() {
43+
HairType<?> hairType = sheep.getHairType();
44+
HairTypeRenderer<?> hairTypeRenderer = hairType.getRenderer();
45+
46+
hairTypeRenderer.renderHair(sheep.getHairType(), sheep);
47+
}
48+
}

0 commit comments

Comments
 (0)