use of javax.lang.model.type.TypeVariable in project AndroidLife by CaMnter.
the class ButterKnifeProcessor method parseBindView.
/**
* 解析 BindView
*
* 1.拿到 BindArray 注解元素 的 .java 类元素
* 2.检查注解使用错误,或者注解所在的环境问题( 比如 private or static,所在的 .java 是 private 等 )
* - 有错误就 return
* 3.获取元素的类型
* 4.校验元素类型( 不是 View 的子类,并且不是接口类型 ),报错返回
* 5.获取 id 构造一个 QualifiedId;获取该 .java 元素对应的 BindingSet.Builder,没有则创建
* 6.检查 QualifiedId 包装成的 FieldResourceBinding 是否存在 BindingSet.Builder
* - 是,报错。防止生成重复代码
* - 不是,添加进去
* 7.记录 .java 元素 为要删除的目录
*
* @param element BindBitmap 注解元素
* @param builderMap BindingSet.Builder 缓存 Map
* @param erasedTargetNames 要删除元素的目录,存在的是 .java 的元素
*/
private void parseBindView(Element element, Map<TypeElement, BindingSet.Builder> builderMap, Set<TypeElement> erasedTargetNames) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Start by verifying common generated code restrictions.
boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element) || isBindingInWrongPackage(BindView.class, element);
// Verify that the target type extends from View.
TypeMirror elementType = element.asType();
if (elementType.getKind() == TypeKind.TYPEVAR) {
TypeVariable typeVariable = (TypeVariable) elementType;
elementType = typeVariable.getUpperBound();
}
Name qualifiedName = enclosingElement.getQualifiedName();
Name simpleName = element.getSimpleName();
if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
if (elementType.getKind() == TypeKind.ERROR) {
note(element, "@%s field with unresolved type (%s) " + "must elsewhere be generated as a View or interface. (%s.%s)", BindView.class.getSimpleName(), elementType, qualifiedName, simpleName);
} else {
error(element, "@%s fields must extend from View or be an interface. (%s.%s)", BindView.class.getSimpleName(), qualifiedName, simpleName);
hasError = true;
}
}
if (hasError) {
return;
}
// Assemble information on the field.
int id = element.getAnnotation(BindView.class).value();
BindingSet.Builder builder = builderMap.get(enclosingElement);
QualifiedId qualifiedId = elementToQualifiedId(element, id);
if (builder != null) {
String existingBindingName = builder.findExistingBindingName(getId(qualifiedId));
if (existingBindingName != null) {
error(element, "Attempt to use @%s for an already bound ID %d on '%s'. (%s.%s)", BindView.class.getSimpleName(), id, existingBindingName, enclosingElement.getQualifiedName(), element.getSimpleName());
return;
}
} else {
builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
}
String name = simpleName.toString();
TypeName type = TypeName.get(elementType);
boolean required = isFieldRequired(element);
builder.addField(getId(qualifiedId), new FieldViewBinding(name, type, required));
// Add the type-erased version to the valid binding targets set.
erasedTargetNames.add(enclosingElement);
}
use of javax.lang.model.type.TypeVariable in project AndroidLife by CaMnter.
the class ButterKnifeProcessor method parseListenerAnnotation.
/**
* 解析 注解
* 1.@OnCheckedChanged
* 2.@OnClick
* 3.@OnEditorAction
* 4.@OnFocusChange
* 5.@OnItemClick
* 6.@OnItemLongClick
* 7.@OnItemSelected
* 8.@OnLongClick
* 9.@OnPageChange
* 10.@OnTextChanged
* 11.@OnTouch
*
* 1.校验元素符合 可执行元素 或者 方法。不符合 throw 异常
* 2.拿到 可执行元素;获取注解元素的所在 .java 元素
* 3.反射获取注解类的 value 方法,并校验返回参数是不是 int[]。不是,则返回
* 4.反射调用 value 方法,并且获取返回值 int[]
* 5.检查注解使用错误,或者注解所在的环境问题( 比如 private or static,所在的 .java 是 private 等 )
* - 有错误就 return
* 6.校验 int[] 是否存在重复的 值
* 7.拿到 ListenerClass 和 ListenerMethod 分别校验 id 和 方法,否则抛出异常
* 8.反射校验注解 class 的 callback 方法
* 9.校验 可执行元素 的返回值类型
* 10.获取 拿到 可执行元素 的参数,并进行校验
* 11.将参数包装成 MethodViewBinding 添加到 BindingSet.Builder 中
* 12.记录 .java 元素 为要删除的目录
*
* @param annotationClass 注解 class 类型
* @param element 注解元素
* @param builderMap BindingSet.Builder 缓存 Map
* @param erasedTargetNames 要删除元素的目录,存在的是 .java 的元素
* @throws Exception exception
*/
private void parseListenerAnnotation(Class<? extends Annotation> annotationClass, Element element, Map<TypeElement, BindingSet.Builder> builderMap, Set<TypeElement> erasedTargetNames) throws Exception {
// This should be guarded by the annotation's @Target but it's worth a check for safe casting.
if (!(element instanceof ExecutableElement) || element.getKind() != METHOD) {
throw new IllegalStateException(String.format("@%s annotation must be on a method.", annotationClass.getSimpleName()));
}
ExecutableElement executableElement = (ExecutableElement) element;
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Assemble information on the method.
Annotation annotation = element.getAnnotation(annotationClass);
Method annotationValue = annotationClass.getDeclaredMethod("value");
if (annotationValue.getReturnType() != int[].class) {
throw new IllegalStateException(String.format("@%s annotation value() type not int[].", annotationClass));
}
int[] ids = (int[]) annotationValue.invoke(annotation);
String name = executableElement.getSimpleName().toString();
boolean required = isListenerRequired(executableElement);
// Verify that the method and its containing class are accessible via generated code.
boolean hasError = isInaccessibleViaGeneratedCode(annotationClass, "methods", element);
hasError |= isBindingInWrongPackage(annotationClass, element);
Integer duplicateId = findDuplicate(ids);
if (duplicateId != null) {
error(element, "@%s annotation for method contains duplicate ID %d. (%s.%s)", annotationClass.getSimpleName(), duplicateId, enclosingElement.getQualifiedName(), element.getSimpleName());
hasError = true;
}
ListenerClass listener = annotationClass.getAnnotation(ListenerClass.class);
if (listener == null) {
throw new IllegalStateException(String.format("No @%s defined on @%s.", ListenerClass.class.getSimpleName(), annotationClass.getSimpleName()));
}
for (int id : ids) {
if (id == NO_ID.value) {
if (ids.length == 1) {
if (!required) {
error(element, "ID-free binding must not be annotated with @Optional. (%s.%s)", enclosingElement.getQualifiedName(), element.getSimpleName());
hasError = true;
}
} else {
error(element, "@%s annotation contains invalid ID %d. (%s.%s)", annotationClass.getSimpleName(), id, enclosingElement.getQualifiedName(), element.getSimpleName());
hasError = true;
}
}
}
ListenerMethod method;
ListenerMethod[] methods = listener.method();
if (methods.length > 1) {
throw new IllegalStateException(String.format("Multiple listener methods specified on @%s.", annotationClass.getSimpleName()));
} else if (methods.length == 1) {
if (listener.callbacks() != ListenerClass.NONE.class) {
throw new IllegalStateException(String.format("Both method() and callback() defined on @%s.", annotationClass.getSimpleName()));
}
method = methods[0];
} else {
Method annotationCallback = annotationClass.getDeclaredMethod("callback");
Enum<?> callback = (Enum<?>) annotationCallback.invoke(annotation);
Field callbackField = callback.getDeclaringClass().getField(callback.name());
method = callbackField.getAnnotation(ListenerMethod.class);
if (method == null) {
throw new IllegalStateException(String.format("No @%s defined on @%s's %s.%s.", ListenerMethod.class.getSimpleName(), annotationClass.getSimpleName(), callback.getDeclaringClass().getSimpleName(), callback.name()));
}
}
// Verify that the method has equal to or less than the number of parameters as the listener.
List<? extends VariableElement> methodParameters = executableElement.getParameters();
if (methodParameters.size() > method.parameters().length) {
error(element, "@%s methods can have at most %s parameter(s). (%s.%s)", annotationClass.getSimpleName(), method.parameters().length, enclosingElement.getQualifiedName(), element.getSimpleName());
hasError = true;
}
// Verify method return type matches the listener.
TypeMirror returnType = executableElement.getReturnType();
if (returnType instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) returnType;
returnType = typeVariable.getUpperBound();
}
if (!returnType.toString().equals(method.returnType())) {
error(element, "@%s methods must have a '%s' return type. (%s.%s)", annotationClass.getSimpleName(), method.returnType(), enclosingElement.getQualifiedName(), element.getSimpleName());
hasError = true;
}
if (hasError) {
return;
}
Parameter[] parameters = Parameter.NONE;
if (!methodParameters.isEmpty()) {
parameters = new Parameter[methodParameters.size()];
BitSet methodParameterUsed = new BitSet(methodParameters.size());
String[] parameterTypes = method.parameters();
for (int i = 0; i < methodParameters.size(); i++) {
VariableElement methodParameter = methodParameters.get(i);
TypeMirror methodParameterType = methodParameter.asType();
if (methodParameterType instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) methodParameterType;
methodParameterType = typeVariable.getUpperBound();
}
for (int j = 0; j < parameterTypes.length; j++) {
if (methodParameterUsed.get(j)) {
continue;
}
if ((isSubtypeOfType(methodParameterType, parameterTypes[j]) && isSubtypeOfType(methodParameterType, VIEW_TYPE)) || isTypeEqual(methodParameterType, parameterTypes[j]) || isInterface(methodParameterType)) {
parameters[i] = new Parameter(j, TypeName.get(methodParameterType));
methodParameterUsed.set(j);
break;
}
}
if (parameters[i] == null) {
StringBuilder builder = new StringBuilder();
builder.append("Unable to match @").append(annotationClass.getSimpleName()).append(" method arguments. (").append(enclosingElement.getQualifiedName()).append('.').append(element.getSimpleName()).append(')');
for (int j = 0; j < parameters.length; j++) {
Parameter parameter = parameters[j];
builder.append("\n\n Parameter #").append(j + 1).append(": ").append(methodParameters.get(j).asType().toString()).append("\n ");
if (parameter == null) {
builder.append("did not match any listener parameters");
} else {
builder.append("matched listener parameter #").append(parameter.getListenerPosition() + 1).append(": ").append(parameter.getType());
}
}
builder.append("\n\nMethods may have up to ").append(method.parameters().length).append(" parameter(s):\n");
for (String parameterType : method.parameters()) {
builder.append("\n ").append(parameterType);
}
builder.append("\n\nThese may be listed in any order but will be searched for from top to bottom.");
error(executableElement, builder.toString());
return;
}
}
}
MethodViewBinding binding = new MethodViewBinding(name, Arrays.asList(parameters), required);
BindingSet.Builder builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
for (int id : ids) {
QualifiedId qualifiedId = elementToQualifiedId(element, id);
if (!builder.addMethod(getId(qualifiedId), listener, method, binding)) {
error(element, "Multiple listener methods with return value specified for ID %d. (%s.%s)", id, enclosingElement.getQualifiedName(), element.getSimpleName());
return;
}
}
// Add the type-erased version to the valid binding targets set.
erasedTargetNames.add(enclosingElement);
}
use of javax.lang.model.type.TypeVariable in project javapoet by square.
the class MethodSpec method overriding.
/**
* Returns a new method spec builder that overrides {@code method}.
*
* <p>This will copy its visibility modifiers, type parameters, return type, name, parameters, and
* throws declarations. An {@link Override} annotation will be added.
*
* <p>Note that in JavaPoet 1.2 through 1.7 this method retained annotations from the method and
* parameters of the overridden method. Since JavaPoet 1.8 annotations must be added separately.
*/
public static Builder overriding(ExecutableElement method) {
checkNotNull(method, "method == null");
Element enclosingClass = method.getEnclosingElement();
if (enclosingClass.getModifiers().contains(Modifier.FINAL)) {
throw new IllegalArgumentException("Cannot override method on final class " + enclosingClass);
}
Set<Modifier> modifiers = method.getModifiers();
if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.FINAL) || modifiers.contains(Modifier.STATIC)) {
throw new IllegalArgumentException("cannot override method with modifiers: " + modifiers);
}
String methodName = method.getSimpleName().toString();
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(methodName);
methodBuilder.addAnnotation(Override.class);
modifiers = new LinkedHashSet<>(modifiers);
modifiers.remove(Modifier.ABSTRACT);
modifiers.remove(Modifier.DEFAULT);
methodBuilder.addModifiers(modifiers);
for (TypeParameterElement typeParameterElement : method.getTypeParameters()) {
TypeVariable var = (TypeVariable) typeParameterElement.asType();
methodBuilder.addTypeVariable(TypeVariableName.get(var));
}
methodBuilder.returns(TypeName.get(method.getReturnType()));
methodBuilder.addParameters(ParameterSpec.parametersOf(method));
methodBuilder.varargs(method.isVarArgs());
for (TypeMirror thrownType : method.getThrownTypes()) {
methodBuilder.addException(TypeName.get(thrownType));
}
return methodBuilder;
}
use of javax.lang.model.type.TypeVariable in project j2objc by google.
the class SignatureGenerator method genTypeSignature.
// TODO(kstanger): Figure out if this can replace TypeUtil.getSignatureName().
private void genTypeSignature(TypeMirror type, StringBuilder sb) {
switch(type.getKind()) {
case BOOLEAN:
case BYTE:
case CHAR:
case DOUBLE:
case FLOAT:
case INT:
case LONG:
case SHORT:
case VOID:
sb.append(TypeUtil.getBinaryName(type));
break;
case ARRAY:
// ArrayTypeSignature ::= "[" TypSignature.
sb.append('[');
genTypeSignature(((ArrayType) type).getComponentType(), sb);
break;
case DECLARED:
String typeName = elementUtil.getBinaryName(TypeUtil.asTypeElement(type));
if (!TypeUtil.isStubType(typeName)) {
// ClassTypeSignature ::= "L" {Ident "/"} Ident
// OptTypeArguments {"." Ident OptTypeArguments} ";".
sb.append('L');
sb.append(typeName.replace('.', '/'));
genOptTypeArguments(((DeclaredType) type).getTypeArguments(), sb);
sb.append(';');
}
break;
case TYPEVAR:
// TypeVariableSignature ::= "T" Ident ";".
sb.append('T');
sb.append(ElementUtil.getName(((TypeVariable) type).asElement()));
sb.append(';');
break;
case WILDCARD:
// TypeArgument ::= (["+" | "-"] FieldTypeSignature) | "*".
TypeMirror upperBound = ((WildcardType) type).getExtendsBound();
TypeMirror lowerBound = ((WildcardType) type).getSuperBound();
if (upperBound != null) {
sb.append('+');
genTypeSignature(upperBound, sb);
} else if (lowerBound != null) {
sb.append('-');
genTypeSignature(lowerBound, sb);
} else {
sb.append('*');
}
break;
default:
throw new AssertionError("Unexpected type kind: " + type.getKind());
}
}
use of javax.lang.model.type.TypeVariable in project auto by google.
the class TypeSimplifierTest method testTypeMirrorSetWildcardCapture.
@Test
public void testTypeMirrorSetWildcardCapture() {
// TODO(emcmanus): this test should really be in MoreTypesTest.
// This test checks the assumption made by MoreTypes that you can find the
// upper bounds of a TypeVariable tv like this:
// TypeParameterElement tpe = (TypeParameterElement) tv.asElement();
// List<? extends TypeMirror> bounds = tpe.getBounds();
// There was some doubt as to whether this would be true in exotic cases involving
// wildcard capture, but apparently it is.
// The methods one and two here have identical signatures:
// abstract <T extends V, U extends T, V> Map<? extends T, ? super U> name();
// Their return types should be considered equal by TypeMirrorSet. The capture of
// each return type is different from the original return type, but the two captures
// should compare equal to each other. We also add various other types like ? super U
// to the set to ensure that the implied calls to the equals and hashCode visitors
// don't cause a ClassCastException for TypeParameterElement.
TypeElement wildcardsElement = typeElementOf(Wildcards.class);
List<? extends ExecutableElement> methods = ElementFilter.methodsIn(wildcardsElement.getEnclosedElements());
assertThat(methods).hasSize(2);
ExecutableElement one = methods.get(0);
ExecutableElement two = methods.get(1);
assertThat(one.getSimpleName().toString()).isEqualTo("one");
assertThat(two.getSimpleName().toString()).isEqualTo("two");
TypeMirrorSet typeMirrorSet = new TypeMirrorSet();
assertThat(typeMirrorSet.add(one.getReturnType())).isTrue();
assertThat(typeMirrorSet.add(two.getReturnType())).isFalse();
DeclaredType captureOne = (DeclaredType) typeUtils.capture(one.getReturnType());
assertThat(typeMirrorSet.add(captureOne)).isTrue();
DeclaredType captureTwo = (DeclaredType) typeUtils.capture(two.getReturnType());
assertThat(typeMirrorSet.add(captureTwo)).isFalse();
// Reminder: captureOne is Map<?#123 extends T, ?#456 super U>
TypeVariable extendsT = (TypeVariable) captureOne.getTypeArguments().get(0);
assertThat(typeMirrorSet.add(extendsT)).isTrue();
// NoType
assertThat(typeMirrorSet.add(extendsT.getLowerBound())).isTrue();
for (TypeMirror bound : ((TypeParameterElement) extendsT.asElement()).getBounds()) {
assertThat(typeMirrorSet.add(bound)).isTrue();
}
TypeVariable superU = (TypeVariable) captureOne.getTypeArguments().get(1);
assertThat(typeMirrorSet.add(superU)).isTrue();
assertThat(typeMirrorSet.add(superU.getLowerBound())).isTrue();
}
Aggregations