Search in sources :

Example 76 with TypeVariable

use of javax.lang.model.type.TypeVariable in project glide by bumptech.

the class ProcessorUtil method overriding.

static MethodSpec.Builder overriding(ExecutableElement method) {
    String methodName = method.getSimpleName().toString();
    MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName).addAnnotation(Override.class);
    Set<Modifier> modifiers = method.getModifiers();
    modifiers = new LinkedHashSet<>(modifiers);
    modifiers.remove(Modifier.ABSTRACT);
    Modifier defaultModifier = null;
    // Modifier.DEFAULT doesn't exist until Java 8.
    try {
        defaultModifier = Modifier.valueOf("DEFAULT");
    } catch (IllegalArgumentException e) {
    // Ignored.
    }
    modifiers.remove(defaultModifier);
    builder = builder.addModifiers(modifiers);
    for (TypeParameterElement typeParameterElement : method.getTypeParameters()) {
        TypeVariable var = (TypeVariable) typeParameterElement.asType();
        builder = builder.addTypeVariable(TypeVariableName.get(var));
    }
    builder = builder.returns(TypeName.get(method.getReturnType())).addParameters(getParameters(method)).varargs(method.isVarArgs());
    for (TypeMirror thrownType : method.getThrownTypes()) {
        builder = builder.addException(TypeName.get(thrownType));
    }
    return builder;
}
Also used : MethodSpec(com.squareup.javapoet.MethodSpec) TypeVariable(javax.lang.model.type.TypeVariable) TypeMirror(javax.lang.model.type.TypeMirror) Modifier(javax.lang.model.element.Modifier) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 77 with TypeVariable

use of javax.lang.model.type.TypeVariable in project neo4j by neo4j.

the class PublicApiAnnotationProcessor method encodeType.

private String encodeType(TypeMirror type) {
    TypeKind kind = type.getKind();
    if (kind.isPrimitive()) {
        return kind.toString().toLowerCase(Locale.ROOT);
    }
    if (kind == TypeKind.ARRAY) {
        ArrayType arrayType = (ArrayType) type;
        return encodeType(arrayType.getComponentType()) + "[]";
    }
    if (kind == TypeKind.TYPEVAR) {
        TypeVariable typeVariable = (TypeVariable) type;
        return "#" + typeVariable;
    }
    if (kind == TypeKind.DECLARED) {
        DeclaredType referenceType = (DeclaredType) type;
        validatePublicVisibility(referenceType);
        return referenceType.toString();
    }
    if (kind == TypeKind.VOID) {
        return "void";
    }
    error("Unhandled type: " + kind);
    return "ERROR";
}
Also used : ArrayType(javax.lang.model.type.ArrayType) TypeVariable(javax.lang.model.type.TypeVariable) TypeKind(javax.lang.model.type.TypeKind) DeclaredType(javax.lang.model.type.DeclaredType)

Example 78 with TypeVariable

use of javax.lang.model.type.TypeVariable in project butterknife by JakeWharton.

the class ButterKnifeProcessor method parseBindView.

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);
    Id resourceId = elementToId(element, BindView.class, id);
    if (builder != null) {
        String existingBindingName = builder.findExistingBindingName(resourceId);
        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(resourceId, 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) 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 79 with TypeVariable

use of javax.lang.model.type.TypeVariable in project butterknife by JakeWharton.

the class ButterKnifeProcessor method parseBindViews.

private void parseBindViews(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(BindViews.class, "fields", element) || isBindingInWrongPackage(BindViews.class, element);
    // Verify that the type is a List or an array.
    TypeMirror elementType = element.asType();
    String erasedType = doubleErasure(elementType);
    TypeMirror viewType = null;
    FieldCollectionViewBinding.Kind kind = null;
    if (elementType.getKind() == TypeKind.ARRAY) {
        ArrayType arrayType = (ArrayType) elementType;
        viewType = arrayType.getComponentType();
        kind = FieldCollectionViewBinding.Kind.ARRAY;
    } else if (LIST_TYPE.equals(erasedType)) {
        DeclaredType declaredType = (DeclaredType) elementType;
        List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
        if (typeArguments.size() != 1) {
            error(element, "@%s List must have a generic component. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
            hasError = true;
        } else {
            viewType = typeArguments.get(0);
        }
        kind = FieldCollectionViewBinding.Kind.LIST;
    } else {
        error(element, "@%s must be a List or array. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
        hasError = true;
    }
    if (viewType != null && viewType.getKind() == TypeKind.TYPEVAR) {
        TypeVariable typeVariable = (TypeVariable) viewType;
        viewType = typeVariable.getUpperBound();
    }
    // Verify that the target type extends from View.
    if (viewType != null && !isSubtypeOfType(viewType, VIEW_TYPE) && !isInterface(viewType)) {
        if (viewType.getKind() == TypeKind.ERROR) {
            note(element, "@%s List or array with unresolved type (%s) " + "must elsewhere be generated as a View or interface. (%s.%s)", BindViews.class.getSimpleName(), viewType, enclosingElement.getQualifiedName(), element.getSimpleName());
        } else {
            error(element, "@%s List or array type must extend from View or be an interface. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
            hasError = true;
        }
    }
    // Assemble information on the field.
    String name = element.getSimpleName().toString();
    int[] ids = element.getAnnotation(BindViews.class).value();
    if (ids.length == 0) {
        error(element, "@%s must specify at least one ID. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
        hasError = true;
    }
    Integer duplicateId = findDuplicate(ids);
    if (duplicateId != null) {
        error(element, "@%s annotation contains duplicate ID %d. (%s.%s)", BindViews.class.getSimpleName(), duplicateId, enclosingElement.getQualifiedName(), element.getSimpleName());
        hasError = true;
    }
    if (hasError) {
        return;
    }
    TypeName type = TypeName.get(requireNonNull(viewType));
    boolean required = isFieldRequired(element);
    BindingSet.Builder builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
    builder.addFieldCollection(new FieldCollectionViewBinding(name, type, requireNonNull(kind), new ArrayList<>(elementToIds(element, BindViews.class, ids).values()), required));
    erasedTargetNames.add(enclosingElement);
}
Also used : TypeName(com.squareup.javapoet.TypeName) TypeElement(javax.lang.model.element.TypeElement) ArrayList(java.util.ArrayList) BindString(butterknife.BindString) BindViews(butterknife.BindViews) ArrayType(javax.lang.model.type.ArrayType) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) List(java.util.List) ArrayList(java.util.ArrayList) DeclaredType(javax.lang.model.type.DeclaredType)

Example 80 with TypeVariable

use of javax.lang.model.type.TypeVariable in project butterknife by JakeWharton.

the class ButterKnifeProcessor method parseListenerAnnotation.

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();
    }
    String returnTypeString = returnType.toString();
    boolean hasReturnValue = !"void".equals(returnTypeString);
    if (!returnTypeString.equals(method.returnType()) && hasReturnValue) {
        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, hasReturnValue);
    BindingSet.Builder builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
    Map<Integer, Id> resourceIds = elementToIds(element, annotationClass, ids);
    for (Map.Entry<Integer, Id> entry : resourceIds.entrySet()) {
        if (!builder.addMethod(entry.getValue(), listener, method, binding)) {
            error(element, "Multiple listener methods with return value specified for ID %d. (%s.%s)", entry.getKey(), 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) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap)

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