21
21
import static com .google .errorprone .matchers .Description .NO_MATCH ;
22
22
import static com .google .errorprone .matchers .Matchers .hasModifier ;
23
23
import static com .google .errorprone .util .ASTHelpers .getSymbol ;
24
+ import static com .google .errorprone .util .ASTHelpers .getType ;
25
+ import static com .google .errorprone .util .ASTHelpers .hasAnnotation ;
26
+ import static com .google .errorprone .util .ASTHelpers .isSameType ;
24
27
import static java .beans .Introspector .decapitalize ;
25
28
26
29
import com .google .auto .value .AutoValue ;
34
37
import com .google .errorprone .fixes .SuggestedFix ;
35
38
import com .google .errorprone .matchers .Description ;
36
39
import com .google .errorprone .matchers .Matcher ;
37
- import com .google .errorprone .util .ASTHelpers ;
38
40
import com .sun .source .tree .ClassTree ;
39
41
import com .sun .source .tree .IdentifierTree ;
40
42
import com .sun .source .tree .MethodTree ;
@@ -60,31 +62,24 @@ public class AutoValueBoxedValues extends BugChecker implements ClassTreeMatcher
60
62
61
63
@ Override
62
64
public Description matchClass (ClassTree tree , VisitorState state ) {
63
- if (!ASTHelpers . hasAnnotation (tree , AutoValue .class .getName (), state )) {
65
+ if (!hasAnnotation (tree , AutoValue .class .getName (), state )) {
64
66
return NO_MATCH ;
65
67
}
66
68
69
+ Optional <ClassTree > builderClass = findBuilderClass (tree , state );
70
+
67
71
// Identify and potentially fix the getters.
68
- ImmutableList <Getter > getters = handleGetterMethods (tree , state );
72
+ ImmutableList <Getter > getters = handleGetterMethods (tree , state , builderClass );
69
73
70
74
// If we haven't modified any getter, it's ok to stop.
71
75
if (getters .stream ().allMatch (getter -> getter .fix ().isEmpty ())) {
72
76
return NO_MATCH ;
73
77
}
74
78
75
- // Handle the Builder class, if there is one.
76
- boolean builderFound = false ;
77
- for (Tree memberTree : tree .getMembers ()) {
78
- if (memberTree instanceof ClassTree
79
- && ASTHelpers .hasAnnotation (memberTree , AutoValue .Builder .class .getName (), state )) {
80
- handleSetterMethods ((ClassTree ) memberTree , state , getters );
81
- builderFound = true ;
82
- break ;
83
- }
84
- }
85
-
86
- // If a builder was not found, handle the factory methods.
87
- if (!builderFound ) {
79
+ // Handle the Builder class, if there is one. Otherwise handle the factory methods.
80
+ if (builderClass .isPresent ()) {
81
+ handleSetterMethods (builderClass .get (), state , getters );
82
+ } else {
88
83
handleFactoryMethods (tree , state , getters );
89
84
}
90
85
@@ -103,13 +98,16 @@ public Description matchClass(ClassTree tree, VisitorState state) {
103
98
* @param state The visitor state.
104
99
* @return The list of {@link Getter} in the class.
105
100
*/
106
- private ImmutableList <Getter > handleGetterMethods (ClassTree classTree , VisitorState state ) {
101
+ private ImmutableList <Getter > handleGetterMethods (
102
+ ClassTree classTree , VisitorState state , Optional <ClassTree > builderClass ) {
107
103
return classTree .getMembers ().stream ()
108
104
.filter (MethodTree .class ::isInstance )
109
105
.map (memberTree -> (MethodTree ) memberTree )
110
106
.filter (
111
107
methodTree ->
112
- ABSTRACT_MATCHER .matches (methodTree , state ) && methodTree .getParameters ().isEmpty ())
108
+ ABSTRACT_MATCHER .matches (methodTree , state )
109
+ && methodTree .getParameters ().isEmpty ()
110
+ && !isToBuilderMethod (methodTree , state , builderClass ))
113
111
.map (methodTree -> maybeFixGetter (methodTree , state ))
114
112
.collect (toImmutableList ());
115
113
}
@@ -120,7 +118,7 @@ private ImmutableList<Getter> handleGetterMethods(ClassTree classTree, VisitorSt
120
118
*/
121
119
private Getter maybeFixGetter (MethodTree method , VisitorState state ) {
122
120
Getter getter = Getter .of (method );
123
- Type type = ASTHelpers . getType (method .getReturnType ());
121
+ Type type = getType (method .getReturnType ());
124
122
if (!isSuppressed (method , state )
125
123
&& !hasNullableAnnotation (method )
126
124
&& isBoxedPrimitive (state , type )) {
@@ -143,7 +141,8 @@ private void handleSetterMethods(ClassTree classTree, VisitorState state, List<G
143
141
.filter (
144
142
methodTree ->
145
143
ABSTRACT_MATCHER .matches (methodTree , state )
146
- && methodTree .getParameters ().size () == 1 )
144
+ && methodTree .getParameters ().size () == 1
145
+ && isSameType (getType (methodTree .getReturnType ()), getType (classTree ), state ))
147
146
.forEach (methodTree -> maybeFixSetter (methodTree , state , getters ));
148
147
}
149
148
@@ -162,7 +161,7 @@ && matchGetterAndSetter(getter.method(), methodTree, allGettersPrefixed))
162
161
.findAny ();
163
162
if (fixedGetter .isPresent ()) {
164
163
var parameter = methodTree .getParameters ().get (0 );
165
- Type type = ASTHelpers . getType (parameter );
164
+ Type type = getType (parameter );
166
165
if (isBoxedPrimitive (state , type ) && !hasNullableAnnotation (parameter )) {
167
166
suggestRemoveUnnecessaryBoxing (parameter .getType (), state , type , fixedGetter .get ().fix ());
168
167
}
@@ -188,10 +187,8 @@ private void handleFactoryMethods(ClassTree classTree, VisitorState state, List<
188
187
.filter (
189
188
methodTree ->
190
189
STATIC_MATCHER .matches (methodTree , state )
191
- && ASTHelpers .isSameType (
192
- ASTHelpers .getType (methodTree .getReturnType ()),
193
- ASTHelpers .getType (classTree ),
194
- state )
190
+ && isSameType (
191
+ getType (methodTree .getReturnType ()), getType (classTree ), state )
195
192
&& isTrivialFactoryMethod (methodTree , getters .size ()))
196
193
.findAny ();
197
194
if (trivialFactoryMethod .isEmpty ()) {
@@ -201,7 +198,7 @@ && isTrivialFactoryMethod(methodTree, getters.size()))
201
198
Getter getter = getters .get (idx );
202
199
if (!getter .fix ().isEmpty ()) {
203
200
var parameter = trivialFactoryMethod .get ().getParameters ().get (idx );
204
- Type type = ASTHelpers . getType (parameter );
201
+ Type type = getType (parameter );
205
202
if (isBoxedPrimitive (state , type ) && !hasNullableAnnotation (parameter )) {
206
203
suggestRemoveUnnecessaryBoxing (parameter .getType (), state , type , getter .fix ());
207
204
}
@@ -228,6 +225,23 @@ private static boolean isBoxedPrimitive(VisitorState state, Type type) {
228
225
return unboxed != null && unboxed .getTag () != TypeTag .NONE && unboxed .getTag () != TypeTag .VOID ;
229
226
}
230
227
228
+ private static Optional <ClassTree > findBuilderClass (ClassTree tree , VisitorState state ) {
229
+ return tree .getMembers ().stream ()
230
+ .filter (
231
+ memberTree ->
232
+ memberTree instanceof ClassTree
233
+ && hasAnnotation (memberTree , AutoValue .Builder .class .getName (), state ))
234
+ .map (memberTree -> (ClassTree ) memberTree )
235
+ .findAny ();
236
+ }
237
+
238
+ private static boolean isToBuilderMethod (
239
+ MethodTree methodTree , VisitorState state , Optional <ClassTree > builderClass ) {
240
+ return builderClass .isPresent ()
241
+ && !STATIC_MATCHER .matches (methodTree , state )
242
+ && isSameType (getType (methodTree .getReturnType ()), getType (builderClass .get ()), state );
243
+ }
244
+
231
245
private static boolean allGettersPrefixed (List <Getter > getters ) {
232
246
return getters .stream ().allMatch (getter -> !getterPrefix (getter .method ()).isEmpty ());
233
247
}
@@ -238,7 +252,7 @@ private static String getterPrefix(MethodTree getterMethod) {
238
252
return "get" ;
239
253
} else if (name .startsWith ("is" )
240
254
&& !name .equals ("is" )
241
- && ASTHelpers . getType (getterMethod .getReturnType ()).getKind () == TypeKind .BOOLEAN ) {
255
+ && getType (getterMethod .getReturnType ()).getKind () == TypeKind .BOOLEAN ) {
242
256
return "is" ;
243
257
}
244
258
return "" ;
0 commit comments