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