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