Search in sources :

Example 11 with TypeVariable

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);
}
Also used : TypeName(com.squareup.javapoet.TypeName) TypeElement(javax.lang.model.element.TypeElement) BindString(butterknife.BindString) ClassName(com.squareup.javapoet.ClassName) TypeName(com.squareup.javapoet.TypeName) Name(javax.lang.model.element.Name) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) BindView(butterknife.BindView)

Example 12 with TypeVariable

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);
}
Also used : ListenerClass(butterknife.internal.ListenerClass) ExecutableElement(javax.lang.model.element.ExecutableElement) BindString(butterknife.BindString) VariableElement(javax.lang.model.element.VariableElement) Field(java.lang.reflect.Field) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) TypeElement(javax.lang.model.element.TypeElement) BitSet(java.util.BitSet) Method(java.lang.reflect.Method) ListenerMethod(butterknife.internal.ListenerMethod) Annotation(java.lang.annotation.Annotation) ListenerMethod(butterknife.internal.ListenerMethod)

Example 13 with TypeVariable

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;
}
Also used : TypeVariable(javax.lang.model.type.TypeVariable) TypeMirror(javax.lang.model.type.TypeMirror) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) TypeParameterElement(javax.lang.model.element.TypeParameterElement) Modifier(javax.lang.model.element.Modifier) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 14 with TypeVariable

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());
    }
}
Also used : WildcardType(javax.lang.model.type.WildcardType) TypeVariable(javax.lang.model.type.TypeVariable) TypeMirror(javax.lang.model.type.TypeMirror)

Example 15 with TypeVariable

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();
}
Also used : TypeVariable(javax.lang.model.type.TypeVariable) TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) DeclaredType(javax.lang.model.type.DeclaredType) TypeParameterElement(javax.lang.model.element.TypeParameterElement) Test(org.junit.Test)

Aggregations

TypeVariable (javax.lang.model.type.TypeVariable)80 AnnotatedTypeVariable (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)38 TypeMirror (javax.lang.model.type.TypeMirror)30 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)22 TypeElement (javax.lang.model.element.TypeElement)21 ArrayList (java.util.ArrayList)16 DeclaredType (javax.lang.model.type.DeclaredType)15 HashMap (java.util.HashMap)14 LinkedHashMap (java.util.LinkedHashMap)13 Map (java.util.Map)13 ExecutableElement (javax.lang.model.element.ExecutableElement)12 TypeParameterElement (javax.lang.model.element.TypeParameterElement)12 Test (org.junit.Test)10 ArrayType (javax.lang.model.type.ArrayType)9 WildcardType (javax.lang.model.type.WildcardType)9 AnnotationMirror (javax.lang.model.element.AnnotationMirror)8 Element (javax.lang.model.element.Element)8 AnnotationMirrorMap (org.checkerframework.framework.util.AnnotationMirrorMap)8 AnnotationMirrorSet (org.checkerframework.framework.util.AnnotationMirrorSet)8 VariableElement (javax.lang.model.element.VariableElement)7