Search in sources :

Example 61 with ExecutableType

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

the class BuilderMethodClassifier method getSetterFunction.

/**
 * Returns an {@code Optional} describing how to convert a value from the setter's parameter type
 * to the getter's return type, or {@code Optional.empty()} if the conversion isn't possible. An
 * error will have been reported in the latter case. We can convert if they are already the same
 * type, when the returned function will be the identity; or if the setter type can be copied
 * using a method like {@code ImmutableList.copyOf} or {@code Optional.of}, when the returned
 * function will be something like {@code s -> "Optional.of(" + s + ")"}.
 */
private Optional<Copier> getSetterFunction(E propertyElement, ExecutableElement setter) {
    VariableElement parameterElement = Iterables.getOnlyElement(setter.getParameters());
    boolean nullableParameter = nullableAnnotationFor(parameterElement, parameterElement.asType()).isPresent();
    String property = propertyElements().inverse().get(propertyElement);
    TypeMirror targetType = rewrittenPropertyTypes.get(property);
    ExecutableType finalSetter = MoreTypes.asExecutable(typeUtils.asMemberOf(MoreTypes.asDeclared(builderType.asType()), setter));
    TypeMirror parameterType = finalSetter.getParameterTypes().get(0);
    // we're likely to want to accept those too.
    if (typeUtils.isAssignable(parameterType, targetType) && typeUtils.isAssignable(targetType, parameterType)) {
        if (nullableParameter) {
            boolean nullableProperty = nullableAnnotationFor(propertyElement, originalPropertyType(propertyElement)).isPresent();
            if (!nullableProperty) {
                errorReporter.reportError(setter, "[%sNullNotNull] Parameter of setter method is @Nullable but %s is not", autoWhat(), propertyString(propertyElement));
                return Optional.empty();
            }
        }
        return Optional.of(Copier.IDENTITY);
    }
    // Parameter type is not equal to property type, but might be convertible with copyOf.
    ImmutableList<ExecutableElement> copyOfMethods = copyOfMethods(targetType, nullableParameter);
    if (!copyOfMethods.isEmpty()) {
        return getConvertingSetterFunction(copyOfMethods, propertyElement, setter, parameterType);
    }
    errorReporter.reportError(setter, "[%sGetVsSet] Parameter type %s of setter method should be %s to match %s", autoWhat(), parameterType, targetType, propertyString(propertyElement));
    return Optional.empty();
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) TypeMirror(javax.lang.model.type.TypeMirror) ExecutableElement(javax.lang.model.element.ExecutableElement) VariableElement(javax.lang.model.element.VariableElement)

Example 62 with ExecutableType

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

the class BuilderMethodClassifier method classifyMethodOneArg.

/**
 * Classifies a method given that it has one argument. A method with one argument can be:
 *
 * <ul>
 *   <li>a setter, meaning that it looks like {@code foo(T)} or {@code setFoo(T)}, where the
 *       {@code AutoValue} class has a property called {@code foo} of type {@code T};
 *   <li>a property builder with one argument, meaning it looks like {@code
 *       ImmutableSortedSet.Builder<V> foosBuilder(Comparator<V>)}, where the {@code AutoValue}
 *       class has a property called {@code foos} with a type whose builder can be made with an
 *       argument of the given type.
 * </ul>
 */
private void classifyMethodOneArg(ExecutableElement method) {
    if (classifyPropertyBuilderOneArg(method)) {
        return;
    }
    String methodName = method.getSimpleName().toString();
    ImmutableMap<String, E> propertyElements = propertyElements();
    String propertyName = null;
    E propertyElement = propertyElements.get(methodName);
    Multimap<String, PropertySetter> propertyNameToSetters = null;
    if (propertyElement != null) {
        propertyNameToSetters = propertyNameToUnprefixedSetters;
        propertyName = methodName;
    } else if (methodName.startsWith("set") && methodName.length() > 3) {
        propertyNameToSetters = propertyNameToPrefixedSetters;
        propertyName = PropertyNames.decapitalizeLikeJavaBeans(methodName.substring(3));
        propertyElement = propertyElements.get(propertyName);
        if (propertyElement == null) {
            // If our property is defined by a getter called getOAuth() then it is called "OAuth"
            // because of JavaBeans rules. Therefore we want JavaBeans rules to be used for the setter
            // too, so that you can write setOAuth(x). Meanwhile if the property is defined by a getter
            // called oAuth() then it is called "oAuth", but you would still expect to be able to set it
            // using setOAuth(x). Hence the second try using a decapitalize method without the quirky
            // two-leading-capitals rule.
            propertyName = PropertyNames.decapitalizeNormally(methodName.substring(3));
            propertyElement = propertyElements.get(propertyName);
        }
    } else {
        // We might also have an unprefixed setter, so the getter is called OAuth() or getOAuth() and
        // the setter is called oAuth(x), where again JavaBeans rules imply that it should be called
        // OAuth(x). Iterating over the properties here is a bit clunky but this case should be
        // unusual.
        propertyNameToSetters = propertyNameToUnprefixedSetters;
        for (Map.Entry<String, E> entry : propertyElements.entrySet()) {
            if (methodName.equals(PropertyNames.decapitalizeNormally(entry.getKey()))) {
                propertyName = entry.getKey();
                propertyElement = entry.getValue();
                break;
            }
        }
    }
    if (propertyElement == null || propertyNameToSetters == null) {
        // The second disjunct isn't needed but convinces control-flow checkers that
        // propertyNameToSetters can't be null when we call put on it below.
        errorReporter.reportError(method, "[%sBuilderWhatProp] Method %s does not correspond to %s", autoWhat(), methodName, getterMustMatch());
        checkForFailedJavaBean(method);
        return;
    }
    Optional<Copier> function = getSetterFunction(propertyElement, method);
    if (function.isPresent()) {
        DeclaredType builderTypeMirror = MoreTypes.asDeclared(builderType.asType());
        ExecutableType methodMirror = MoreTypes.asExecutable(typeUtils.asMemberOf(builderTypeMirror, method));
        TypeMirror returnType = methodMirror.getReturnType();
        if (typeUtils.isSubtype(builderType.asType(), returnType) && !MoreTypes.isTypeOf(Object.class, returnType)) {
            // We allow the return type to be a supertype (other than Object), to support step builders.
            TypeMirror parameterType = Iterables.getOnlyElement(methodMirror.getParameterTypes());
            propertyNameToSetters.put(propertyName, new PropertySetter(method, parameterType, function.get()));
        } else {
            errorReporter.reportError(method, "[%sBuilderRet] Setter methods must return %s or a supertype", autoWhat(), builderType.asType());
        }
    }
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) TypeMirror(javax.lang.model.type.TypeMirror) PropertySetter(com.google.auto.value.processor.BuilderSpec.PropertySetter) Copier(com.google.auto.value.processor.BuilderSpec.Copier) DeclaredType(javax.lang.model.type.DeclaredType)

Example 63 with ExecutableType

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

the class AutoFactoryProcessor method implementationMethods.

private ImmutableSet<ImplementationMethodDescriptor> implementationMethods(TypeElement supertype, Element autoFactoryElement) {
    ImmutableSet.Builder<ImplementationMethodDescriptor> implementationMethodsBuilder = ImmutableSet.builder();
    for (ExecutableElement implementationMethod : ElementFilter.methodsIn(elements.getAllMembers(supertype))) {
        if (implementationMethod.getModifiers().contains(Modifier.ABSTRACT)) {
            ExecutableType methodType = Elements2.getExecutableElementAsMemberOf(types, implementationMethod, supertype);
            ImmutableSet<Parameter> passedParameters = Parameter.forParameterList(implementationMethod.getParameters(), methodType.getParameterTypes(), types);
            implementationMethodsBuilder.add(ImplementationMethodDescriptor.builder().name(implementationMethod.getSimpleName().toString()).returnType(getAnnotatedType(autoFactoryElement)).publicMethod().passedParameters(passedParameters).isVarArgs(implementationMethod.isVarArgs()).exceptions(implementationMethod.getThrownTypes()).build());
        }
    }
    return implementationMethodsBuilder.build();
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) ImmutableSet(com.google.common.collect.ImmutableSet) ExecutableElement(javax.lang.model.element.ExecutableElement)

Example 64 with ExecutableType

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

the class TreeConverter method convertMethodInvocation.

private TreeNode convertMethodInvocation(MethodInvocationTree node, TreePath parent) {
    TreePath path = getTreePath(parent, node);
    ExpressionTree method = node.getMethodSelect();
    TreePath methodInvocationPath = getTreePath(path, method);
    String methodName = getMemberName(method);
    ExecutableType type = (ExecutableType) getTypeMirror(methodInvocationPath);
    ExecutableElement element = (ExecutableElement) getElement(methodInvocationPath);
    ExpressionTree target = method.getKind() == Kind.MEMBER_SELECT ? ((MemberSelectTree) method).getExpression() : null;
    if ("this".equals(methodName)) {
        ConstructorInvocation newNode = new ConstructorInvocation().setExecutablePair(new ExecutablePair(element)).setVarargsType(((JCMethodInvocation) node).varargsElement);
        for (ExpressionTree arg : node.getArguments()) {
            newNode.addArgument((Expression) convert(arg, path));
        }
        return newNode;
    }
    if ("super".equals(methodName)) {
        if (element == null && node.getArguments().isEmpty()) {
            // If multiple classes have default constructors added, javac may not have an element
            // defined for the super() invocation, so create an equivalent here.
            TreePath methodPath = parent;
            while (methodPath.getLeaf().getKind() != Kind.METHOD) {
                methodPath = methodPath.getParentPath();
            }
            ExecutableElement enclosingMethod = (ExecutableElement) getElement(methodPath);
            TypeMirror superclassType = ElementUtil.getDeclaringClass(enclosingMethod).getSuperclass();
            TypeElement superclass = (TypeElement) ((DeclaredType) superclassType).asElement();
            element = GeneratedExecutableElement.newConstructor(superclass, newUnit.getEnv().typeUtil());
        }
        SuperConstructorInvocation newNode = new SuperConstructorInvocation().setExecutablePair(new ExecutablePair(element)).setVarargsType(((JCMethodInvocation) node).varargsElement);
        if (target != null) {
            newNode.setExpression((Expression) convert(target, methodInvocationPath));
        }
        for (ExpressionTree arg : node.getArguments()) {
            newNode.addArgument((Expression) convert(arg, path));
        }
        return newNode;
    }
    if (target != null && "super".equals(getMemberName(target))) {
        SuperMethodInvocation newNode = new SuperMethodInvocation().setExecutablePair(new ExecutablePair(element, type)).setVarargsType(((JCMethodInvocation) node).varargsElement);
        if (target.getKind() == Kind.MEMBER_SELECT) {
            // foo.bar.MyClass.super.print(...):
            // target: foo.bar.MyClass.super
            // target.selected: foo.bar.MyClass
            TreePath targetPath = getTreePath(getTreePath(path, method), target);
            newNode.setQualifier((Name) convert(((MemberSelectTree) target).getExpression(), targetPath));
        }
        for (ExpressionTree arg : node.getArguments()) {
            newNode.addArgument((Expression) convert(arg, path));
        }
        return newNode;
    }
    MethodInvocation newNode = new MethodInvocation();
    if (target != null) {
        newNode.setExpression((Expression) convert(target, methodInvocationPath));
    }
    for (ExpressionTree arg : node.getArguments()) {
        newNode.addArgument((Expression) convert(arg, path));
    }
    return newNode.setTypeMirror(getTypeMirror(path)).setExecutablePair(new ExecutablePair(element, type)).setVarargsType(((JCMethodInvocation) node).varargsElement);
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) TreePath(com.sun.source.util.TreePath) ConstructorInvocation(com.google.devtools.j2objc.ast.ConstructorInvocation) SuperConstructorInvocation(com.google.devtools.j2objc.ast.SuperConstructorInvocation) ExecutablePair(com.google.devtools.j2objc.types.ExecutablePair) TypeMirror(javax.lang.model.type.TypeMirror) GeneratedTypeElement(com.google.devtools.j2objc.types.GeneratedTypeElement) TypeElement(javax.lang.model.element.TypeElement) GeneratedExecutableElement(com.google.devtools.j2objc.types.GeneratedExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MethodInvocation(com.google.devtools.j2objc.ast.MethodInvocation) JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) SuperMethodInvocation(com.google.devtools.j2objc.ast.SuperMethodInvocation) SuperConstructorInvocation(com.google.devtools.j2objc.ast.SuperConstructorInvocation) SuperMethodInvocation(com.google.devtools.j2objc.ast.SuperMethodInvocation)

Example 65 with ExecutableType

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

the class LogSiteInjector method injectLogSite.

private MethodInvocation injectLogSite(MethodInvocation node) {
    // Inject withInjectedLogSite(class, method, line, file) into method expression.
    ExecutableElement injectedMethod = ElementUtil.findMethod(loggingApiClass, WITH_INJECTED_LOG_SITE_METHOD, "java.lang.String", "java.lang.String", "int", "java.lang.String");
    DeclaredType loggingApiClassType = googleLoggerApiClass != null ? (DeclaredType) googleLoggerApiClass.asType() : (DeclaredType) loggingApiClass.asType();
    ExecutableType injectedType = typeUtil.asMemberOf(loggingApiClassType, injectedMethod);
    MethodInvocation injectedInvocation = new MethodInvocation(new ExecutablePair(injectedMethod, injectedType), node.getExpression().copy());
    injectedInvocation.addArgument(enclosingClassLiteral(node));
    injectedInvocation.addArgument(enclosingMethodLiteral(node));
    injectedInvocation.addArgument(lineNumberLiteral(node));
    injectedInvocation.addArgument(sourceFileLiteral());
    MethodInvocation newNode = new MethodInvocation(node.getExecutablePair(), injectedInvocation);
    for (Expression arg : node.getArguments()) {
        newNode.addArgument(arg.copy());
    }
    return newNode;
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) ExecutablePair(com.google.devtools.j2objc.types.ExecutablePair) Expression(com.google.devtools.j2objc.ast.Expression) ExecutableElement(javax.lang.model.element.ExecutableElement) MethodInvocation(com.google.devtools.j2objc.ast.MethodInvocation) DeclaredType(javax.lang.model.type.DeclaredType)

Aggregations

ExecutableType (javax.lang.model.type.ExecutableType)83 ExecutableElement (javax.lang.model.element.ExecutableElement)64 DeclaredType (javax.lang.model.type.DeclaredType)47 TypeMirror (javax.lang.model.type.TypeMirror)45 TypeElement (javax.lang.model.element.TypeElement)44 Element (javax.lang.model.element.Element)33 VariableElement (javax.lang.model.element.VariableElement)33 Nonnull (javax.annotation.Nonnull)22 ArrayList (java.util.ArrayList)18 MethodSpec (com.squareup.javapoet.MethodSpec)15 HashMap (java.util.HashMap)15 Map (java.util.Map)15 AnnotationMirror (javax.lang.model.element.AnnotationMirror)15 TypeSpec (com.squareup.javapoet.TypeSpec)14 HashSet (java.util.HashSet)14 TypeKind (javax.lang.model.type.TypeKind)14 IOException (java.io.IOException)13 Nullable (javax.annotation.Nullable)13 PackageElement (javax.lang.model.element.PackageElement)13 List (java.util.List)12