1 /* 2 * Copyright (C) 2013 Google, Inc. 3 * Copyright (C) 2013 Square, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package dagger.internal.codegen; 18 19 import com.google.auto.common.MoreTypes; 20 import com.google.common.base.Equivalence; 21 import com.google.common.base.Equivalence.Wrapper; 22 import com.google.common.base.Optional; 23 import com.google.common.collect.ImmutableSet; 24 import dagger.producers.Produced; 25 import java.util.Map; 26 import java.util.Set; 27 import javax.inject.Provider; 28 import javax.lang.model.element.Element; 29 import javax.lang.model.element.ExecutableElement; 30 import javax.lang.model.element.Modifier; 31 import javax.lang.model.element.TypeElement; 32 import javax.lang.model.type.DeclaredType; 33 import javax.lang.model.type.TypeMirror; 34 import javax.lang.model.util.Elements; 35 36 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods; 37 import static com.google.auto.common.MoreTypes.asDeclared; 38 import static com.google.common.base.Preconditions.checkState; 39 import static javax.lang.model.element.ElementKind.CONSTRUCTOR; 40 import static javax.lang.model.element.Modifier.ABSTRACT; 41 import static javax.lang.model.element.Modifier.PRIVATE; 42 import static javax.lang.model.element.Modifier.STATIC; 43 44 /** 45 * Utilities for handling types in annotation processors 46 */ 47 final class Util { 48 /** 49 * Returns the {@code V} type for a {@link Map} type like {@code Map<K, Provider<V>>} if the map 50 * includes such a construction 51 */ getProvidedValueTypeOfMap(DeclaredType mapType)52 public static TypeMirror getProvidedValueTypeOfMap(DeclaredType mapType) { 53 checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType); 54 return asDeclared(mapType.getTypeArguments().get(1)).getTypeArguments().get(0); 55 } 56 57 // TODO(cgruber): Consider an object that holds and exposes the various parts of a Map type. 58 /** 59 * returns the value type for a {@link Map} type like Map<K, V>}. 60 */ getValueTypeOfMap(DeclaredType mapType)61 public static TypeMirror getValueTypeOfMap(DeclaredType mapType) { 62 checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType); 63 return mapType.getTypeArguments().get(1); 64 } 65 66 /** 67 * Returns the key type for a {@link Map} type like Map<K, Provider<V>>} 68 */ getKeyTypeOfMap(DeclaredType mapType)69 public static TypeMirror getKeyTypeOfMap(DeclaredType mapType) { 70 checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType); 71 return mapType.getTypeArguments().get(0); 72 } 73 74 /** 75 * Returns true if {@code type} is a {@link Map} whose value type is not a {@link Provider}. 76 */ isMapWithNonProvidedValues(TypeMirror type)77 public static boolean isMapWithNonProvidedValues(TypeMirror type) { 78 return MoreTypes.isType(type) 79 && MoreTypes.isTypeOf(Map.class, type) 80 && !MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1)); 81 } 82 83 /** 84 * Returns true if {@code type} is a {@link Map} whose value type is a {@link Provider}. 85 */ isMapWithProvidedValues(TypeMirror type)86 public static boolean isMapWithProvidedValues(TypeMirror type) { 87 return MoreTypes.isType(type) 88 && MoreTypes.isTypeOf(Map.class, type) 89 && MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1)); 90 } 91 92 /** Returns true if {@code type} is a {@code Set<Produced<T>>}. */ isSetOfProduced(TypeMirror type)93 static boolean isSetOfProduced(TypeMirror type) { 94 return MoreTypes.isType(type) 95 && MoreTypes.isTypeOf(Set.class, type) 96 && MoreTypes.isTypeOf(Produced.class, MoreTypes.asDeclared(type).getTypeArguments().get(0)); 97 } 98 99 /** 100 * Wraps an {@link Optional} of a type in an {@code Optional} of a {@link Wrapper} for that type. 101 */ wrapOptionalInEquivalence( Equivalence<T> equivalence, Optional<T> optional)102 static <T> Optional<Equivalence.Wrapper<T>> wrapOptionalInEquivalence( 103 Equivalence<T> equivalence, Optional<T> optional) { 104 return optional.isPresent() 105 ? Optional.of(equivalence.wrap(optional.get())) 106 : Optional.<Equivalence.Wrapper<T>>absent(); 107 } 108 109 /** 110 * Unwraps an {@link Optional} of a {@link Wrapper} into an {@code Optional} of the underlying 111 * type. 112 */ unwrapOptionalEquivalence( Optional<Equivalence.Wrapper<T>> wrappedOptional)113 static <T> Optional<T> unwrapOptionalEquivalence( 114 Optional<Equivalence.Wrapper<T>> wrappedOptional) { 115 return wrappedOptional.isPresent() 116 ? Optional.of(wrappedOptional.get().get()) 117 : Optional.<T>absent(); 118 } 119 requiresEnclosingInstance(TypeElement typeElement)120 private static boolean requiresEnclosingInstance(TypeElement typeElement) { 121 switch (typeElement.getNestingKind()) { 122 case TOP_LEVEL: 123 return false; 124 case MEMBER: 125 return !typeElement.getModifiers().contains(STATIC); 126 case ANONYMOUS: 127 case LOCAL: 128 return true; 129 default: 130 throw new AssertionError("TypeElement cannot have nesting kind: " 131 + typeElement.getNestingKind()); 132 } 133 } 134 135 /** 136 * Returns true if and only if a component can instantiate new instances (typically of a module) 137 * rather than requiring that they be passed. 138 */ componentCanMakeNewInstances(TypeElement typeElement)139 static boolean componentCanMakeNewInstances(TypeElement typeElement) { 140 switch (typeElement.getKind()) { 141 case CLASS: 142 break; 143 case ENUM: 144 case ANNOTATION_TYPE: 145 case INTERFACE: 146 return false; 147 default: 148 throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind()); 149 } 150 151 if (typeElement.getModifiers().contains(ABSTRACT)) { 152 return false; 153 } 154 155 if (requiresEnclosingInstance(typeElement)) { 156 return false; 157 } 158 159 for (Element enclosed : typeElement.getEnclosedElements()) { 160 if (enclosed.getKind().equals(CONSTRUCTOR) 161 && ((ExecutableElement) enclosed).getParameters().isEmpty() 162 && !enclosed.getModifiers().contains(PRIVATE)) { 163 return true; 164 } 165 } 166 167 // TODO(gak): still need checks for visibility 168 169 return false; 170 } 171 getUnimplementedMethods( Elements elements, TypeElement type)172 static ImmutableSet<ExecutableElement> getUnimplementedMethods( 173 Elements elements, TypeElement type) { 174 ImmutableSet.Builder<ExecutableElement> unimplementedMethods = ImmutableSet.builder(); 175 Set<ExecutableElement> methods = getLocalAndInheritedMethods(type, elements); 176 for (ExecutableElement method : methods) { 177 if (method.getModifiers().contains(Modifier.ABSTRACT)) { 178 unimplementedMethods.add(method); 179 } 180 } 181 return unimplementedMethods.build(); 182 } 183 Util()184 private Util() {} 185 } 186