• 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.compat.XConverters.toJavac;
20 import static dagger.spi.model.BindingKind.MEMBERS_INJECTOR;
21 
22 import androidx.room.compiler.processing.XType;
23 import com.google.auto.value.AutoValue;
24 import com.google.common.base.CaseFormat;
25 import com.squareup.javapoet.ClassName;
26 import com.squareup.javapoet.ParameterizedTypeName;
27 import com.squareup.javapoet.TypeName;
28 import java.util.Optional;
29 import javax.lang.model.element.Element;
30 import javax.lang.model.element.ElementVisitor;
31 import javax.lang.model.element.ExecutableElement;
32 import javax.lang.model.element.TypeElement;
33 import javax.lang.model.element.VariableElement;
34 import javax.lang.model.util.ElementKindVisitor8;
35 
36 /**
37  * A value object that represents a field in the generated Component class.
38  *
39  * <p>Examples:
40  *
41  * <ul>
42  *   <li>{@code Provider<String>}
43  *   <li>{@code Producer<Widget>}
44  *   <li>{@code Provider<Map<SomeMapKey, MapValue>>}.
45  * </ul>
46  */
47 @AutoValue
48 public abstract class FrameworkField {
49 
50   /**
51    * Creates a framework field.
52    *
53    * @param frameworkClassName the name of the framework class (e.g., {@link javax.inject.Provider})
54    * @param valueTypeName the name of the type parameter of the framework class (e.g., {@code Foo}
55    *     for {@code Provider<Foo>}
56    * @param fieldName the name of the field
57    */
create( ClassName frameworkClassName, TypeName valueTypeName, String fieldName)58   public static FrameworkField create(
59       ClassName frameworkClassName, TypeName valueTypeName, String fieldName) {
60     String suffix = frameworkClassName.simpleName();
61     return new AutoValue_FrameworkField(
62         ParameterizedTypeName.get(frameworkClassName, valueTypeName),
63         fieldName.endsWith(suffix) ? fieldName : fieldName + suffix);
64   }
65 
66   /**
67    * A framework field for a {@link ContributionBinding}.
68    *
69    * @param frameworkClass if present, the field will use this framework class instead of the normal
70    *     one for the binding's type.
71    */
forBinding( ContributionBinding binding, Optional<ClassName> frameworkClassName)72   public static FrameworkField forBinding(
73       ContributionBinding binding, Optional<ClassName> frameworkClassName) {
74     return create(
75         frameworkClassName.orElse(binding.frameworkType().frameworkClassName()),
76         fieldValueType(binding).getTypeName(),
77         frameworkFieldName(binding));
78   }
79 
fieldValueType(ContributionBinding binding)80   private static XType fieldValueType(ContributionBinding binding) {
81     return binding.contributionType().isMultibinding()
82         ? binding.contributedType()
83         : binding.key().type().xprocessing();
84   }
85 
frameworkFieldName(ContributionBinding binding)86   private static String frameworkFieldName(ContributionBinding binding) {
87     if (binding.bindingElement().isPresent()) {
88       String name = BINDING_ELEMENT_NAME.visit(toJavac(binding.bindingElement().get()), binding);
89       return binding.kind().equals(MEMBERS_INJECTOR) ? name + "MembersInjector" : name;
90     }
91     return KeyVariableNamer.name(binding.key());
92   }
93 
94   private static final ElementVisitor<String, Binding> BINDING_ELEMENT_NAME =
95       new ElementKindVisitor8<String, Binding>() {
96 
97         @Override
98         protected String defaultAction(Element e, Binding p) {
99           throw new IllegalArgumentException("Unexpected binding " + p);
100         }
101 
102         @Override
103         public String visitExecutableAsConstructor(ExecutableElement e, Binding p) {
104           return visit(e.getEnclosingElement(), p);
105         }
106 
107         @Override
108         public String visitExecutableAsMethod(ExecutableElement e, Binding p) {
109           return e.getSimpleName().toString();
110         }
111 
112         @Override
113         public String visitType(TypeElement e, Binding p) {
114           return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, e.getSimpleName().toString());
115         }
116 
117         @Override
118         public String visitVariableAsParameter(VariableElement e, Binding p) {
119           return e.getSimpleName().toString();
120         }
121       };
122 
type()123   public abstract ParameterizedTypeName type();
124 
name()125   public abstract String name();
126 }
127