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