2121import static com .google .errorprone .matchers .Description .NO_MATCH ;
2222import static com .google .errorprone .matchers .Matchers .hasModifier ;
2323import 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 ;
2427import static java .beans .Introspector .decapitalize ;
2528
2629import com .google .auto .value .AutoValue ;
3437import com .google .errorprone .fixes .SuggestedFix ;
3538import com .google .errorprone .matchers .Description ;
3639import com .google .errorprone .matchers .Matcher ;
37- import com .google .errorprone .util .ASTHelpers ;
3840import com .sun .source .tree .ClassTree ;
3941import com .sun .source .tree .IdentifierTree ;
4042import com .sun .source .tree .MethodTree ;
@@ -60,31 +62,24 @@ public class AutoValueBoxedValues extends BugChecker implements ClassTreeMatcher
6062
6163 @ Override
6264 public Description matchClass (ClassTree tree , VisitorState state ) {
63- if (!ASTHelpers . hasAnnotation (tree , AutoValue .class .getName (), state )) {
65+ if (!hasAnnotation (tree , AutoValue .class .getName (), state )) {
6466 return NO_MATCH ;
6567 }
6668
69+ Optional <ClassTree > builderClass = findBuilderClass (tree , state );
70+
6771 // Identify and potentially fix the getters.
68- ImmutableList <Getter > getters = handleGetterMethods (tree , state );
72+ ImmutableList <Getter > getters = handleGetterMethods (tree , state , builderClass );
6973
7074 // If we haven't modified any getter, it's ok to stop.
7175 if (getters .stream ().allMatch (getter -> getter .fix ().isEmpty ())) {
7276 return NO_MATCH ;
7377 }
7478
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 {
8883 handleFactoryMethods (tree , state , getters );
8984 }
9085
@@ -103,13 +98,16 @@ public Description matchClass(ClassTree tree, VisitorState state) {
10398 * @param state The visitor state.
10499 * @return The list of {@link Getter} in the class.
105100 */
106- private ImmutableList <Getter > handleGetterMethods (ClassTree classTree , VisitorState state ) {
101+ private ImmutableList <Getter > handleGetterMethods (
102+ ClassTree classTree , VisitorState state , Optional <ClassTree > builderClass ) {
107103 return classTree .getMembers ().stream ()
108104 .filter (MethodTree .class ::isInstance )
109105 .map (memberTree -> (MethodTree ) memberTree )
110106 .filter (
111107 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 ))
113111 .map (methodTree -> maybeFixGetter (methodTree , state ))
114112 .collect (toImmutableList ());
115113 }
@@ -120,7 +118,7 @@ private ImmutableList<Getter> handleGetterMethods(ClassTree classTree, VisitorSt
120118 */
121119 private Getter maybeFixGetter (MethodTree method , VisitorState state ) {
122120 Getter getter = Getter .of (method );
123- Type type = ASTHelpers . getType (method .getReturnType ());
121+ Type type = getType (method .getReturnType ());
124122 if (!isSuppressed (method , state )
125123 && !hasNullableAnnotation (method )
126124 && isBoxedPrimitive (state , type )) {
@@ -143,7 +141,8 @@ private void handleSetterMethods(ClassTree classTree, VisitorState state, List<G
143141 .filter (
144142 methodTree ->
145143 ABSTRACT_MATCHER .matches (methodTree , state )
146- && methodTree .getParameters ().size () == 1 )
144+ && methodTree .getParameters ().size () == 1
145+ && isSameType (getType (methodTree .getReturnType ()), getType (classTree ), state ))
147146 .forEach (methodTree -> maybeFixSetter (methodTree , state , getters ));
148147 }
149148
@@ -162,7 +161,7 @@ && matchGetterAndSetter(getter.method(), methodTree, allGettersPrefixed))
162161 .findAny ();
163162 if (fixedGetter .isPresent ()) {
164163 var parameter = methodTree .getParameters ().get (0 );
165- Type type = ASTHelpers . getType (parameter );
164+ Type type = getType (parameter );
166165 if (isBoxedPrimitive (state , type ) && !hasNullableAnnotation (parameter )) {
167166 suggestRemoveUnnecessaryBoxing (parameter .getType (), state , type , fixedGetter .get ().fix ());
168167 }
@@ -188,10 +187,8 @@ private void handleFactoryMethods(ClassTree classTree, VisitorState state, List<
188187 .filter (
189188 methodTree ->
190189 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 )
195192 && isTrivialFactoryMethod (methodTree , getters .size ()))
196193 .findAny ();
197194 if (trivialFactoryMethod .isEmpty ()) {
@@ -201,7 +198,7 @@ && isTrivialFactoryMethod(methodTree, getters.size()))
201198 Getter getter = getters .get (idx );
202199 if (!getter .fix ().isEmpty ()) {
203200 var parameter = trivialFactoryMethod .get ().getParameters ().get (idx );
204- Type type = ASTHelpers . getType (parameter );
201+ Type type = getType (parameter );
205202 if (isBoxedPrimitive (state , type ) && !hasNullableAnnotation (parameter )) {
206203 suggestRemoveUnnecessaryBoxing (parameter .getType (), state , type , getter .fix ());
207204 }
@@ -228,6 +225,23 @@ private static boolean isBoxedPrimitive(VisitorState state, Type type) {
228225 return unboxed != null && unboxed .getTag () != TypeTag .NONE && unboxed .getTag () != TypeTag .VOID ;
229226 }
230227
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+
231245 private static boolean allGettersPrefixed (List <Getter > getters ) {
232246 return getters .stream ().allMatch (getter -> !getterPrefix (getter .method ()).isEmpty ());
233247 }
@@ -238,7 +252,7 @@ private static String getterPrefix(MethodTree getterMethod) {
238252 return "get" ;
239253 } else if (name .startsWith ("is" )
240254 && !name .equals ("is" )
241- && ASTHelpers . getType (getterMethod .getReturnType ()).getKind () == TypeKind .BOOLEAN ) {
255+ && getType (getterMethod .getReturnType ()).getKind () == TypeKind .BOOLEAN ) {
242256 return "is" ;
243257 }
244258 return "" ;
0 commit comments