• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.isMethodParameter;
20 import static androidx.room.compiler.processing.XElementKt.isTypeElement;
21 import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
22 import static dagger.internal.codegen.base.ElementFormatter.elementToString;
23 import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
24 import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
25 import static dagger.internal.codegen.xprocessing.XElements.isExecutable;
26 
27 import androidx.room.compiler.processing.XElement;
28 import androidx.room.compiler.processing.XTypeElement;
29 import com.google.common.collect.ImmutableList;
30 import dagger.internal.codegen.base.Formatter;
31 import dagger.internal.codegen.xprocessing.XTypes;
32 import javax.inject.Inject;
33 
34 /**
35  * Formats a {@link BindingDeclaration} into a {@link String} suitable for use in error messages.
36  */
37 public final class BindingDeclarationFormatter extends Formatter<BindingDeclaration> {
38   private final MethodSignatureFormatter methodSignatureFormatter;
39 
40   @Inject
BindingDeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter)41   BindingDeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter) {
42     this.methodSignatureFormatter = methodSignatureFormatter;
43   }
44 
45   /**
46    * Returns {@code true} for declarations that this formatter can format. Specifically bindings
47    * from subcomponent declarations or those with {@linkplain BindingDeclaration#bindingElement()
48    * binding elements} that are methods, constructors, or types.
49    */
canFormat(BindingDeclaration bindingDeclaration)50   public boolean canFormat(BindingDeclaration bindingDeclaration) {
51     if (bindingDeclaration instanceof SubcomponentDeclaration) {
52       return true;
53     }
54     if (bindingDeclaration.bindingElement().isPresent()) {
55       XElement bindingElement = bindingDeclaration.bindingElement().get();
56       return isMethodParameter(bindingElement)
57           || isTypeElement(bindingElement)
58           || isExecutable(bindingElement);
59     }
60     // TODO(dpb): validate whether what this is doing is correct
61     return false;
62   }
63 
64   @Override
format(BindingDeclaration bindingDeclaration)65   public String format(BindingDeclaration bindingDeclaration) {
66     if (bindingDeclaration instanceof SubcomponentDeclaration) {
67       return formatSubcomponentDeclaration((SubcomponentDeclaration) bindingDeclaration);
68     }
69 
70     if (bindingDeclaration.bindingElement().isPresent()) {
71       XElement bindingElement = bindingDeclaration.bindingElement().get();
72       if (isMethodParameter(bindingElement)) {
73         return elementToString(bindingElement);
74       } else if (isTypeElement(bindingElement)) {
75         return stripCommonTypePrefixes(
76             XTypes.toStableString(asTypeElement(bindingElement).getType()));
77       } else if (isExecutable(bindingElement)) {
78         return methodSignatureFormatter.format(
79             asExecutable(bindingElement),
80             bindingDeclaration.contributingModule().map(XTypeElement::getType));
81       }
82       throw new IllegalArgumentException("Formatting unsupported for element: " + bindingElement);
83     }
84 
85     return String.format(
86         "Dagger-generated binding for %s",
87         stripCommonTypePrefixes(bindingDeclaration.key().toString()));
88   }
89 
formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration)90   private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
91     ImmutableList<XTypeElement> moduleSubcomponents =
92         subcomponentDeclaration.moduleAnnotation().subcomponents();
93     int index = moduleSubcomponents.indexOf(subcomponentDeclaration.subcomponentType());
94     StringBuilder annotationValue = new StringBuilder();
95     if (moduleSubcomponents.size() != 1) {
96       annotationValue.append("{");
97     }
98     annotationValue.append(
99         formatArgumentInList(
100             index,
101             moduleSubcomponents.size(),
102             subcomponentDeclaration.subcomponentType().getQualifiedName() + ".class"));
103     if (moduleSubcomponents.size() != 1) {
104       annotationValue.append("}");
105     }
106 
107     return String.format(
108         "@%s(subcomponents = %s) for %s",
109         subcomponentDeclaration.moduleAnnotation().simpleName(),
110         annotationValue,
111         subcomponentDeclaration.contributingModule().get());
112   }
113 }
114