Fix: issue 2738 UnsolvedSymbolException while trying to ResolvedMethodDeclaration from MethodCallExpr
diff --git a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java
index d003c8b..5524c35 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java
@@ -496,13 +496,17 @@
}
} else {
if (thisParam instanceof ResolvedTypeVariable && otherParam instanceof ResolvedTypeVariable) {
+ // Here we want to compare something like @{code C extends Comparable<C>} with @{code K extends Comparable<K>}
+ // we have to compare the type of the erased bound (in this example the type @{code Comparable}).
List<ResolvedType> thisBounds =
thisParam.asTypeVariable().asTypeParameter().getBounds().stream()
.map(ResolvedTypeParameterDeclaration.Bound::getType)
+ .map(type -> type.erasure())
.collect(Collectors.toList());
List<ResolvedType> otherBounds =
otherParam.asTypeVariable().asTypeParameter().getBounds().stream()
.map(ResolvedTypeParameterDeclaration.Bound::getType)
+ .map(type -> type.erasure())
.collect(Collectors.toList());
return thisBounds.size() == otherBounds.size() && otherBounds.containsAll(thisBounds);
}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedTypeVariable.java b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedTypeVariable.java
index 240cdec..74ae96d 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedTypeVariable.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedTypeVariable.java
@@ -109,6 +109,12 @@
@Override
public boolean isAssignableBy(ResolvedType other) {
if (other.isTypeVariable()) {
+ // if we want to compare something like @{code C extends Comparable<C>} with @{code K extends Comparable<K>}
+ // we have to compare the type of the bound. For the moment we are focusing solely on the first type.
+ if (typeParameter.hasBound() && other.asTypeVariable().asTypeParameter().hasBound()) {
+ return typeParameter.getBounds().get(0).getType()
+ .isAssignableBy(other.asTypeVariable().asTypeParameter().getBounds().get(0).getType());
+ }
return describe().equals(other.describe());
}
return true;
diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2738Test.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2738Test.java
new file mode 100755
index 0000000..a2c1623
--- /dev/null
+++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2738Test.java
@@ -0,0 +1,32 @@
+package com.github.javaparser.symbolsolver;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import com.github.javaparser.ParserConfiguration;
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.resolution.TypeSolver;
+import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
+import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
+import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
+import java.io.IOException;
+import java.nio.file.Path;
+import org.junit.jupiter.api.Test;
+
+public class Issue2738Test extends AbstractSymbolResolutionTest {
+ @Test
+ void test() throws IOException {
+ ParserConfiguration config = new ParserConfiguration();
+ Path pathToSourceFile = adaptPath("src/test/resources/issue2738");
+ TypeSolver cts = new CombinedTypeSolver(new ReflectionTypeSolver(), new JavaParserTypeSolver(pathToSourceFile));
+ config.setSymbolResolver(new JavaSymbolSolver(cts));
+
+ StaticJavaParser.setConfiguration(config);
+ CompilationUnit cu = StaticJavaParser.parse(pathToSourceFile.resolve("B.java"));
+
+ // We shouldn't throw an exception
+ assertDoesNotThrow(() -> cu.findAll(MethodCallExpr.class).stream().map(MethodCallExpr::resolve));
+
+ }
+}
diff --git a/javaparser-symbol-solver-testing/src/test/resources/issue2738/A.java b/javaparser-symbol-solver-testing/src/test/resources/issue2738/A.java
new file mode 100755
index 0000000..16ea6c9
--- /dev/null
+++ b/javaparser-symbol-solver-testing/src/test/resources/issue2738/A.java
@@ -0,0 +1,5 @@
+public class A<K extends Comparable<K>> {
+ public int getIndex(K key) {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/javaparser-symbol-solver-testing/src/test/resources/issue2738/B.java b/javaparser-symbol-solver-testing/src/test/resources/issue2738/B.java
new file mode 100755
index 0000000..c9c5eaf
--- /dev/null
+++ b/javaparser-symbol-solver-testing/src/test/resources/issue2738/B.java
@@ -0,0 +1,8 @@
+public class B<C extends Comparable<C>> {
+ private A<C> aC;
+ private C myC;
+
+ public void getValue(int row, int column) {
+ aC.getIndex(myC);
+ }
+}
\ No newline at end of file