Skip to content

Commit

Permalink
SONARJAVA-5338 Fix variable owner in the case of lambdas
Browse files Browse the repository at this point in the history
The computation of owners in lambdas was returning the interface method implemented by the lambda (for instance accept for Function) which doesn't allow distinguishing between symbols declared in different lambdas in different methods with the same variable name.
  • Loading branch information
romainbrenguier committed Feb 14, 2025
1 parent 7f28869 commit 27e8ed7
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 0 deletions.
15 changes: 15 additions & 0 deletions java-frontend/src/main/java/org/sonar/java/model/JSymbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,17 @@ private Symbol variableOwner(IVariableBinding variableBinding) {
if (!variableBinding.isRecordComponent()) {
IMethodBinding declaringMethod = variableBinding.getDeclaringMethod();
if (declaringMethod != null) {
IBinding declaringMember = declaringMethod.getDeclaringMember();
// declaringMember is non-null in the case of lambdas
if (declaringMember != null) {
if (declaringMember instanceof IMethodBinding methodBinding) {
return sema.methodSymbol(methodBinding);
} else if (declaringMember instanceof IVariableBinding varBinding) {
return sema.variableSymbol(varBinding);
} else if (declaringMember instanceof ITypeBinding typeBinding) {
return sema.typeSymbol(typeBinding);
}
}
// local variable
return sema.methodSymbol(declaringMethod);
}
Expand All @@ -203,6 +214,10 @@ private Symbol variableOwner(IVariableBinding variableBinding) {
return sema.typeSymbol(declaringClass);
}
}
return ownerOfRecordComponentConstant(variableBinding);
}

private Symbol ownerOfRecordComponentConstant(IVariableBinding variableBinding) {
Tree node = sema.declarations.get(variableBinding);
if (node == null) {
// array.length
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1798,4 +1798,36 @@ void warnings_are_detected() {
assertThat(nestedCastWarning.message()).isEqualTo("Unnecessary cast from String to String");
assertThat(nestedCastWarning.syntaxTree()).isEqualTo(parenthesizedTree);
}

@Test
void test_variable_equals_in_lambda() {
String source = """
package org.foo;
class A {
void f1() {
java.util.function.Consumer<String> a = p -> { System.out.println(p); };
java.util.function.Consumer<String> c = p -> { System.out.println(p); };
}
void f2() {
java.util.function.Consumer<String> b = p -> { System.out.println(p); };
}
}
""";
JavaTree.CompilationUnitTreeImpl cu = test(source);
ClassTreeImpl c = (ClassTreeImpl) cu.types().get(0);
MethodTree f1 = (MethodTree) c.members().get(0);
MethodTree f2 = (MethodTree) c.members().get(1);
VariableTree variableTreeA = (VariableTree) f1.block().body().get(0);
VariableTree variableTreeC = (VariableTree) f1.block().body().get(1);
VariableTree variableTreeB = (VariableTree) f2.block().body().get(0);
LambdaExpressionTreeImpl lambdaA = (LambdaExpressionTreeImpl) variableTreeA.initializer();
LambdaExpressionTreeImpl lambdaB = (LambdaExpressionTreeImpl) variableTreeB.initializer();
LambdaExpressionTreeImpl lambdaC = (LambdaExpressionTreeImpl) variableTreeC.initializer();
VariableTreeImpl pOfA = (VariableTreeImpl) lambdaA.parameters().get(0);
VariableTreeImpl pOfB = (VariableTreeImpl) lambdaB.parameters().get(0);
VariableTreeImpl pOfC = (VariableTreeImpl) lambdaC.parameters().get(0);

assertThat(pOfA.symbol()).isNotSameAs(pOfB.symbol());
assertThat(pOfA.symbol()).isNotSameAs(pOfC.symbol());
}
}

0 comments on commit 27e8ed7

Please sign in to comment.