• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal.codegen.binding;
18 
19 import com.google.common.base.Joiner;
20 import com.google.common.collect.ImmutableMap;
21 import dagger.internal.codegen.base.ComponentAnnotation;
22 import java.util.Set;
23 import java.util.function.Function;
24 import java.util.function.UnaryOperator;
25 import javax.lang.model.element.ExecutableElement;
26 import javax.lang.model.element.TypeElement;
27 import javax.lang.model.type.TypeMirror;
28 
29 /** The collection of error messages to be reported back to users. */
30 public final class ErrorMessages {
31 
32   private static final UnaryOperator<String> PRODUCTION =
33       s ->
34           s.replace("component", "production component")
35               .replace("Component", "ProductionComponent");
36 
37   private static final UnaryOperator<String> SUBCOMPONENT =
38       s -> s.replace("component", "subcomponent").replace("Component", "Subcomponent");
39 
40   private static final UnaryOperator<String> FACTORY = s -> s.replace("Builder", "Factory");
41 
42   private static final ImmutableMap<ComponentKind, Function<String, String>>
43       COMPONENT_TRANSFORMATIONS =
44           ImmutableMap.of(
45               ComponentKind.COMPONENT, UnaryOperator.identity(),
46               ComponentKind.SUBCOMPONENT, SUBCOMPONENT,
47               ComponentKind.PRODUCTION_COMPONENT, PRODUCTION,
48               ComponentKind.PRODUCTION_SUBCOMPONENT, PRODUCTION.andThen(SUBCOMPONENT));
49 
componentMessagesFor(ComponentKind componentKind)50   public static ComponentMessages componentMessagesFor(ComponentKind componentKind) {
51     return new ComponentMessages(COMPONENT_TRANSFORMATIONS.get(componentKind));
52   }
53 
componentMessagesFor(ComponentAnnotation componentAnnotation)54   public static ComponentMessages componentMessagesFor(ComponentAnnotation componentAnnotation) {
55     return new ComponentMessages(
56         transformation(componentAnnotation.isProduction(), componentAnnotation.isSubcomponent()));
57   }
58 
creatorMessagesFor( ComponentCreatorAnnotation creatorAnnotation)59   public static ComponentCreatorMessages creatorMessagesFor(
60       ComponentCreatorAnnotation creatorAnnotation) {
61     Function<String, String> transformation =
62         transformation(
63             creatorAnnotation.isProductionCreatorAnnotation(),
64             creatorAnnotation.isSubcomponentCreatorAnnotation());
65     switch (creatorAnnotation.creatorKind()) {
66       case BUILDER:
67         return new BuilderMessages(transformation);
68       case FACTORY:
69         return new FactoryMessages(transformation);
70     }
71     throw new AssertionError(creatorAnnotation);
72   }
73 
transformation( boolean isProduction, boolean isSubcomponent)74   private static Function<String, String> transformation(
75       boolean isProduction, boolean isSubcomponent) {
76     Function<String, String> transformation = isProduction ? PRODUCTION : UnaryOperator.identity();
77     return isSubcomponent ? transformation.andThen(SUBCOMPONENT) : transformation;
78   }
79 
80   private abstract static class Messages {
81     private final Function<String, String> transformation;
82 
Messages(Function<String, String> transformation)83     Messages(Function<String, String> transformation) {
84       this.transformation = transformation;
85     }
86 
process(String s)87     protected final String process(String s) {
88       return transformation.apply(s);
89     }
90   }
91 
92   /** Errors for components. */
93   public static final class ComponentMessages extends Messages {
ComponentMessages(Function<String, String> transformation)94     ComponentMessages(Function<String, String> transformation) {
95       super(transformation);
96     }
97 
moreThanOne()98     public final String moreThanOne() {
99       return process("@Component has more than one @Component.Builder or @Component.Factory: %s");
100     }
101   }
102 
103   /** Errors for component creators. */
104   public abstract static class ComponentCreatorMessages extends Messages {
ComponentCreatorMessages(Function<String, String> transformation)105     ComponentCreatorMessages(Function<String, String> transformation) {
106       super(transformation);
107     }
108 
builderMethodRequiresNoArgs()109     public static String builderMethodRequiresNoArgs() {
110       return "Methods returning a @Component.Builder must have no arguments";
111     }
112 
moreThanOneRefToSubcomponent()113     public static String moreThanOneRefToSubcomponent() {
114       return "Only one method can create a given subcomponent. %s is created by: %s";
115     }
116 
invalidConstructor()117     public final String invalidConstructor() {
118       return process("@Component.Builder classes must have exactly one constructor,"
119           + " and it must not be private or have any parameters");
120     }
121 
generics()122     public final String generics() {
123       return process("@Component.Builder types must not have any generic types");
124     }
125 
mustBeInComponent()126     public final String mustBeInComponent() {
127       return process("@Component.Builder types must be nested within a @Component");
128     }
129 
mustBeClassOrInterface()130     public final String mustBeClassOrInterface() {
131       return process("@Component.Builder types must be abstract classes or interfaces");
132     }
133 
isPrivate()134     public final String isPrivate() {
135       return process("@Component.Builder types must not be private");
136     }
137 
mustBeStatic()138     public final String mustBeStatic() {
139       return process("@Component.Builder types must be static");
140     }
141 
mustBeAbstract()142     public final String mustBeAbstract() {
143       return process("@Component.Builder types must be abstract");
144     }
145 
missingFactoryMethod()146     public abstract String missingFactoryMethod();
147 
multipleSettersForModuleOrDependencyType()148     public abstract String multipleSettersForModuleOrDependencyType();
149 
extraSetters()150     public abstract String extraSetters();
151 
missingSetters()152     public abstract String missingSetters();
153 
twoFactoryMethods()154     public abstract String twoFactoryMethods();
155 
inheritedTwoFactoryMethods()156     public abstract String inheritedTwoFactoryMethods();
157 
factoryMethodMustReturnComponentType()158     public abstract String factoryMethodMustReturnComponentType();
159 
inheritedFactoryMethodMustReturnComponentType()160     public final String inheritedFactoryMethodMustReturnComponentType() {
161       return factoryMethodMustReturnComponentType() + ". Inherited method: %s";
162     }
163 
factoryMethodMayNotBeAnnotatedWithBindsInstance()164     public abstract String factoryMethodMayNotBeAnnotatedWithBindsInstance();
165 
inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance()166     public final String inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance() {
167       return factoryMethodMayNotBeAnnotatedWithBindsInstance() + ". Inherited method: %s";
168     }
169 
setterMethodsMustTakeOneArg()170     public final String setterMethodsMustTakeOneArg() {
171       return process("@Component.Builder methods must not have more than one argument");
172     }
173 
inheritedSetterMethodsMustTakeOneArg()174     public final String inheritedSetterMethodsMustTakeOneArg() {
175       return setterMethodsMustTakeOneArg() + ". Inherited method: %s";
176     }
177 
setterMethodsMustReturnVoidOrBuilder()178     public final String setterMethodsMustReturnVoidOrBuilder() {
179       return process("@Component.Builder setter methods must return void, the builder,"
180           + " or a supertype of the builder");
181     }
182 
inheritedSetterMethodsMustReturnVoidOrBuilder()183     public final String inheritedSetterMethodsMustReturnVoidOrBuilder() {
184       return setterMethodsMustReturnVoidOrBuilder() + ". Inherited method: %s";
185     }
186 
methodsMayNotHaveTypeParameters()187     public final String methodsMayNotHaveTypeParameters() {
188       return process("@Component.Builder methods must not have type parameters");
189     }
190 
inheritedMethodsMayNotHaveTypeParameters()191     public final String inheritedMethodsMayNotHaveTypeParameters() {
192       return methodsMayNotHaveTypeParameters() + ". Inherited method: %s";
193     }
194 
nonBindsInstanceParametersMayNotBePrimitives()195     public abstract String nonBindsInstanceParametersMayNotBePrimitives();
196 
inheritedNonBindsInstanceParametersMayNotBePrimitives()197     public final String inheritedNonBindsInstanceParametersMayNotBePrimitives() {
198       return nonBindsInstanceParametersMayNotBePrimitives() + ". Inherited method: %s";
199     }
200 
factoryMethodReturnsSupertypeWithMissingMethods( TypeElement component, TypeElement componentBuilder, TypeMirror returnType, ExecutableElement buildMethod, Set<ExecutableElement> additionalMethods)201     public final String factoryMethodReturnsSupertypeWithMissingMethods(
202         TypeElement component,
203         TypeElement componentBuilder,
204         TypeMirror returnType,
205         ExecutableElement buildMethod,
206         Set<ExecutableElement> additionalMethods) {
207       return String.format(
208           "%1$s.%2$s() returns %3$s, but %4$s declares additional component method(s): %5$s. In "
209               + "order to provide type-safe access to these methods, override %2$s() to return "
210               + "%4$s",
211           componentBuilder.getQualifiedName(),
212           buildMethod.getSimpleName(),
213           returnType,
214           component.getQualifiedName(),
215           Joiner.on(", ").join(additionalMethods));
216     }
217 
bindsInstanceNotAllowedOnBothSetterMethodAndParameter()218     public final String bindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
219       return process("@Component.Builder setter methods may not have @BindsInstance on both the "
220           + "method and its parameter; choose one or the other");
221     }
222 
inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter()223     public final String inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
224       return bindsInstanceNotAllowedOnBothSetterMethodAndParameter() + ". Inherited method: %s";
225     }
226   }
227 
228   private static final class BuilderMessages extends ComponentCreatorMessages {
BuilderMessages(Function<String, String> transformation)229     BuilderMessages(Function<String, String> transformation) {
230       super(transformation);
231     }
232 
233     @Override
missingFactoryMethod()234     public String missingFactoryMethod() {
235       return process(
236           "@Component.Builder types must have exactly one no-args method that "
237               + " returns the @Component type");
238     }
239 
240     @Override
multipleSettersForModuleOrDependencyType()241     public String multipleSettersForModuleOrDependencyType() {
242       return process(
243           "@Component.Builder types must not have more than one setter method per module or "
244               + "dependency, but %s is set by %s");
245     }
246 
247     @Override
extraSetters()248     public String extraSetters() {
249       return process(
250           "@Component.Builder has setters for modules or components that aren't required: %s");
251     }
252 
253     @Override
missingSetters()254     public String missingSetters() {
255       return process(
256           "@Component.Builder is missing setters for required modules or components: %s");
257     }
258 
259     @Override
twoFactoryMethods()260     public String twoFactoryMethods() {
261       return process(
262           "@Component.Builder types must have exactly one zero-arg method, and that"
263               + " method must return the @Component type. Already found: %s");
264     }
265 
266     @Override
inheritedTwoFactoryMethods()267     public String inheritedTwoFactoryMethods() {
268       return process(
269           "@Component.Builder types must have exactly one zero-arg method, and that"
270               + " method must return the @Component type. Found %s and %s");
271     }
272 
273     @Override
factoryMethodMustReturnComponentType()274     public String factoryMethodMustReturnComponentType() {
275       return process(
276           "@Component.Builder methods that have no arguments must return the @Component type or a "
277               + "supertype of the @Component");
278     }
279 
280     @Override
factoryMethodMayNotBeAnnotatedWithBindsInstance()281     public String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
282       return process(
283           "@Component.Builder no-arg build methods may not be annotated with @BindsInstance");
284     }
285 
286     @Override
nonBindsInstanceParametersMayNotBePrimitives()287     public String nonBindsInstanceParametersMayNotBePrimitives() {
288       return process(
289           "@Component.Builder methods that are not annotated with @BindsInstance "
290               + "must take either a module or a component dependency, not a primitive");
291     }
292   }
293 
294   private static final class FactoryMessages extends ComponentCreatorMessages {
FactoryMessages(Function<String, String> transformation)295     FactoryMessages(Function<String, String> transformation) {
296       super(transformation.andThen(FACTORY));
297     }
298 
299     @Override
missingFactoryMethod()300     public String missingFactoryMethod() {
301       return process(
302           "@Component.Factory types must have exactly one method that "
303               + "returns the @Component type");
304     }
305 
306     @Override
multipleSettersForModuleOrDependencyType()307     public String multipleSettersForModuleOrDependencyType() {
308       return process(
309           "@Component.Factory methods must not have more than one parameter per module or "
310               + "dependency, but %s is set by %s");
311     }
312 
313     @Override
extraSetters()314     public String extraSetters() {
315       return process(
316           "@Component.Factory method has parameters for modules or components that aren't "
317               + "required: %s");
318     }
319 
320     @Override
missingSetters()321     public String missingSetters() {
322       return process(
323           "@Component.Factory method is missing parameters for required modules or components: %s");
324     }
325 
326     @Override
twoFactoryMethods()327     public String twoFactoryMethods() {
328       return process(
329           "@Component.Factory types must have exactly one abstract method. Already found: %s");
330     }
331 
332     @Override
inheritedTwoFactoryMethods()333     public String inheritedTwoFactoryMethods() {
334       return twoFactoryMethods();
335     }
336 
337     @Override
factoryMethodMustReturnComponentType()338     public String factoryMethodMustReturnComponentType() {
339       return process(
340           "@Component.Factory abstract methods must return the @Component type or a "
341               + "supertype of the @Component");
342     }
343 
344     @Override
factoryMethodMayNotBeAnnotatedWithBindsInstance()345     public String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
346       return process("@Component.Factory method may not be annotated with @BindsInstance");
347     }
348 
349     @Override
nonBindsInstanceParametersMayNotBePrimitives()350     public String nonBindsInstanceParametersMayNotBePrimitives() {
351       return process(
352           "@Component.Factory method parameters that are not annotated with @BindsInstance "
353               + "must be either a module or a component dependency, not a primitive");
354     }
355   }
356 
ErrorMessages()357   private ErrorMessages() {}
358 }
359