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;
}