From a71ad27200040942bb774bc223d6d04ab954df2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 8 Mar 2021 16:02:24 +0100 Subject: [PATCH] Fix a bug with nested lambdas --- .../pmd/lang/java/ast/PolyResolution.java | 4 +- .../internal/infer/LambdaInferenceTest.kt | 48 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/PolyResolution.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/PolyResolution.java index 951b6b06ea..07af8a2834 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/PolyResolution.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/PolyResolution.java @@ -454,7 +454,9 @@ final class PolyResolution { } return node instanceof ASTSwitchExpression && child.getIndexInParent() != 0 // not the condition || node instanceof ASTSwitchArrowBranch - || node instanceof ASTConditionalExpression && child.getIndexInParent() != 0; // not the condition + || node instanceof ASTConditionalExpression && child.getIndexInParent() != 0 // not the condition + // lambdas "forward the context" when you have nested lambdas, eg: `x -> y -> f(x, y)` + || node instanceof ASTLambdaExpression && child.getIndexInParent() == 1; // the body expression } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LambdaInferenceTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LambdaInferenceTest.kt index 0c50a0caf4..cae1d44d62 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LambdaInferenceTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LambdaInferenceTest.kt @@ -677,4 +677,52 @@ class NodeStream { } } + parserTest("Lambda bug with nested lambdas") { + + fun makeTest(insideOut: Boolean) { + + val (acu, spy) = parser.parseWithTypeInferenceSpy( + """ + interface Function { + V apply(U u); + } + + class Scratch { + + void chainingWithLambda(Function f) { + this.>chainingWithLambda(x -> y -> y.contains(0)); + } + } + """.trimIndent() + ) + + val (t_Function, t_Scratch) = acu.declaredTypeSignatures() + val (lambdaX, lambdaY) = acu.descendants(ASTLambdaExpression::class.java).crossFindBoundaries() + .toList() + + + spy.shouldBeOk { + val t_lambdaY = t_Function[t_Scratch, ts.STRING] + val t_lambdaX = t_Function[ts.OBJECT, t_lambdaY] + + if (insideOut) { + lambdaY shouldHaveType t_lambdaY + lambdaX shouldHaveType t_lambdaX + } else { + lambdaX shouldHaveType t_lambdaX + lambdaY shouldHaveType t_lambdaY + } + } + } + + + doTest("Outside in") { + makeTest(false) + } + + doTest("Inside out") { + makeTest(true) + } + } + })