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();
}
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());
}
}
}
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();
}
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);
}
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;
}
Aggregations