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 androidx.room.compiler.processing.XElementKt.isMethod; 20 import static androidx.room.compiler.processing.XElementKt.isTypeElement; 21 import static androidx.room.compiler.processing.XElementKt.isVariableElement; 22 import static dagger.internal.codegen.base.ElementFormatter.elementToString; 23 import static dagger.internal.codegen.base.RequestKinds.requestType; 24 25 import androidx.room.compiler.processing.XElement; 26 import androidx.room.compiler.processing.XProcessingEnv; 27 import com.google.errorprone.annotations.CanIgnoreReturnValue; 28 import dagger.internal.codegen.base.Formatter; 29 import dagger.internal.codegen.model.DaggerAnnotation; 30 import dagger.internal.codegen.model.DependencyRequest; 31 import dagger.internal.codegen.xprocessing.XTypes; 32 import java.util.Optional; 33 import javax.inject.Inject; 34 35 /** 36 * Formats a {@link DependencyRequest} into a {@link String} suitable for an error message listing a 37 * chain of dependencies. 38 * 39 * <dl> 40 * <dt>For component provision methods 41 * <dd>{@code @Qualifier SomeType is provided at\n ComponentType.method()} 42 * <dt>For component injection methods 43 * <dd>{@code SomeType is injected at\n ComponentType.method(foo)} 44 * <dt>For parameters to {@code @Provides}, {@code @Produces}, or {@code @Inject} methods: 45 * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType.method([…, ]param[, …])} 46 * <dt>For parameters to {@link Inject @Inject} constructors: 47 * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType([…, ]param[, …])} 48 * <dt>For {@link Inject @Inject} fields: 49 * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType.field} 50 * </dl> 51 */ 52 public final class DependencyRequestFormatter extends Formatter<DependencyRequest> { 53 54 private final XProcessingEnv processingEnv; 55 56 @Inject DependencyRequestFormatter(XProcessingEnv processingEnv)57 DependencyRequestFormatter(XProcessingEnv processingEnv) { 58 this.processingEnv = processingEnv; 59 } 60 61 @Override format(DependencyRequest request)62 public String format(DependencyRequest request) { 63 if (!request.requestElement().isPresent()) { 64 return ""; 65 } 66 XElement requestElement = request.requestElement().get().xprocessing(); 67 if (isMethod(requestElement)) { 68 return INDENT 69 + request.key() 70 + " is " 71 + componentMethodRequestVerb(request) 72 + " at\n" 73 + DOUBLE_INDENT 74 + elementToString(requestElement); 75 } else if (isVariableElement(requestElement)) { 76 return INDENT 77 + formatQualifier(request.key().qualifier()) 78 + XTypes.toStableString( 79 requestType(request.kind(), request.key().type().xprocessing(), processingEnv)) 80 + " is injected at\n" 81 + DOUBLE_INDENT 82 + elementToString(requestElement); 83 } else if (isTypeElement(requestElement)) { 84 return ""; // types by themselves provide no useful information. 85 } else { 86 throw new IllegalStateException("Invalid request element " + requestElement); 87 } 88 } 89 90 /** 91 * Appends a newline and the formatted dependency request unless {@link 92 * #format(DependencyRequest)} returns the empty string. 93 */ 94 @CanIgnoreReturnValue appendFormatLine( StringBuilder builder, DependencyRequest dependencyRequest)95 public StringBuilder appendFormatLine( 96 StringBuilder builder, DependencyRequest dependencyRequest) { 97 String formatted = format(dependencyRequest); 98 if (!formatted.isEmpty()) { 99 builder.append('\n').append(formatted); 100 } 101 return builder; 102 } 103 formatQualifier(Optional<DaggerAnnotation> maybeQualifier)104 private String formatQualifier(Optional<DaggerAnnotation> maybeQualifier) { 105 return maybeQualifier.map(qualifier -> qualifier + " ").orElse(""); 106 } 107 108 /** 109 * Returns the verb for a component method dependency request. Returns "produced", "provided", or 110 * "injected", depending on the kind of request. 111 */ componentMethodRequestVerb(DependencyRequest request)112 private String componentMethodRequestVerb(DependencyRequest request) { 113 switch (request.kind()) { 114 case FUTURE: 115 case PRODUCER: 116 case INSTANCE: 117 case LAZY: 118 case PROVIDER: 119 case PROVIDER_OF_LAZY: 120 return "requested"; 121 122 case MEMBERS_INJECTION: 123 return "injected"; 124 125 case PRODUCED: 126 break; 127 } 128 throw new AssertionError("illegal request kind for method: " + request); 129 } 130 } 131