• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google, Inc.
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 package dagger.internal.codegen;
17 
18 import com.google.auto.common.MoreTypes;
19 import com.google.auto.value.AutoValue;
20 import com.google.common.base.CaseFormat;
21 import com.google.common.collect.ImmutableSet;
22 import dagger.MembersInjector;
23 import dagger.internal.codegen.writer.ClassName;
24 import dagger.internal.codegen.writer.ParameterizedTypeName;
25 import dagger.internal.codegen.writer.TypeNames;
26 import javax.lang.model.element.ElementVisitor;
27 import javax.lang.model.element.ExecutableElement;
28 import javax.lang.model.element.TypeElement;
29 import javax.lang.model.type.TypeMirror;
30 import javax.lang.model.util.ElementKindVisitor6;
31 
32 import static com.google.common.collect.Iterables.any;
33 import static com.google.common.collect.Iterables.getOnlyElement;
34 import static dagger.internal.codegen.ContributionBinding.contributionTypeFor;
35 
36 /**
37  * A value object that represents a field used by Dagger-generated code.
38  *
39  * @author Jesse Beder
40  * @since 2.0
41  */
42 @AutoValue
43 abstract class FrameworkField {
44   // TODO(gak): reexamine the this class and how consistently we're using it and its creation
45   // methods
createWithTypeFromKey( Class<?> frameworkClass, BindingKey bindingKey, String name)46   static FrameworkField createWithTypeFromKey(
47       Class<?> frameworkClass, BindingKey bindingKey, String name) {
48     String suffix = frameworkClass.getSimpleName();
49     ParameterizedTypeName frameworkType = ParameterizedTypeName.create(
50         ClassName.fromClass(frameworkClass),
51         TypeNames.forTypeMirror(bindingKey.key().type()));
52     return new AutoValue_FrameworkField(frameworkClass, frameworkType, bindingKey,
53         name.endsWith(suffix) ? name : name + suffix);
54   }
55 
createForMapBindingContribution( Class<?> frameworkClass, BindingKey bindingKey, String name)56   private static FrameworkField createForMapBindingContribution(
57       Class<?> frameworkClass, BindingKey bindingKey, String name) {
58     TypeMirror mapValueType =
59         MoreTypes.asDeclared(bindingKey.key().type()).getTypeArguments().get(1);
60     return new AutoValue_FrameworkField(frameworkClass,
61         (ParameterizedTypeName) TypeNames.forTypeMirror(mapValueType),
62         bindingKey,
63         name);
64   }
65 
createForSyntheticContributionBinding( int contributionNumber, ContributionBinding contributionBinding)66   static FrameworkField createForSyntheticContributionBinding(
67       int contributionNumber, ContributionBinding contributionBinding) {
68     switch (contributionBinding.contributionType()) {
69       case MAP:
70         return createForMapBindingContribution(
71             contributionBinding.frameworkClass(),
72             contributionBinding.bindingKey(),
73             KeyVariableNamer.INSTANCE.apply(contributionBinding.key())
74                 + "Contribution"
75                 + contributionNumber);
76 
77       case SET:
78       case UNIQUE:
79         return createWithTypeFromKey(
80             contributionBinding.frameworkClass(),
81             contributionBinding.bindingKey(),
82             KeyVariableNamer.INSTANCE.apply(contributionBinding.key())
83                 + "Contribution"
84                 + contributionNumber);
85       default:
86         throw new AssertionError();
87     }
88   }
89 
createForResolvedBindings(ResolvedBindings resolvedBindings)90   static FrameworkField createForResolvedBindings(ResolvedBindings resolvedBindings) {
91     BindingKey bindingKey = resolvedBindings.bindingKey();
92     switch (bindingKey.kind()) {
93       case CONTRIBUTION:
94         ImmutableSet<ContributionBinding> contributionBindings =
95             resolvedBindings.contributionBindings();
96         switch (contributionTypeFor(contributionBindings)) {
97           case SET:
98           case MAP:
99             return createWithTypeFromKey(
100                 FrameworkField.frameworkClassForResolvedBindings(resolvedBindings),
101                 bindingKey,
102                 KeyVariableNamer.INSTANCE.apply(bindingKey.key()));
103           case UNIQUE:
104             ContributionBinding binding = getOnlyElement(contributionBindings);
105             return createWithTypeFromKey(
106                 FrameworkField.frameworkClassForResolvedBindings(resolvedBindings),
107                 bindingKey,
108                 BINDING_ELEMENT_NAME.visit(binding.bindingElement()));
109           default:
110             throw new AssertionError();
111         }
112       case MEMBERS_INJECTION:
113         return createWithTypeFromKey(
114             MembersInjector.class,
115             bindingKey,
116             CaseFormat.UPPER_CAMEL.to(
117                 CaseFormat.LOWER_CAMEL,
118                 resolvedBindings
119                     .membersInjectionBinding()
120                     .get()
121                     .bindingElement()
122                     .getSimpleName()
123                     .toString()));
124       default:
125         throw new AssertionError();
126     }
127   }
128 
129   private static final ElementVisitor<String, Void> BINDING_ELEMENT_NAME =
130       new ElementKindVisitor6<String, Void>() {
131         @Override
132         public String visitExecutableAsConstructor(ExecutableElement e, Void p) {
133           return visit(e.getEnclosingElement());
134         }
135 
136         @Override
137         public String visitExecutableAsMethod(ExecutableElement e, Void p) {
138           return e.getSimpleName().toString();
139         }
140 
141         @Override
142         public String visitType(TypeElement e, Void p) {
143           return CaseFormat.UPPER_CAMEL.to(
144               CaseFormat.LOWER_CAMEL, e.getSimpleName().toString());
145         }
146       };
147 
frameworkClassForResolvedBindings(ResolvedBindings resolvedBindings)148   static Class<?> frameworkClassForResolvedBindings(ResolvedBindings resolvedBindings) {
149     switch (resolvedBindings.bindingKey().kind()) {
150       case CONTRIBUTION:
151         return any(resolvedBindings.contributionBindings(), Binding.Type.PRODUCTION)
152             ? Binding.Type.PRODUCTION.frameworkClass()
153             : Binding.Type.PROVISION.frameworkClass();
154       case MEMBERS_INJECTION:
155         return MembersInjector.class;
156       default:
157         throw new AssertionError();
158     }
159   }
160 
frameworkClass()161   abstract Class<?> frameworkClass();
frameworkType()162   abstract ParameterizedTypeName frameworkType();
bindingKey()163   abstract BindingKey bindingKey();
name()164   abstract String name();
165 }
166