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