Skip to content

Commit 332cbfa

Browse files
graememorganError Prone Team
authored andcommitted
Support record destructuring in ArgumentSelectionDefectChecker.
PiperOrigin-RevId: 697569466
1 parent 0db3360 commit 332cbfa

File tree

5 files changed

+39
-68
lines changed

5 files changed

+39
-68
lines changed

core/src/main/java/com/google/errorprone/bugpatterns/argumentselectiondefects/ArgumentSelectionDefectChecker.java

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState
8484
return Description.NO_MATCH;
8585
}
8686

87-
return visitNewClassOrMethodInvocation(
88-
InvocationInfo.createFromMethodInvocation(tree, symbol, state));
87+
return visit(InvocationInfo.createFromMethodInvocation(tree, symbol, state));
8988
}
9089

9190
@Override
@@ -97,28 +96,24 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) {
9796
return Description.NO_MATCH;
9897
}
9998

100-
return visitNewClassOrMethodInvocation(InvocationInfo.createFromNewClass(tree, symbol, state));
99+
return visit(InvocationInfo.createFromNewClass(tree, symbol, state));
101100
}
102101

103-
private Description visitNewClassOrMethodInvocation(InvocationInfo invocationInfo) {
104-
102+
private Description visit(InvocationInfo invocationInfo) {
105103
Changes changes = argumentChangeFinder.findChanges(invocationInfo);
106104

107105
if (changes.isEmpty()) {
108106
return Description.NO_MATCH;
109107
}
110108

111-
Description.Builder description =
112-
buildDescription(invocationInfo.tree()).setMessage(changes.describe(invocationInfo));
113-
114-
// Fix 1 (semantics-preserving): apply comments with parameter names to potentially-swapped
115-
// arguments of the method
116-
description.addFix(changes.buildCommentArgumentsFix(invocationInfo));
117-
118-
// Fix 2: permute the arguments as required
119-
description.addFix(changes.buildPermuteArgumentsFix(invocationInfo));
120-
121-
return description.build();
109+
return buildDescription(invocationInfo.tree())
110+
.setMessage(changes.describe(invocationInfo))
111+
// Fix 1 (semantics-preserving): apply comments with parameter names to potentially-swapped
112+
// arguments of the method
113+
.addFix(changes.buildCommentArgumentsFix(invocationInfo))
114+
// Fix 2: permute the arguments as required
115+
.addFix(changes.buildPermuteArgumentsFix(invocationInfo))
116+
.build();
122117
}
123118

124119
/**

core/src/main/java/com/google/errorprone/bugpatterns/argumentselectiondefects/Changes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import com.google.auto.value.AutoValue;
2222
import com.google.common.collect.ImmutableList;
2323
import com.google.errorprone.fixes.SuggestedFix;
24-
import com.sun.source.tree.ExpressionTree;
24+
import com.sun.source.tree.Tree;
2525
import java.util.stream.Collectors;
2626

2727
/**
@@ -65,7 +65,7 @@ SuggestedFix buildCommentArgumentsFix(InvocationInfo info) {
6565
SuggestedFix.Builder commentArgumentsFixBuilder = SuggestedFix.builder();
6666
for (ParameterPair change : changedPairs()) {
6767
int index = change.formal().index();
68-
ExpressionTree actual = info.actualParameters().get(index);
68+
Tree actual = info.actualParameters().get(index);
6969
int startPosition = getStartPosition(actual);
7070
String formal = info.formalParameters().get(index).getSimpleName().toString();
7171
commentArgumentsFixBuilder.replace(

core/src/main/java/com/google/errorprone/bugpatterns/argumentselectiondefects/InvocationInfo.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import com.google.auto.value.AutoValue;
2020
import com.google.common.collect.ImmutableList;
2121
import com.google.errorprone.VisitorState;
22-
import com.sun.source.tree.ExpressionTree;
2322
import com.sun.source.tree.MethodInvocationTree;
2423
import com.sun.source.tree.NewClassTree;
2524
import com.sun.source.tree.Tree;
@@ -39,7 +38,7 @@ abstract class InvocationInfo {
3938

4039
abstract MethodSymbol symbol();
4140

42-
abstract ImmutableList<? extends ExpressionTree> actualParameters();
41+
abstract ImmutableList<Tree> actualParameters();
4342

4443
abstract ImmutableList<VarSymbol> formalParameters();
4544

core/src/main/java/com/google/errorprone/bugpatterns/argumentselectiondefects/Parameter.java

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.sun.source.tree.MemberSelectTree;
3333
import com.sun.source.tree.MethodInvocationTree;
3434
import com.sun.source.tree.NewClassTree;
35+
import com.sun.source.tree.Tree;
3536
import com.sun.source.tree.Tree.Kind;
3637
import com.sun.source.tree.VariableTree;
3738
import com.sun.tools.javac.code.Symbol;
@@ -88,14 +89,17 @@ static ImmutableList<Parameter> createListFromVarSymbols(List<VarSymbol> varSymb
8889
.collect(toImmutableList());
8990
}
9091

91-
static ImmutableList<Parameter> createListFromExpressionTrees(
92-
List<? extends ExpressionTree> trees) {
92+
static ImmutableList<Parameter> createListFromExpressionTrees(List<? extends Tree> trees) {
9393
return Streams.mapWithIndex(
9494
trees.stream(),
9595
(t, i) ->
9696
new AutoValue_Parameter(
9797
getArgumentName(t),
98-
Optional.ofNullable(ASTHelpers.getResultType(t)).orElse(Type.noType),
98+
Optional.ofNullable(
99+
t instanceof ExpressionTree
100+
? ASTHelpers.getResultType((ExpressionTree) t)
101+
: ASTHelpers.getType(t))
102+
.orElse(Type.noType),
99103
(int) i,
100104
t.toString(),
101105
t.getKind(),
@@ -162,28 +166,25 @@ private static String getClassName(ClassSymbol s) {
162166
* will return the marker for an unknown name.
163167
*/
164168
@VisibleForTesting
165-
static String getArgumentName(ExpressionTree expressionTree) {
166-
switch (expressionTree.getKind()) {
167-
case MEMBER_SELECT -> {
168-
return ((MemberSelectTree) expressionTree).getIdentifier().toString();
169-
}
170-
case NULL_LITERAL -> {
171-
// null could match anything pretty well
172-
return NAME_NULL;
173-
}
169+
static String getArgumentName(Tree tree) {
170+
return switch (tree.getKind()) {
171+
case VARIABLE -> ((VariableTree) tree).getName().toString();
172+
case MEMBER_SELECT -> ((MemberSelectTree) tree).getIdentifier().toString();
173+
// null could match anything pretty well
174+
case NULL_LITERAL -> NAME_NULL;
174175
case IDENTIFIER -> {
175-
IdentifierTree idTree = (IdentifierTree) expressionTree;
176+
IdentifierTree idTree = (IdentifierTree) tree;
176177
if (idTree.getName().contentEquals("this")) {
177178
// for the 'this' keyword the argument name is the name of the object's class
178179
Symbol sym = ASTHelpers.getSymbol(idTree);
179-
return sym != null ? getClassName(ASTHelpers.enclosingClass(sym)) : NAME_NOT_PRESENT;
180+
yield sym != null ? getClassName(ASTHelpers.enclosingClass(sym)) : NAME_NOT_PRESENT;
180181
} else {
181182
// if we have a variable, just extract its name
182-
return idTree.getName().toString();
183+
yield idTree.getName().toString();
183184
}
184185
}
185186
case METHOD_INVOCATION -> {
186-
MethodInvocationTree methodInvocationTree = (MethodInvocationTree) expressionTree;
187+
MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree;
187188
MethodSymbol methodSym = ASTHelpers.getSymbol(methodInvocationTree);
188189
String name = methodSym.getSimpleName().toString();
189190
ImmutableList<String> terms = NamingConventions.splitToLowercaseTerms(name);
@@ -192,26 +193,24 @@ static String getArgumentName(ExpressionTree expressionTree) {
192193
if (terms.size() == 1) {
193194
ExpressionTree receiver = ASTHelpers.getReceiver(methodInvocationTree);
194195
if (receiver == null) {
195-
return getClassName(ASTHelpers.enclosingClass(methodSym));
196+
yield getClassName(ASTHelpers.enclosingClass(methodSym));
196197
}
197198
// recursively try to get a name from the receiver
198-
return getArgumentName(receiver);
199+
yield getArgumentName(receiver);
199200
} else {
200-
return name.substring(firstTerm.length());
201+
yield name.substring(firstTerm.length());
201202
}
202203
} else {
203-
return name;
204+
yield name;
204205
}
205206
}
206207
case NEW_CLASS -> {
207-
MethodSymbol constructorSym = ASTHelpers.getSymbol((NewClassTree) expressionTree);
208-
return constructorSym.owner != null
208+
MethodSymbol constructorSym = ASTHelpers.getSymbol((NewClassTree) tree);
209+
yield constructorSym.owner != null
209210
? getClassName((ClassSymbol) constructorSym.owner)
210211
: NAME_NOT_PRESENT;
211212
}
212-
default -> {
213-
return NAME_NOT_PRESENT;
214-
}
215-
}
213+
default -> NAME_NOT_PRESENT;
214+
};
216215
}
217216
}

core/src/test/java/com/google/errorprone/bugpatterns/argumentselectiondefects/ArgumentSelectionDefectCheckerTest.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -399,28 +399,6 @@ Foo test(String first, String second) {
399399
}
400400
}
401401
402-
record Foo(String first, String second) {}
403-
""")
404-
.doTest();
405-
}
406-
407-
@Test
408-
public void recordDeconstruction() {
409-
assume().that(Runtime.version().feature()).isAtLeast(21);
410-
411-
testHelper
412-
.addSourceLines(
413-
"Test.java",
414-
"""
415-
class Test {
416-
void test(Foo foo) {
417-
switch (foo) {
418-
// TODO(user): We should report a finding here!
419-
case Foo(String second, String first) -> {}
420-
}
421-
}
422-
}
423-
424402
record Foo(String first, String second) {}
425403
""")
426404
.doTest();

0 commit comments

Comments
 (0)