Search in sources :

Example 36 with DeclaredType

use of javax.lang.model.type.DeclaredType in project auto by google.

the class PropertyBuilderClassifier method makePropertyBuilder.

// Our @AutoValue class `Foo` has a property `Bar bar()` or `Bar getBar()` and we've encountered
// a builder method like `BarBuilder barBuilder()`. Here `BarBuilder` can have any name (its name
// doesn't have to be the name of `Bar` with `Builder` stuck on the end), but `barBuilder()` does
// have to be the name of the property with `Builder` stuck on the end. The requirements for the
// `BarBuilder` type are:
// (1) It must have an instance method called `build()` that returns `Bar`. If the type of
//     `bar()` is `Bar<String>` then the type of `build()` must be `Bar<String>`.
// (2) `BarBuilder` must have a public no-arg constructor, or `Bar` must have a static method
//     `builder()` or `newBuilder()` that returns `BarBuilder`.
// (3) `Bar` must have an instance method `BarBuilder toBuilder()`, or `BarBuilder` must be a
//      Guava immutable builder like `ImmutableSet.Builder`. (See TODO below for relaxing the
//      requirement on having a `toBuilder()`.
//
// This method outputs an error and returns Optional.absent() if the barBuilder() method has a
// problem.
Optional<PropertyBuilder> makePropertyBuilder(ExecutableElement method, String property) {
    TypeMirror barBuilderTypeMirror = builderMethodClassifier.builderMethodReturnType(method);
    if (barBuilderTypeMirror.getKind() != TypeKind.DECLARED) {
        errorReporter.reportError("Method looks like a property builder, but its return type " + "is not a class or interface", method);
        return Optional.absent();
    }
    DeclaredType barBuilderDeclaredType = MoreTypes.asDeclared(barBuilderTypeMirror);
    TypeElement barBuilderTypeElement = MoreTypes.asTypeElement(barBuilderTypeMirror);
    Map<String, ExecutableElement> barBuilderNoArgMethods = noArgMethodsOf(barBuilderTypeElement);
    ExecutableElement barGetter = getterToPropertyName.inverse().get(property);
    TypeMirror barTypeMirror = barGetter.getReturnType();
    if (barTypeMirror.getKind() != TypeKind.DECLARED) {
        errorReporter.reportError("Method looks like a property builder, but the type of property " + property + " is not a class or interface", method);
        return Optional.absent();
    }
    if (isNullable(barGetter)) {
        errorReporter.reportError("Property " + property + " has a property builder so it cannot " + "be @Nullable", barGetter);
    }
    TypeElement barTypeElement = MoreTypes.asTypeElement(barTypeMirror);
    Map<String, ExecutableElement> barNoArgMethods = noArgMethodsOf(barTypeElement);
    // Condition (1), must have build() method returning Bar.
    ExecutableElement build = barBuilderNoArgMethods.get("build");
    if (build == null || build.getModifiers().contains(Modifier.STATIC)) {
        errorReporter.reportError("Method looks like a property builder, but it returns " + barBuilderTypeElement + " which does not have a non-static build() method", method);
        return Optional.absent();
    }
    // We've determined that `BarBuilder` has a method `build()`. But it must return `Bar`.
    // And if the type of `bar()` is Bar<String> then `BarBuilder.build()` must return Bar<String>.
    TypeMirror buildType = eclipseHack.methodReturnType(build, barBuilderDeclaredType);
    if (!MoreTypes.equivalence().equivalent(barTypeMirror, buildType)) {
        errorReporter.reportError("Property builder for " + property + " has type " + barBuilderTypeElement + " whose build() method returns " + buildType + " instead of " + barTypeMirror, method);
        return Optional.absent();
    }
    Optional<ExecutableElement> maybeBuilderMaker = builderMaker(barNoArgMethods, barBuilderTypeElement);
    if (!maybeBuilderMaker.isPresent()) {
        errorReporter.reportError("Method looks like a property builder, but its type " + barBuilderTypeElement + " does not have a public constructor and " + barTypeElement + " does not have a static builder() or newBuilder() method that returns " + barBuilderTypeElement, method);
        return Optional.absent();
    }
    ExecutableElement builderMaker = maybeBuilderMaker.get();
    String barBuilderType = typeSimplifier.simplify(barBuilderTypeMirror);
    String rawBarType = typeSimplifier.simplifyRaw(barTypeMirror);
    String initializer = (builderMaker.getKind() == ElementKind.CONSTRUCTOR) ? "new " + barBuilderType + "()" : rawBarType + "." + builderMaker.getSimpleName() + "()";
    String builtToBuilder = null;
    String copyAll = null;
    ExecutableElement toBuilder = barNoArgMethods.get("toBuilder");
    if (toBuilder != null && !toBuilder.getModifiers().contains(Modifier.STATIC) && typeUtils.isAssignable(typeUtils.erasure(toBuilder.getReturnType()), typeUtils.erasure(barBuilderTypeMirror))) {
        builtToBuilder = toBuilder.getSimpleName().toString();
    } else {
        boolean isGuavaBuilder = barBuilderTypeMirror.toString().startsWith(COM_GOOGLE_COMMON_COLLECT_IMMUTABLE) && barBuilderType.contains(".Builder<");
        Optional<ExecutableElement> maybeCopyAll = addAllPutAll(barBuilderTypeElement);
        if (maybeCopyAll.isPresent() && isGuavaBuilder) {
            copyAll = maybeCopyAll.get().getSimpleName().toString();
        }
    }
    ExecutableElement barOf = barNoArgMethods.get("of");
    boolean hasOf = (barOf != null && barOf.getModifiers().contains(Modifier.STATIC));
    // An expression (initDefault) to make a default one of these, plus optionally a statement
    // (beforeInitDefault) that prepares the expression. For a collection, beforeInitDefault is
    // empty and initDefault is (e.g.) `ImmutableList.of()`. For a nested value type,
    // beforeInitDefault is (e.g.)
    //   `NestedAutoValueType.Builder foo$builder = NestedAutoValueType.builder();`
    // and initDefault is `foo$builder.build();`. The reason for the separate statement is to
    // exploit type inference rather than having to write `NestedAutoValueType.<Bar>build();`.
    String beforeInitDefault;
    String initDefault;
    if (hasOf) {
        beforeInitDefault = "";
        initDefault = rawBarType + ".of()";
    } else {
        String localBuilder = property + "$builder";
        beforeInitDefault = barBuilderType + " " + localBuilder + " = " + initializer + ";";
        initDefault = localBuilder + ".build()";
    }
    PropertyBuilder propertyBuilder = new PropertyBuilder(method, barBuilderType, initializer, beforeInitDefault, initDefault, builtToBuilder, copyAll);
    return Optional.of(propertyBuilder);
}
Also used : TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) DeclaredType(javax.lang.model.type.DeclaredType)

Example 37 with DeclaredType

use of javax.lang.model.type.DeclaredType in project auto by google.

the class AutoAnnotationProcessor method wrapperTypesUsedInCollections.

/**
   * Returns the wrapper types ({@code Integer.class} etc) that are used in collection parameters
   * like {@code List<Integer>}. This is needed because we will emit a helper method for each such
   * type, for example to convert {@code Collection<Integer>} into {@code int[]}.
   */
private Set<Class<?>> wrapperTypesUsedInCollections(ExecutableElement method) {
    TypeElement javaUtilCollection = processingEnv.getElementUtils().getTypeElement(Collection.class.getName());
    ImmutableSet.Builder<Class<?>> usedInCollections = ImmutableSet.builder();
    for (Class<?> wrapper : Primitives.allWrapperTypes()) {
        DeclaredType collectionOfWrapper = typeUtils.getDeclaredType(javaUtilCollection, getTypeMirror(wrapper));
        for (VariableElement parameter : method.getParameters()) {
            if (typeUtils.isAssignable(parameter.asType(), collectionOfWrapper)) {
                usedInCollections.add(wrapper);
                break;
            }
        }
    }
    return usedInCollections.build();
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) TypeElement(javax.lang.model.element.TypeElement) Collection(java.util.Collection) VariableElement(javax.lang.model.element.VariableElement) DeclaredType(javax.lang.model.type.DeclaredType)

Example 38 with DeclaredType

use of javax.lang.model.type.DeclaredType in project auto by google.

the class AutoServiceProcessor method processAnnotations.

private void processAnnotations(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(AutoService.class);
    log(annotations.toString());
    log(elements.toString());
    for (Element e : elements) {
        // TODO(gak): check for error trees?
        TypeElement providerImplementer = (TypeElement) e;
        AnnotationMirror providerAnnotation = getAnnotationMirror(e, AutoService.class).get();
        DeclaredType providerInterface = getProviderInterface(providerAnnotation);
        TypeElement providerType = (TypeElement) providerInterface.asElement();
        log("provider interface: " + providerType.getQualifiedName());
        log("provider implementer: " + providerImplementer.getQualifiedName());
        if (!checkImplementer(providerImplementer, providerType)) {
            String message = "ServiceProviders must implement their service provider interface. " + providerImplementer.getQualifiedName() + " does not implement " + providerType.getQualifiedName();
            error(message, e, providerAnnotation);
        }
        String providerTypeName = getBinaryName(providerType);
        String providerImplementerName = getBinaryName(providerImplementer);
        log("provider interface binary name: " + providerTypeName);
        log("provider implementer binary name: " + providerImplementerName);
        providers.put(providerTypeName, providerImplementerName);
    }
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) MoreElements.getAnnotationMirror(com.google.auto.common.MoreElements.getAnnotationMirror) AutoService(com.google.auto.service.AutoService) TypeElement(javax.lang.model.element.TypeElement) PackageElement(javax.lang.model.element.PackageElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) DeclaredType(javax.lang.model.type.DeclaredType)

Example 39 with DeclaredType

use of javax.lang.model.type.DeclaredType in project j2objc by google.

the class AbstractMethodRewriter method addReturnTypeNarrowingDeclarations.

// Adds declarations for any methods where the known return type is more
// specific than what is already declared in inherited types.
private void addReturnTypeNarrowingDeclarations(AbstractTypeDeclaration node) {
    TypeElement type = node.getTypeElement();
    // No need to run this if the entire class is dead.
    if (deadCodeMap != null && deadCodeMap.containsClass(type, elementUtil)) {
        return;
    }
    Map<String, ExecutablePair> newDeclarations = new HashMap<>();
    Map<String, TypeMirror> resolvedReturnTypes = new HashMap<>();
    for (DeclaredType inheritedType : typeUtil.getObjcOrderedInheritedTypes(type.asType())) {
        TypeElement inheritedElem = (TypeElement) inheritedType.asElement();
        for (ExecutableElement methodElem : ElementUtil.getMethods(inheritedElem)) {
            if (ElementUtil.isPrivate(methodElem)) {
                continue;
            }
            TypeMirror declaredReturnType = typeUtil.erasure(methodElem.getReturnType());
            if (!TypeUtil.isReferenceType(declaredReturnType)) {
                // Short circuit
                continue;
            }
            String selector = nameTable.getMethodSelector(methodElem);
            ExecutableType methodType = typeUtil.asMemberOf(inheritedType, methodElem);
            TypeMirror returnType = typeUtil.erasure(methodType.getReturnType());
            TypeMirror resolvedReturnType = resolvedReturnTypes.get(selector);
            if (resolvedReturnType == null) {
                resolvedReturnType = declaredReturnType;
                resolvedReturnTypes.put(selector, resolvedReturnType);
            } else if (!typeUtil.isSubtype(returnType, resolvedReturnType)) {
                continue;
            }
            if (resolvedReturnType != returnType && !nameTable.getObjCType(resolvedReturnType).equals(nameTable.getObjCType(returnType))) {
                newDeclarations.put(selector, new ExecutablePair(methodElem, methodType));
                resolvedReturnTypes.put(selector, returnType);
            }
        }
    }
    for (Map.Entry<String, ExecutablePair> newDecl : newDeclarations.entrySet()) {
        if (deadCodeMap != null && deadCodeMap.containsMethod(newDecl.getValue().element(), typeUtil)) {
            continue;
        }
        node.addBodyDeclaration(newReturnTypeNarrowingDeclaration(newDecl.getKey(), newDecl.getValue(), type));
    }
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) HashMap(java.util.HashMap) ExecutablePair(com.google.devtools.j2objc.types.ExecutablePair) TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) GeneratedExecutableElement(com.google.devtools.j2objc.types.GeneratedExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) HashMap(java.util.HashMap) Map(java.util.Map) CodeReferenceMap(com.google.devtools.j2objc.util.CodeReferenceMap) DeclaredType(javax.lang.model.type.DeclaredType)

Example 40 with DeclaredType

use of javax.lang.model.type.DeclaredType in project j2objc by google.

the class TreeConverter method addImplicitSuperCall.

private static void addImplicitSuperCall(MethodDeclaration node) {
    ExecutableElement method = node.getExecutableElement();
    DeclaredType superType = (DeclaredType) ElementUtil.getDeclaringClass(method).getSuperclass();
    TypeElement superClass = TypeUtil.asTypeElement(superType);
    ExecutableElement superConstructor = findDefaultConstructorElement(superClass);
    SuperConstructorInvocation invocation = new SuperConstructorInvocation(new ExecutablePair(superConstructor, (ExecutableType) JdtTypes.asMemberOfInternal(superType, superConstructor))).setVarargsType(getVarargsType(BindingConverter.unwrapExecutableElement(superConstructor), Collections.emptyList()));
    node.getBody().addStatement(0, invocation);
}
Also used : ExecutablePair(com.google.devtools.j2objc.types.ExecutablePair) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) SuperConstructorInvocation(com.google.devtools.j2objc.ast.SuperConstructorInvocation) DeclaredType(javax.lang.model.type.DeclaredType)

Aggregations

DeclaredType (javax.lang.model.type.DeclaredType)138 TypeElement (javax.lang.model.element.TypeElement)82 TypeMirror (javax.lang.model.type.TypeMirror)75 ExecutableElement (javax.lang.model.element.ExecutableElement)38 Element (javax.lang.model.element.Element)28 VariableElement (javax.lang.model.element.VariableElement)26 AnnotationMirror (javax.lang.model.element.AnnotationMirror)19 Test (org.junit.Test)19 ArrayType (javax.lang.model.type.ArrayType)15 ArrayList (java.util.ArrayList)14 List (java.util.List)10 Map (java.util.Map)9 AbstractJClass (com.helger.jcodemodel.AbstractJClass)8 HashSet (java.util.HashSet)8 AnnotationValue (javax.lang.model.element.AnnotationValue)8 HashMap (java.util.HashMap)6 TypeParameterElement (javax.lang.model.element.TypeParameterElement)6 Types (javax.lang.model.util.Types)6 Name (javax.lang.model.element.Name)5 PackageElement (javax.lang.model.element.PackageElement)5