1 /* 2 * Copyright 2014 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.auto.value.processor; 17 18 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods; 19 import static com.google.auto.common.MoreStreams.toImmutableSet; 20 import static com.google.auto.value.processor.AutoValueishProcessor.hasAnnotationMirror; 21 import static com.google.auto.value.processor.AutoValueishProcessor.hasVisibleNoArgConstructor; 22 import static com.google.auto.value.processor.AutoValueishProcessor.nullableAnnotationFor; 23 import static com.google.auto.value.processor.ClassNames.AUTO_VALUE_BUILDER_NAME; 24 import static com.google.common.collect.Sets.immutableEnumSet; 25 import static java.util.stream.Collectors.toList; 26 import static java.util.stream.Collectors.toSet; 27 import static javax.lang.model.util.ElementFilter.methodsIn; 28 import static javax.lang.model.util.ElementFilter.typesIn; 29 30 import com.google.auto.common.MoreElements; 31 import com.google.auto.common.MoreTypes; 32 import com.google.auto.value.extension.AutoValueExtension; 33 import com.google.auto.value.processor.AutoValueishProcessor.Property; 34 import com.google.auto.value.processor.PropertyBuilderClassifier.PropertyBuilder; 35 import com.google.common.collect.ImmutableBiMap; 36 import com.google.common.collect.ImmutableMap; 37 import com.google.common.collect.ImmutableSet; 38 import com.google.common.collect.Iterables; 39 import com.google.common.collect.Maps; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.Optional; 43 import java.util.Set; 44 import java.util.function.Function; 45 import javax.annotation.processing.ProcessingEnvironment; 46 import javax.lang.model.element.Element; 47 import javax.lang.model.element.ElementKind; 48 import javax.lang.model.element.ExecutableElement; 49 import javax.lang.model.element.Modifier; 50 import javax.lang.model.element.TypeElement; 51 import javax.lang.model.element.TypeParameterElement; 52 import javax.lang.model.element.VariableElement; 53 import javax.lang.model.type.DeclaredType; 54 import javax.lang.model.type.ExecutableType; 55 import javax.lang.model.type.TypeKind; 56 import javax.lang.model.type.TypeMirror; 57 import javax.lang.model.util.Types; 58 59 /** 60 * Support for AutoValue builders. 61 * 62 * @author Éamonn McManus 63 */ 64 class BuilderSpec { 65 private final TypeElement autoValueClass; 66 private final ProcessingEnvironment processingEnv; 67 private final ErrorReporter errorReporter; 68 BuilderSpec( TypeElement autoValueClass, ProcessingEnvironment processingEnv, ErrorReporter errorReporter)69 BuilderSpec( 70 TypeElement autoValueClass, 71 ProcessingEnvironment processingEnv, 72 ErrorReporter errorReporter) { 73 this.autoValueClass = autoValueClass; 74 this.processingEnv = processingEnv; 75 this.errorReporter = errorReporter; 76 } 77 78 private static final ImmutableSet<ElementKind> CLASS_OR_INTERFACE = 79 immutableEnumSet(ElementKind.CLASS, ElementKind.INTERFACE); 80 81 /** 82 * Determines if the {@code @AutoValue} class for this instance has a correct nested 83 * {@code @AutoValue.Builder} class or interface and return a representation of it in an {@code 84 * Optional} if so. 85 */ getBuilder()86 Optional<Builder> getBuilder() { 87 Optional<TypeElement> builderTypeElement = Optional.empty(); 88 for (TypeElement containedClass : typesIn(autoValueClass.getEnclosedElements())) { 89 if (hasAnnotationMirror(containedClass, AUTO_VALUE_BUILDER_NAME)) { 90 findBuilderError(containedClass) 91 .ifPresent(error -> errorReporter.reportError(containedClass, "%s", error)); 92 if (builderTypeElement.isPresent()) { 93 errorReporter.reportError( 94 containedClass, 95 "[AutoValueTwoBuilders] %s already has a Builder: %s", 96 autoValueClass, 97 builderTypeElement.get()); 98 } else { 99 builderTypeElement = Optional.of(containedClass); 100 } 101 } 102 } 103 104 if (builderTypeElement.isPresent()) { 105 return builderFrom(builderTypeElement.get()); 106 } else { 107 return Optional.empty(); 108 } 109 } 110 111 /** Finds why this {@code @AutoValue.Builder} class is bad, if it is bad. */ findBuilderError(TypeElement builderTypeElement)112 private Optional<String> findBuilderError(TypeElement builderTypeElement) { 113 if (!CLASS_OR_INTERFACE.contains(builderTypeElement.getKind())) { 114 return Optional.of( 115 "[AutoValueBuilderClass] @AutoValue.Builder can only apply to a class or an" 116 + " interface"); 117 } else if (!builderTypeElement.getModifiers().contains(Modifier.STATIC)) { 118 return Optional.of( 119 "[AutoValueInnerBuilder] @AutoValue.Builder cannot be applied to a non-static class"); 120 } else if (builderTypeElement.getKind().equals(ElementKind.CLASS) 121 && !hasVisibleNoArgConstructor(builderTypeElement)) { 122 return Optional.of( 123 "[AutoValueBuilderConstructor] @AutoValue.Builder class must have a non-private no-arg" 124 + " constructor"); 125 } 126 return Optional.empty(); 127 } 128 129 /** Representation of an {@code AutoValue.Builder} class or interface. */ 130 class Builder implements AutoValueExtension.BuilderContext { 131 private final TypeElement builderTypeElement; 132 private ImmutableSet<ExecutableElement> toBuilderMethods; 133 private ExecutableElement buildMethod; 134 private BuilderMethodClassifier<?> classifier; 135 Builder(TypeElement builderTypeElement)136 Builder(TypeElement builderTypeElement) { 137 this.builderTypeElement = builderTypeElement; 138 } 139 140 @Override builderType()141 public TypeElement builderType() { 142 return builderTypeElement; 143 } 144 145 @Override builderMethods()146 public Set<ExecutableElement> builderMethods() { 147 return methodsIn(autoValueClass.getEnclosedElements()).stream() 148 .filter( 149 m -> 150 m.getParameters().isEmpty() 151 && m.getModifiers().contains(Modifier.STATIC) 152 && !m.getModifiers().contains(Modifier.PRIVATE) 153 && erasedTypeIs(m.getReturnType(), builderTypeElement)) 154 .collect(toSet()); 155 } 156 157 @Override buildMethod()158 public Optional<ExecutableElement> buildMethod() { 159 Types typeUtils = processingEnv.getTypeUtils(); 160 DeclaredType builderTypeMirror = MoreTypes.asDeclared(builderTypeElement.asType()); 161 return MoreElements.getLocalAndInheritedMethods( 162 builderTypeElement, typeUtils, processingEnv.getElementUtils()) 163 .stream() 164 .filter( 165 m -> 166 m.getSimpleName().contentEquals("build") 167 && !m.getModifiers().contains(Modifier.PRIVATE) 168 && !m.getModifiers().contains(Modifier.STATIC) 169 && m.getParameters().isEmpty()) 170 .filter( 171 m -> { 172 ExecutableType methodMirror = 173 MoreTypes.asExecutable(typeUtils.asMemberOf(builderTypeMirror, m)); 174 return erasedTypeIs(methodMirror.getReturnType(), autoValueClass); 175 }) 176 .findFirst(); 177 } 178 179 @Override autoBuildMethod()180 public ExecutableElement autoBuildMethod() { 181 return buildMethod; 182 } 183 184 @Override setters()185 public Map<String, Set<ExecutableElement>> setters() { 186 return Maps.transformValues( 187 classifier.propertyNameToSetters().asMap(), 188 propertySetters -> 189 propertySetters.stream().map(PropertySetter::getSetter).collect(toSet())); 190 } 191 192 @Override propertyBuilders()193 public Map<String, ExecutableElement> propertyBuilders() { 194 return Maps.transformValues( 195 classifier.propertyNameToPropertyBuilder(), PropertyBuilder::getPropertyBuilderMethod); 196 } 197 erasedTypeIs(TypeMirror type, TypeElement baseType)198 private boolean erasedTypeIs(TypeMirror type, TypeElement baseType) { 199 return type.getKind().equals(TypeKind.DECLARED) 200 && MoreTypes.asDeclared(type).asElement().equals(baseType); 201 } 202 203 @Override toBuilderMethods()204 public Set<ExecutableElement> toBuilderMethods() { 205 return toBuilderMethods; 206 } 207 208 /** 209 * Finds any methods in the set that return the builder type. If the builder has type parameters 210 * {@code <A, B>}, then the return type of the method must be {@code Builder<A, B>} with the 211 * same parameter names. We enforce elsewhere that the names and bounds of the builder 212 * parameters must be the same as those of the {@code @AutoValue} class. Here's a correct 213 * example: 214 * 215 * <pre> 216 * {@code @AutoValue abstract class Foo<A extends Number, B> { 217 * abstract int someProperty(); 218 * 219 * abstract Builder<A, B> toBuilder(); 220 * 221 * interface Builder<A extends Number, B> {...} 222 * }} 223 * </pre> 224 * 225 * <p>We currently impose that there cannot be more than one such method. 226 */ toBuilderMethods( Types typeUtils, TypeElement autoValueType, Set<ExecutableElement> abstractMethods)227 ImmutableSet<ExecutableElement> toBuilderMethods( 228 Types typeUtils, TypeElement autoValueType, Set<ExecutableElement> abstractMethods) { 229 230 List<String> builderTypeParamNames = 231 builderTypeElement.getTypeParameters().stream() 232 .map(e -> e.getSimpleName().toString()) 233 .collect(toList()); 234 235 DeclaredType autoValueTypeMirror = MoreTypes.asDeclared(autoValueType.asType()); 236 ImmutableSet.Builder<ExecutableElement> methods = ImmutableSet.builder(); 237 for (ExecutableElement method : abstractMethods) { 238 if (!method.getParameters().isEmpty()) { 239 continue; 240 } 241 ExecutableType methodMirror = 242 MoreTypes.asExecutable(typeUtils.asMemberOf(autoValueTypeMirror, method)); 243 TypeMirror returnTypeMirror = methodMirror.getReturnType(); 244 if (builderTypeElement.equals(typeUtils.asElement(returnTypeMirror))) { 245 methods.add(method); 246 DeclaredType returnType = MoreTypes.asDeclared(returnTypeMirror); 247 List<String> typeArguments = 248 returnType.getTypeArguments().stream() 249 .filter(t -> t.getKind().equals(TypeKind.TYPEVAR)) 250 .map(t -> typeUtils.asElement(t).getSimpleName().toString()) 251 .collect(toList()); 252 if (!builderTypeParamNames.equals(typeArguments)) { 253 errorReporter.reportError( 254 method, 255 "[AutoValueBuilderConverterReturn] Builder converter method should return %s%s", 256 builderTypeElement, 257 TypeSimplifier.actualTypeParametersString(builderTypeElement)); 258 } 259 } 260 } 261 ImmutableSet<ExecutableElement> builderMethods = methods.build(); 262 if (builderMethods.size() > 1) { 263 errorReporter.reportError( 264 builderMethods.iterator().next(), 265 "[AutoValueTwoBuilderConverters] There can be at most one builder converter method"); 266 } 267 this.toBuilderMethods = builderMethods; 268 return builderMethods; 269 } 270 defineVarsForAutoValue( AutoValueOrBuilderTemplateVars vars, ImmutableBiMap<ExecutableElement, String> getterToPropertyName, Nullables nullables)271 void defineVarsForAutoValue( 272 AutoValueOrBuilderTemplateVars vars, 273 ImmutableBiMap<ExecutableElement, String> getterToPropertyName, 274 Nullables nullables) { 275 Iterable<ExecutableElement> builderMethods = 276 abstractMethods(builderTypeElement, processingEnv); 277 boolean autoValueHasToBuilder = toBuilderMethods != null && !toBuilderMethods.isEmpty(); 278 ImmutableMap<ExecutableElement, TypeMirror> getterToPropertyType = 279 TypeVariables.rewriteReturnTypes( 280 processingEnv.getElementUtils(), 281 processingEnv.getTypeUtils(), 282 getterToPropertyName.keySet(), 283 autoValueClass, 284 builderTypeElement); 285 ImmutableMap.Builder<String, TypeMirror> rewrittenPropertyTypes = ImmutableMap.builder(); 286 getterToPropertyType.forEach( 287 (getter, type) -> rewrittenPropertyTypes.put(getterToPropertyName.get(getter), type)); 288 Optional<BuilderMethodClassifier<ExecutableElement>> optionalClassifier = 289 BuilderMethodClassifierForAutoValue.classify( 290 builderMethods, 291 errorReporter, 292 processingEnv, 293 autoValueClass, 294 builderTypeElement, 295 getterToPropertyName, 296 rewrittenPropertyTypes.build(), 297 nullables, 298 autoValueHasToBuilder); 299 if (!optionalClassifier.isPresent()) { 300 return; 301 } 302 for (ExecutableElement method : methodsIn(builderTypeElement.getEnclosedElements())) { 303 if (method.getSimpleName().contentEquals("builder") 304 && method.getModifiers().contains(Modifier.STATIC) 305 && method.getAnnotationMirrors().isEmpty() 306 && !(vars instanceof AutoBuilderTemplateVars)) { 307 // For now we don't warn for methods with annotations, because for example we do want to 308 // allow Jackson's @JsonCreator. We also don't warn if this is an @AutoBuilder. 309 errorReporter.reportWarning( 310 method, 311 "[AutoValueBuilderInBuilder] Static builder() method should be in the containing" 312 + " class"); 313 } 314 } 315 defineVars(vars, optionalClassifier.get()); 316 } 317 defineVars(AutoValueOrBuilderTemplateVars vars, BuilderMethodClassifier<?> classifier)318 void defineVars(AutoValueOrBuilderTemplateVars vars, BuilderMethodClassifier<?> classifier) { 319 this.classifier = classifier; 320 Set<ExecutableElement> buildMethods = classifier.buildMethods(); 321 if (buildMethods.size() != 1) { 322 Set<? extends Element> errorElements = 323 buildMethods.isEmpty() ? ImmutableSet.of(builderTypeElement) : buildMethods; 324 for (Element buildMethod : errorElements) { 325 errorReporter.reportError( 326 buildMethod, 327 "[AutoValueBuilderBuild] Builder must have a single no-argument method, typically" 328 + " called build(), that returns %s%s", 329 autoValueClass, 330 typeParamsString()); 331 } 332 errorReporter.abortIfAnyError(); 333 return; 334 } 335 this.buildMethod = Iterables.getOnlyElement(buildMethods); 336 vars.builderIsInterface = builderTypeElement.getKind() == ElementKind.INTERFACE; 337 vars.builderTypeName = TypeSimplifier.classNameOf(builderTypeElement); 338 vars.builderFormalTypes = 339 TypeEncoder.typeParametersString(builderTypeElement.getTypeParameters()); 340 vars.builderActualTypes = TypeSimplifier.actualTypeParametersString(builderTypeElement); 341 vars.buildMethod = Optional.of(new SimpleMethod(buildMethod)); 342 vars.builderGetters = classifier.builderGetters(); 343 vars.builderSetters = classifier.propertyNameToSetters(); 344 345 vars.builderPropertyBuilders = 346 ImmutableMap.copyOf(classifier.propertyNameToPropertyBuilder()); 347 348 ImmutableSet<Property> requiredProperties = 349 vars.props.stream() 350 .filter(p -> !p.isNullable()) 351 .filter(p -> p.getBuilderInitializer().isEmpty()) 352 .filter(p -> !p.hasDefault()) 353 .filter(p -> !vars.builderPropertyBuilders.containsKey(p.getName())) 354 .collect(toImmutableSet()); 355 vars.builderRequiredProperties = 356 BuilderRequiredProperties.of(vars.props, requiredProperties); 357 } 358 } 359 360 /** 361 * Information about a builder property getter, referenced from the autovalue.vm template. A 362 * property called foo (defined by a method {@code T foo()} or {@code T getFoo()}) can have a 363 * getter method in the builder with the same name ({@code foo()} or {@code getFoo()}) and a 364 * return type of either {@code T} or {@code Optional<T>}. The {@code Optional<T>} form can be 365 * used to tell whether the property has been set. Here, {@code Optional<T>} can be either {@code 366 * java.util.Optional} or {@code com.google.common.base.Optional}. If {@code T} is {@code int}, 367 * {@code long}, or {@code double}, then instead of {@code Optional<T>} we can have {@code 368 * OptionalInt} etc. If {@code T} is a primitive type (including these ones but also the other 369 * five) then {@code Optional<T>} can be the corresponding boxed type. 370 */ 371 public static class PropertyGetter { 372 private final String name; 373 private final String access; 374 private final String type; 375 private final Optionalish optional; 376 377 /** 378 * Makes a new {@code PropertyGetter} instance. 379 * 380 * @param method the source method which this getter is implementing. 381 * @param type the type that the getter returns. This is written to take imports into account, 382 * so it might be {@code List<String>} for example. It is either identical to the type of 383 * the corresponding getter in the {@code @AutoValue} class, or it is an optional wrapper, 384 * like {@code Optional<List<String>>}. 385 * @param optional a representation of the {@code Optional} type that the getter returns, if 386 * this is an optional getter, or null otherwise. An optional getter is one that returns 387 * {@code Optional<T>} rather than {@code T}, as explained above. 388 */ PropertyGetter(ExecutableElement method, String type, Optionalish optional)389 PropertyGetter(ExecutableElement method, String type, Optionalish optional) { 390 this.name = method.getSimpleName().toString(); 391 this.access = SimpleMethod.access(method); 392 this.type = type; 393 this.optional = optional; 394 } 395 getName()396 public String getName() { 397 return name; 398 } 399 getAccess()400 public String getAccess() { 401 return access; 402 } 403 getType()404 public String getType() { 405 return type; 406 } 407 getOptional()408 public Optionalish getOptional() { 409 return optional; 410 } 411 } 412 413 /** 414 * Specifies how to copy a parameter value into the target type. This might be the identity, or it 415 * might be something like {@code ImmutableList.of(...)} or {@code Optional.ofNullable(...)}. 416 */ 417 static class Copier { 418 static final Copier IDENTITY = acceptingNull(x -> x); 419 420 private final Function<String, String> copy; 421 private final boolean acceptsNull; 422 Copier(Function<String, String> copy, boolean acceptsNull)423 private Copier(Function<String, String> copy, boolean acceptsNull) { 424 this.copy = copy; 425 this.acceptsNull = acceptsNull; 426 } 427 acceptingNull(Function<String, String> copy)428 static Copier acceptingNull(Function<String, String> copy) { 429 return new Copier(copy, true); 430 } 431 notAcceptingNull(Function<String, String> copy)432 static Copier notAcceptingNull(Function<String, String> copy) { 433 return new Copier(copy, false); 434 } 435 } 436 437 /** 438 * Information about a property setter, referenced from the autovalue.vm template. A property 439 * called foo (defined by a method {@code T foo()} or {@code T getFoo()}) can have a setter method 440 * {@code foo(T)} or {@code setFoo(T)} that returns the builder type. Additionally, it can have a 441 * setter with a type that can be copied to {@code T} through a {@code copyOf} method; for example 442 * a property {@code foo} of type {@code ImmutableSet<String>} can be set with a method {@code 443 * setFoo(Collection<String> foos)}. And, if {@code T} is {@code Optional}, it can have a setter 444 * with a type that can be copied to {@code T} through {@code Optional.of}. 445 */ 446 public static class PropertySetter { 447 private final ExecutableElement setter; 448 private final String access; 449 private final String name; 450 private final String parameterTypeString; 451 private final boolean primitiveParameter; 452 private final String nullableAnnotation; 453 private final Copier copier; 454 PropertySetter(ExecutableElement setter, TypeMirror parameterType, Copier copier)455 PropertySetter(ExecutableElement setter, TypeMirror parameterType, Copier copier) { 456 this.setter = setter; 457 this.copier = copier; 458 this.access = SimpleMethod.access(setter); 459 this.name = setter.getSimpleName().toString(); 460 primitiveParameter = parameterType.getKind().isPrimitive(); 461 this.parameterTypeString = parameterTypeString(setter, parameterType); 462 VariableElement parameterElement = Iterables.getOnlyElement(setter.getParameters()); 463 Optional<String> maybeNullable = nullableAnnotationFor(parameterElement, parameterType); 464 this.nullableAnnotation = maybeNullable.orElse(""); 465 } 466 getSetter()467 ExecutableElement getSetter() { 468 return setter; 469 } 470 parameterTypeString(ExecutableElement setter, TypeMirror parameterType)471 private static String parameterTypeString(ExecutableElement setter, TypeMirror parameterType) { 472 if (setter.isVarArgs()) { 473 TypeMirror componentType = MoreTypes.asArray(parameterType).getComponentType(); 474 // This is a bit ugly. It's OK to annotate just the component type, because if it is 475 // say `@Nullable String` then we will end up with `@Nullable String...`. Unlike the 476 // normal array case, we can't have the situation where the array itself is annotated; 477 // you can write `String @Nullable []` to mean that, but you can't write 478 // `String @Nullable ...`. 479 return TypeEncoder.encodeWithAnnotations(componentType) + "..."; 480 } else { 481 return TypeEncoder.encodeWithAnnotations(parameterType); 482 } 483 } 484 getAccess()485 public String getAccess() { 486 return access; 487 } 488 getName()489 public String getName() { 490 return name; 491 } 492 getParameterType()493 public String getParameterType() { 494 return parameterTypeString; 495 } 496 getPrimitiveParameter()497 public boolean getPrimitiveParameter() { 498 return primitiveParameter; 499 } 500 getNullableAnnotation()501 public String getNullableAnnotation() { 502 return nullableAnnotation; 503 } 504 copy(Property property)505 public String copy(Property property) { 506 String copy = copier.copy.apply(property.toString()); 507 if (property.isNullable() && !copier.acceptsNull) { 508 copy = String.format("(%s == null ? null : %s)", property, copy); 509 } 510 return copy; 511 } 512 } 513 514 /** 515 * Returns a representation of the given {@code @AutoValue.Builder} class or interface. If the 516 * class or interface has abstract methods that could not be part of any builder, emits error 517 * messages and returns Optional.empty(). 518 */ builderFrom(TypeElement builderTypeElement)519 private Optional<Builder> builderFrom(TypeElement builderTypeElement) { 520 521 // We require the builder to have the same type parameters as the @AutoValue class, meaning the 522 // same names and bounds. In principle the type parameters could have different names, but that 523 // would be confusing, and our code would reject it anyway because it wouldn't consider that 524 // the return type of Foo<U> build() was really the same as the declaration of Foo<T>. This 525 // check produces a better error message in that case and similar ones. 526 527 if (!sameTypeParameters(autoValueClass, builderTypeElement)) { 528 errorReporter.reportError( 529 builderTypeElement, 530 "[AutoValueTypeParamMismatch] Type parameters of %s must have same names and bounds as" 531 + " type parameters of %s", 532 builderTypeElement, 533 autoValueClass); 534 return Optional.empty(); 535 } 536 return Optional.of(new Builder(builderTypeElement)); 537 } 538 sameTypeParameters(TypeElement a, TypeElement b)539 private static boolean sameTypeParameters(TypeElement a, TypeElement b) { 540 return sameTypeParameters(a.getTypeParameters(), b.getTypeParameters()); 541 } 542 sameTypeParameters( List<? extends TypeParameterElement> aParams, List<? extends TypeParameterElement> bParams)543 static boolean sameTypeParameters( 544 List<? extends TypeParameterElement> aParams, List<? extends TypeParameterElement> bParams) { 545 int nTypeParameters = aParams.size(); 546 if (nTypeParameters != bParams.size()) { 547 return false; 548 } 549 for (int i = 0; i < nTypeParameters; i++) { 550 TypeParameterElement aParam = aParams.get(i); 551 TypeParameterElement bParam = bParams.get(i); 552 if (!aParam.getSimpleName().equals(bParam.getSimpleName())) { 553 return false; 554 } 555 Set<TypeMirror> aBounds = new TypeMirrorSet(aParam.getBounds()); 556 Set<TypeMirror> bBounds = new TypeMirrorSet(bParam.getBounds()); 557 if (!aBounds.equals(bBounds)) { 558 return false; 559 } 560 } 561 return true; 562 } 563 564 /** 565 * Returns a set of all abstract methods in the given TypeElement or inherited from ancestors. If 566 * any of the abstract methods has a return type or parameter type that is not currently defined 567 * then this method will throw an exception that will cause us to defer processing of the current 568 * class until a later annotation-processing round. 569 */ abstractMethods( TypeElement typeElement, ProcessingEnvironment processingEnv)570 static ImmutableSet<ExecutableElement> abstractMethods( 571 TypeElement typeElement, ProcessingEnvironment processingEnv) { 572 Set<ExecutableElement> methods = 573 getLocalAndInheritedMethods( 574 typeElement, processingEnv.getTypeUtils(), processingEnv.getElementUtils()); 575 ImmutableSet.Builder<ExecutableElement> abstractMethods = ImmutableSet.builder(); 576 for (ExecutableElement method : methods) { 577 if (method.getModifiers().contains(Modifier.ABSTRACT)) { 578 MissingTypes.deferIfMissingTypesIn(method); 579 abstractMethods.add(method); 580 } 581 } 582 return abstractMethods.build(); 583 } 584 typeParamsString()585 private String typeParamsString() { 586 return TypeSimplifier.actualTypeParametersString(autoValueClass); 587 } 588 } 589