• 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 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