private void classifyGetter(ExecutableElement builderGetter, String propertyName) {
    TypeMirror originalGetterType = rewrittenPropertyTypes.get(propertyName).getType();
    AnnotatedTypeMirror builderGetterType = builderMethodReturnType(builderGetter);
    String builderGetterTypeString = TypeEncoder.encodeWithAnnotations(builderGetterType);
    if (TYPE_EQUIVALENCE.equivalent(builderGetterType.getType(), originalGetterType)) {
      builderGetters.put(
          propertyName,
          new BuilderSpec.PropertyGetter(builderGetter, builderGetterTypeString, null));
      return;
    }
    Optionalish optional = Optionalish.createIfOptional(builderGetterType.getType());
    if (optional != null) {
      TypeMirror containedType = optional.getContainedType(typeUtils);
      // If the original method is int getFoo() then we allow Optional<Integer> here.
      // boxedOriginalType is Integer, and containedType is also Integer.
      // We don't need any special code for OptionalInt because containedType will be int then.
      TypeMirror boxedOriginalType =
          originalGetterType.getKind().isPrimitive()
              ? typeUtils.boxedClass(MoreTypes.asPrimitiveType(originalGetterType)).asType()
              : null;
      if (TYPE_EQUIVALENCE.equivalent(containedType, originalGetterType)
          || TYPE_EQUIVALENCE.equivalent(containedType, boxedOriginalType)) {
        builderGetters.put(
            propertyName,
            new BuilderSpec.PropertyGetter(builderGetter, builderGetterTypeString, optional));
        return;
      }
    }
    errorReporter.reportError(
        builderGetter,
        "[AutoValueBuilderReturnType] Method matches a property of %1$s but has return type %2$s"
            + " instead of %3$s or an Optional wrapping of %3$s",
        builtType,
        builderGetterType,
        originalGetterType);
  }
Classifies a method given that it has no arguments. Currently a method with no arguments can be
a {@code build()} method, meaning that its return type must be the {@code @AutoValue} class; it
can be a getter, with the same signature as one of the property getters in the
{@code @AutoValue} class; or it can be a property builder, like {@code
ImmutableList.Builder<String> foosBuilder()} for the property defined by {@code
ImmutableList<String> foos()} or {@code getFoos()}.
value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java