use of com.google.auto.value.processor.BuilderSpec.PropertySetter in project auto by google.
the class BuilderMethodClassifier method classifyMethods.
/**
* Classifies the given methods and sets the state of this object based on what is found.
*/
boolean classifyMethods(Iterable<ExecutableElement> methods, boolean autoValueHasToBuilder) {
int startErrorCount = errorReporter.errorCount();
for (ExecutableElement method : methods) {
classifyMethod(method);
}
if (errorReporter.errorCount() > startErrorCount) {
return false;
}
Multimap<String, PropertySetter> propertyNameToSetter;
if (propertyNameToPrefixedSetters.isEmpty()) {
propertyNameToSetter = propertyNameToUnprefixedSetters;
this.settersPrefixed = false;
} else if (propertyNameToUnprefixedSetters.isEmpty()) {
propertyNameToSetter = propertyNameToPrefixedSetters;
this.settersPrefixed = true;
} else {
errorReporter.reportError(propertyNameToUnprefixedSetters.values().iterator().next().getSetter(), "[%sSetNotSet] If any setter methods use the setFoo convention then all must", autoWhat());
return false;
}
for (String property : rewrittenPropertyTypes.keySet()) {
TypeMirror propertyType = rewrittenPropertyTypes.get(property);
boolean hasSetter = propertyNameToSetter.containsKey(property);
PropertyBuilder propertyBuilder = propertyNameToPropertyBuilder.get(property);
boolean hasBuilder = propertyBuilder != null;
if (hasBuilder) {
// If property bar of type Bar has a barBuilder() that returns BarBuilder, then it must
// be possible to make a BarBuilder from a Bar if either (1) the @AutoValue class has a
// toBuilder() or (2) there is also a setBar(Bar). Making BarBuilder from Bar is
// possible if Bar either has a toBuilder() method or BarBuilder has an addAll or putAll
// method that accepts a Bar argument.
boolean canMakeBarBuilder = (propertyBuilder.getBuiltToBuilder() != null || propertyBuilder.getCopyAll() != null);
boolean needToMakeBarBuilder = (autoValueHasToBuilder || hasSetter);
if (needToMakeBarBuilder && !canMakeBarBuilder) {
errorReporter.reportError(propertyBuilder.getPropertyBuilderMethod(), "[AutoValueCantMakeBuilder] Property builder method returns %1$s but there is no" + " way to make that type from %2$s: %2$s does not have a non-static" + " toBuilder() method that returns %1$s, and %1$s does not have a method" + " addAll or putAll that accepts an argument of type %2$s", propertyBuilder.getBuilderTypeMirror(), propertyType);
}
} else if (!hasSetter && !propertiesWithDefaults.contains(property)) {
// We have neither barBuilder() nor setBar(Bar), so we should complain.
String setterName = settersPrefixed ? prefixWithSet(property) : property;
errorReporter.reportError(builderType, "[%sBuilderMissingMethod] Expected a method with this signature: %s" + " %s(%s), or a %sBuilder() method", autoWhat(), builderType.asType(), setterName, propertyType, property);
}
}
return errorReporter.errorCount() == startErrorCount;
}
use of com.google.auto.value.processor.BuilderSpec.PropertySetter 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());
}
}
}
Aggregations