Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f478dc2

Browse filesBrowse files
authored
Merge pull request #4752 from johannescoetzee/johannes/fix-lambda-varargs
Fix resolution of lambdas used as varargs
2 parents 32c7997 + fd89ae0 commit f478dc2
Copy full SHA for f478dc2

File tree

Expand file treeCollapse file tree

4 files changed

+60
-5
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+60
-5
lines changed

‎javaparser-core/src/main/java/com/github/javaparser/resolution/logic/MethodResolutionLogic.java

Copy file name to clipboardExpand all lines: javaparser-core/src/main/java/com/github/javaparser/resolution/logic/MethodResolutionLogic.java
+12-2Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,7 @@ protected static boolean isExactMatch(ResolvedMethodLikeDeclaration method, List
741741
return true;
742742
}
743743

744-
private static ResolvedType getMethodsExplicitAndVariadicParameterType(
745-
ResolvedMethodLikeDeclaration method, int i) {
744+
public static ResolvedType getMethodsExplicitAndVariadicParameterType(ResolvedMethodLikeDeclaration method, int i) {
746745
int numberOfParams = method.getNumberOfParams();
747746
if (i < numberOfParams) {
748747
return method.getParam(i).getType();
@@ -753,6 +752,17 @@ private static ResolvedType getMethodsExplicitAndVariadicParameterType(
753752
return null;
754753
}
755754

755+
public static ResolvedType getMethodUsageExplicitAndVariadicParameterType(MethodUsage method, int i) {
756+
int numberOfParams = method.getNoParams();
757+
if (i < numberOfParams) {
758+
return method.getParamType(i);
759+
}
760+
if (method.getDeclaration().hasVariadicParameter()) {
761+
return method.getParamType(numberOfParams - 1);
762+
}
763+
return null;
764+
}
765+
756766
static boolean isMoreSpecific(
757767
ResolvedMethodLikeDeclaration methodA,
758768
ResolvedMethodLikeDeclaration methodB,

‎javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/TypeExtractor.java

Copy file name to clipboardExpand all lines: javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/TypeExtractor.java
+17-2Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.github.javaparser.resolution.declarations.*;
4040
import com.github.javaparser.resolution.logic.FunctionalInterfaceLogic;
4141
import com.github.javaparser.resolution.logic.InferenceContext;
42+
import com.github.javaparser.resolution.logic.MethodResolutionLogic;
4243
import com.github.javaparser.resolution.model.SymbolReference;
4344
import com.github.javaparser.resolution.model.Value;
4445
import com.github.javaparser.resolution.model.typesystem.LazyType;
@@ -484,8 +485,15 @@ public ResolvedType visit(LambdaExpr node, Boolean solveLambdas) {
484485
() -> refMethod.getCorrespondingDeclaration().getName());
485486

486487
// The type parameter referred here should be the java.util.stream.Stream.T
487-
ResolvedType result =
488-
refMethod.getCorrespondingDeclaration().getParam(pos).getType();
488+
ResolvedType result = MethodResolutionLogic.getMethodsExplicitAndVariadicParameterType(
489+
refMethod.getCorrespondingDeclaration(), pos);
490+
491+
// It's possible that the lambda may be used as a vararg, in which case the resolved type will be an
492+
// array type. In this case, the component type should be used instead when finding the functional
493+
// method below.
494+
if (result.isArray()) {
495+
result = result.asArrayType().getComponentType();
496+
}
489497

490498
if (solveLambdas) {
491499
if (callExpr.hasScope()) {
@@ -555,6 +563,13 @@ private ResolvedType resolveLambda(LambdaExpr node, ResolvedType result) {
555563
Context ctx = JavaParserFactory.getContext(node, typeSolver);
556564
result = result.solveGenericTypes(ctx);
557565

566+
// It's possible that the lambda may be used as a vararg, in which case the resolved type will be an
567+
// array type. In this case, the component type should be used instead when finding the functional
568+
// method below.
569+
if (result.isArray()) {
570+
result = result.asArrayType().getComponentType();
571+
}
572+
558573
// We should find out which is the functional method (e.g., apply) and replace the params of the
559574
// solveLambdas with it, to derive so the values. We should also consider the value returned by the
560575
// lambdas

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

Copy file name to clipboardExpand all lines: javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/LambdaExprContext.java
+12-1Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
4343
import com.github.javaparser.resolution.logic.FunctionalInterfaceLogic;
4444
import com.github.javaparser.resolution.logic.InferenceContext;
45+
import com.github.javaparser.resolution.logic.MethodResolutionLogic;
4546
import com.github.javaparser.resolution.model.SymbolReference;
4647
import com.github.javaparser.resolution.model.Value;
4748
import com.github.javaparser.resolution.model.typesystem.ReferenceTypeImpl;
@@ -74,7 +75,17 @@ public Optional<Value> solveSymbolAsValue(String name) {
7475
MethodUsage methodUsage =
7576
JavaParserFacade.get(typeSolver).solveMethodAsUsage(methodCallExpr);
7677
int i = methodCallExpr.getArgumentPosition(wrappedNode, EXCLUDE_ENCLOSED_EXPR);
77-
ResolvedType lambdaType = methodUsage.getParamTypes().get(i);
78+
ResolvedType lambdaOrVarargsType =
79+
MethodResolutionLogic.getMethodUsageExplicitAndVariadicParameterType(methodUsage, i);
80+
ResolvedType lambdaType;
81+
// It's possible that the lambda may be used as a vararg, in which case the resolved type will
82+
// be an array type. In this case, the component type should be used instead when finding the
83+
// functional method below.
84+
if (lambdaOrVarargsType.isArray()) {
85+
lambdaType = lambdaOrVarargsType.asArrayType().getComponentType();
86+
} else {
87+
lambdaType = lambdaOrVarargsType;
88+
}
7889

7990
// Get the functional method in order for us to resolve it's type arguments properly
8091
Optional<MethodUsage> functionalMethodOpt =

‎javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/resolution/LambdaResolutionTest.java

Copy file name to clipboardExpand all lines: javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/resolution/LambdaResolutionTest.java
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import static org.junit.jupiter.api.Assertions.assertEquals;
2525

26+
import com.github.javaparser.StaticJavaParser;
2627
import com.github.javaparser.ast.CompilationUnit;
2728
import com.github.javaparser.ast.body.MethodDeclaration;
2829
import com.github.javaparser.ast.expr.Expression;
@@ -31,6 +32,7 @@
3132
import com.github.javaparser.ast.stmt.ReturnStmt;
3233
import com.github.javaparser.resolution.Navigator;
3334
import com.github.javaparser.resolution.types.ResolvedType;
35+
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
3436
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
3537
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
3638
import org.junit.jupiter.api.Test;
@@ -192,4 +194,21 @@ void typeOfVoidLambda() {
192194
ResolvedType type = javaParserFacade.getType(lambdaExpr);
193195
assertEquals("java.util.function.Consumer<? super java.lang.String>", type.describe());
194196
}
197+
198+
@Test
199+
void lambdaAsVararg() {
200+
String source = "import java.util.function.Consumer;\n" + "class Test {\n"
201+
+ " void acceptConsumers(Consumer<String>... consumers) {}\n"
202+
+ " void test(Consumer<String> first) {\n"
203+
+ " acceptConsumers(first, s -> System.out.println(s));\n"
204+
+ " }\n"
205+
+ "}";
206+
207+
StaticJavaParser.getParserConfiguration().setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver()));
208+
final CompilationUnit cu = StaticJavaParser.parse(source);
209+
final LambdaExpr lambda = cu.findFirst(LambdaExpr.class).get();
210+
assertEquals(
211+
"java.util.function.Consumer<java.lang.String>",
212+
lambda.calculateResolvedType().describe());
213+
}
195214
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.