Skip to content

Commit

Permalink
ImmutableChecker: fix the heuristic around MemberSelects.
Browse files Browse the repository at this point in the history
This was previously complaining about something like:

x -> {
  Foo f = new Foo();
  f.someList.get(0); // Complains that someList is mutable.
}

Obviously this doesn't matter, because `f` is owned by the lambda.

This would have made the check a bit _over_-zealous. I don't think I saw any false positives in the flumes previously, but then it's probably quite rare for people to access fields directly rather than via a getter.

PiperOrigin-RevId: 449938995
  • Loading branch information
graememorgan authored and Error Prone Team committed May 20, 2022
1 parent 97a7dbc commit 2cb3b54
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,17 @@ public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {

@Override
public Void visitMemberSelect(MemberSelectTree tree, Void unused) {
// Special case the access of fields to allow accessing fields which would pass an immutable
// check.
// Note: member selects are not intrinsically problematic; the issue is what might be on the
// LHS of them, which is going to be handled by another visit* method.

// If we're only seeing a field access, don't complain about the fact we closed around
// `this`. This is special-case as it would otherwise be vexing to complain about accessing
// a field of type ImmutableList.
if (tree.getExpression() instanceof IdentifierTree
&& getSymbol(tree) instanceof VarSymbol) {
&& getSymbol(tree) instanceof VarSymbol
&& ((IdentifierTree) tree.getExpression()).getName().contentEquals("this")) {
handleIdentifier(getSymbol(tree));
// If we're only seeing a field access, don't complain about the fact we closed around
// `this`.
if (tree.getExpression() instanceof IdentifierTree
&& ((IdentifierTree) tree.getExpression()).getName().contentEquals("this")) {
return null;
}
return null;
}
return super.visitMemberSelect(tree, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2525,6 +2525,25 @@ public void lambda_canCloseAroundImmutableField() {
.doTest();
}

@Test
public void lambda_cannotCloseAroundMutableFieldQualifiedWithThis() {
compilationHelper
.addSourceLines(
"Test.java",
"import com.google.errorprone.annotations.Immutable;",
"import java.util.ArrayList;",
"import java.util.List;",
"class Test {",
" @Immutable interface ImmutableFunction<A, B> { A apply(B b); }",
" private int b = 1;",
" void test(ImmutableFunction<Integer, Integer> f) {",
" // BUG: Diagnostic contains:",
" test(x -> this.b);",
" }",
"}")
.doTest();
}

@Test
public void lambda_cannotCloseAroundMutableLocal() {
compilationHelper
Expand Down Expand Up @@ -2809,4 +2828,29 @@ public void lambda_immutableTypeParam() {
"}")
.doTest();
}

@Test
public void chainedGettersAreAcceptable() {
compilationHelper
.addSourceLines(
"Test.java",
"import com.google.errorprone.annotations.Immutable;",
"import java.util.ArrayList;",
"import java.util.List;",
"class Test {",
" final Test t = null;",
" final List<String> xs = new ArrayList<>();",
" final List<String> getXs() {",
" return xs;",
" }",
" @Immutable interface ImmutableFunction { String apply(String b); }",
" void test(ImmutableFunction f) {",
" test(x -> {",
" Test t = new Test();",
" return t.xs.get(0) + t.getXs().get(0) + t.t.t.xs.get(0);",
" });",
" }",
"}")
.doTest();
}
}

0 comments on commit 2cb3b54

Please sign in to comment.