public Void visitType()

in processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java [73:165]


  public Void visitType(TypeElement shadowType, Element parent) {
    captureJavadoc(shadowType);

    // inner class shadows must be static
    if (shadowType.getEnclosingElement().getKind() == ElementKind.CLASS
        && !shadowType.getModifiers().contains(Modifier.STATIC)) {

      error("inner shadow classes must be static");
    }

    // Don't import nested classes because some of them have the same name.
    AnnotationMirror am = getCurrentAnnotation();
    AnnotationValue av = Helpers.getAnnotationTypeMirrorValue(am, "value");
    AnnotationValue cv = Helpers.getAnnotationTypeMirrorValue(am, "className");

    AnnotationValue minSdkVal = Helpers.getAnnotationTypeMirrorValue(am, "minSdk");
    int minSdk = minSdkVal == null ? -1 : Helpers.getAnnotationIntValue(minSdkVal);
    AnnotationValue maxSdkVal = Helpers.getAnnotationTypeMirrorValue(am, "maxSdk");
    int maxSdk = maxSdkVal == null ? -1 : Helpers.getAnnotationIntValue(maxSdkVal);

    AnnotationValue shadowPickerValue =
        Helpers.getAnnotationTypeMirrorValue(am, "shadowPicker");
    TypeMirror shadowPickerTypeMirror = shadowPickerValue == null
        ? null
        : Helpers.getAnnotationTypeMirrorValue(shadowPickerValue);

    // This shadow doesn't apply to the current SDK. todo: check each SDK.
    if (maxSdk != -1 && maxSdk < MAX_SUPPORTED_ANDROID_SDK) {
      addShadowNotInSdk(shadowType, av, cv);
      return null;
    }

    TypeElement actualType = null;
    if (av == null) {
      if (cv == null) {
        error("@Implements: must specify <value> or <className>");
        return null;
      }
      actualType = getClassNameTypeElement(cv);

      if (actualType == null
          && !suppressWarnings(shadowType, "robolectric.internal.IgnoreMissingClass")) {
        error("@Implements: could not resolve class <" + cv + '>', cv);
        return null;
      }
    } else {
      TypeMirror value = Helpers.getAnnotationTypeMirrorValue(av);
      if (value == null) {
        return null;
      }
      if (cv != null) {
        error("@Implements: cannot specify both <value> and <className> attributes");
      } else {
        actualType = Helpers.getAnnotationTypeMirrorValue(types.asElement(value));
      }
    }
    if (actualType == null) {
      addShadowNotInSdk(shadowType, av, cv);
      return null;
    }
    final List<? extends TypeParameterElement> typeTP = actualType.getTypeParameters();
    final List<? extends TypeParameterElement> elemTP = shadowType.getTypeParameters();
    if (!helpers.isSameParameterList(typeTP, elemTP)) {
      StringBuilder message = new StringBuilder();
      if (elemTP.isEmpty()) {
        message.append("Shadow type is missing type parameters, expected <");
        helpers.appendParameterList(message, actualType.getTypeParameters());
        message.append('>');
      } else if (typeTP.isEmpty()) {
        message.append("Shadow type has type parameters but real type does not");
      } else {
        message.append("Shadow type must have same type parameters as its real counterpart: expected <");
        helpers.appendParameterList(message, actualType.getTypeParameters());
        message.append(">, was <");
        helpers.appendParameterList(message, shadowType.getTypeParameters());
        message.append('>');
      }
      messager.printMessage(Kind.ERROR, message, shadowType);
      return null;
    }

    AnnotationValue looseSignaturesAttr =
        Helpers.getAnnotationTypeMirrorValue(am, "looseSignatures");
    boolean looseSignatures =
        looseSignaturesAttr == null ? false : (Boolean) looseSignaturesAttr.getValue();
    validateShadowMethods(actualType, shadowType, minSdk, maxSdk, looseSignatures);

    modelBuilder.addShadowType(shadowType, actualType,
        shadowPickerTypeMirror == null
            ? null
            : (TypeElement) types.asElement(shadowPickerTypeMirror));
    return null;
  }