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