21
21
import static com .google .common .base .Predicates .equalTo ;
22
22
import static com .google .common .base .Predicates .not ;
23
23
import static com .google .common .collect .Iterables .filter ;
24
+ import static com .google .common .collect .Iterables .getOnlyElement ;
24
25
import static com .squareup .javapoet .MethodSpec .constructorBuilder ;
25
26
import static com .squareup .javapoet .MethodSpec .methodBuilder ;
26
27
import static com .squareup .javapoet .TypeSpec .classBuilder ;
27
28
import static java .util .stream .Collectors .toList ;
28
29
import static javax .lang .model .element .Modifier .ABSTRACT ;
29
30
import static javax .lang .model .element .Modifier .FINAL ;
30
31
import static javax .lang .model .element .Modifier .PRIVATE ;
32
+ import static javax .lang .model .element .Modifier .PUBLIC ;
31
33
import static javax .lang .model .element .Modifier .STATIC ;
32
34
import static javax .lang .model .element .Modifier .VOLATILE ;
33
35
import static javax .lang .model .type .TypeKind .VOID ;
64
66
import javax .lang .model .element .TypeParameterElement ;
65
67
import javax .lang .model .type .TypeMirror ;
66
68
import javax .lang .model .util .Elements ;
69
+ import javax .lang .model .util .Types ;
67
70
import javax .tools .Diagnostic .Kind ;
68
71
69
72
/** An extension that implements the {@link Memoized} contract. */
@@ -110,6 +113,7 @@ static final class Generator {
110
113
private final String classToExtend ;
111
114
private final boolean isFinal ;
112
115
private final Elements elements ;
116
+ private final Types types ;
113
117
private final SourceVersion sourceVersion ;
114
118
private final Messager messager ;
115
119
private final Optional <AnnotationSpec > lazyInitAnnotation ;
@@ -121,6 +125,7 @@ static final class Generator {
121
125
this .classToExtend = classToExtend ;
122
126
this .isFinal = isFinal ;
123
127
this .elements = context .processingEnvironment ().getElementUtils ();
128
+ this .types = context .processingEnvironment ().getTypeUtils ();
124
129
this .sourceVersion = context .processingEnvironment ().getSourceVersion ();
125
130
this .messager = context .processingEnvironment ().getMessager ();
126
131
this .lazyInitAnnotation = getLazyInitAnnotation (elements );
@@ -140,6 +145,9 @@ String generate() {
140
145
generated .addFields (methodOverrider .fields ());
141
146
generated .addMethod (methodOverrider .method ());
142
147
}
148
+ if (isHashCodeMemoized () && !isEqualsFinal ()) {
149
+ generated .addMethod (equalsWithHashCodeCheck ());
150
+ }
143
151
if (hasErrors ) {
144
152
return null ;
145
153
}
@@ -176,6 +184,40 @@ private MethodSpec constructor() {
176
184
return constructor .build ();
177
185
}
178
186
187
+ private boolean isHashCodeMemoized () {
188
+ return memoizedMethods (context ).stream ()
189
+ .anyMatch (method -> method .getSimpleName ().contentEquals ("hashCode" ));
190
+ }
191
+
192
+ private boolean isEqualsFinal () {
193
+ TypeMirror objectType = elements .getTypeElement (Object .class .getCanonicalName ()).asType ();
194
+ ExecutableElement equals =
195
+ MoreElements .getLocalAndInheritedMethods (context .autoValueClass (), types , elements )
196
+ .stream ()
197
+ .filter (method -> method .getSimpleName ().contentEquals ("equals" ))
198
+ .filter (method -> method .getParameters ().size () == 1 )
199
+ .filter (
200
+ method ->
201
+ types .isSameType (getOnlyElement (method .getParameters ()).asType (), objectType ))
202
+ .findFirst ()
203
+ .get ();
204
+ return equals .getModifiers ().contains (FINAL );
205
+ }
206
+
207
+ private MethodSpec equalsWithHashCodeCheck () {
208
+ return methodBuilder ("equals" )
209
+ .addModifiers (PUBLIC )
210
+ .returns (TypeName .BOOLEAN )
211
+ .addAnnotation (Override .class )
212
+ .addParameter (TypeName .OBJECT , "that" )
213
+ .addStatement (
214
+ "return that instanceof $N "
215
+ + "&& this.hashCode() == that.hashCode() "
216
+ + "&& super.equals(that)" ,
217
+ className )
218
+ .build ();
219
+ }
220
+
179
221
/**
180
222
* Determines the required fields and overriding method for a {@link Memoized @Memoized} method.
181
223
*/
0 commit comments