1 /* 2 * Copyright (C) 2016 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.base; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 21 import com.google.auto.common.MoreElements; 22 import com.google.auto.common.MoreTypes; 23 import com.google.auto.value.AutoValue; 24 import com.google.common.base.Equivalence; 25 import com.squareup.javapoet.ClassName; 26 import com.squareup.javapoet.CodeBlock; 27 import com.squareup.javapoet.ParameterizedTypeName; 28 import com.squareup.javapoet.TypeName; 29 import dagger.model.Key; 30 import java.util.Optional; 31 import javax.lang.model.element.Name; 32 import javax.lang.model.type.DeclaredType; 33 import javax.lang.model.type.TypeMirror; 34 import javax.lang.model.type.TypeVisitor; 35 import javax.lang.model.util.SimpleTypeVisitor8; 36 37 /** 38 * Information about an {@code Optional} {@link TypeMirror}. 39 * 40 * <p>{@link com.google.common.base.Optional} and {@link java.util.Optional} are supported. 41 */ 42 @AutoValue 43 public abstract class OptionalType { 44 45 /** A variant of {@code Optional}. */ 46 public enum OptionalKind { 47 /** {@link com.google.common.base.Optional}. */ 48 GUAVA_OPTIONAL(com.google.common.base.Optional.class, "absent"), 49 50 /** {@link java.util.Optional}. */ 51 JDK_OPTIONAL(java.util.Optional.class, "empty"), 52 ; 53 54 private final Class<?> clazz; 55 private final String absentFactoryMethodName; 56 OptionalKind(Class<?> clazz, String absentFactoryMethodName)57 OptionalKind(Class<?> clazz, String absentFactoryMethodName) { 58 this.clazz = clazz; 59 this.absentFactoryMethodName = absentFactoryMethodName; 60 } 61 62 /** Returns {@code valueType} wrapped in the correct class. */ of(TypeName valueType)63 public ParameterizedTypeName of(TypeName valueType) { 64 return ParameterizedTypeName.get(ClassName.get(clazz), valueType); 65 } 66 67 /** Returns an expression for the absent/empty value. */ absentValueExpression()68 public CodeBlock absentValueExpression() { 69 return CodeBlock.of("$T.$L()", clazz, absentFactoryMethodName); 70 } 71 72 /** 73 * Returns an expression for the absent/empty value, parameterized with {@link #valueType()}. 74 */ parameterizedAbsentValueExpression(OptionalType optionalType)75 public CodeBlock parameterizedAbsentValueExpression(OptionalType optionalType) { 76 return CodeBlock.of("$T.<$T>$L()", clazz, optionalType.valueType(), absentFactoryMethodName); 77 } 78 79 /** Returns an expression for the present {@code value}. */ presentExpression(CodeBlock value)80 public CodeBlock presentExpression(CodeBlock value) { 81 return CodeBlock.of("$T.of($L)", clazz, value); 82 } 83 84 /** 85 * Returns an expression for the present {@code value}, returning {@code Optional<Object>} no 86 * matter what type the value is. 87 */ presentObjectExpression(CodeBlock value)88 public CodeBlock presentObjectExpression(CodeBlock value) { 89 return CodeBlock.of("$T.<$T>of($L)", clazz, Object.class, value); 90 } 91 } 92 93 private static final TypeVisitor<Optional<OptionalKind>, Void> OPTIONAL_KIND = 94 new SimpleTypeVisitor8<Optional<OptionalKind>, Void>(Optional.empty()) { 95 @Override 96 public Optional<OptionalKind> visitDeclared(DeclaredType t, Void p) { 97 for (OptionalKind optionalKind : OptionalKind.values()) { 98 Name qualifiedName = MoreElements.asType(t.asElement()).getQualifiedName(); 99 if (qualifiedName.contentEquals(optionalKind.clazz.getCanonicalName())) { 100 return Optional.of(optionalKind); 101 } 102 } 103 return Optional.empty(); 104 } 105 }; 106 107 /** 108 * The optional type itself, wrapped using {@link MoreTypes#equivalence()}. 109 * 110 * @deprecated Use {@link #declaredOptionalType()} instead. 111 */ 112 @Deprecated wrappedDeclaredOptionalType()113 protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredOptionalType(); 114 115 /** The optional type itself. */ 116 @SuppressWarnings("deprecation") declaredOptionalType()117 private DeclaredType declaredOptionalType() { 118 return wrappedDeclaredOptionalType().get(); 119 } 120 121 /** Which {@code Optional} type is used. */ kind()122 public OptionalKind kind() { 123 return declaredOptionalType().accept(OPTIONAL_KIND, null).get(); 124 } 125 126 /** The value type. */ valueType()127 public TypeMirror valueType() { 128 return declaredOptionalType().getTypeArguments().get(0); 129 } 130 131 /** Returns {@code true} if {@code type} is an {@code Optional} type. */ isOptional(TypeMirror type)132 private static boolean isOptional(TypeMirror type) { 133 return type.accept(OPTIONAL_KIND, null).isPresent(); 134 } 135 136 /** Returns {@code true} if {@code key.type()} is an {@code Optional} type. */ isOptional(Key key)137 public static boolean isOptional(Key key) { 138 return isOptional(key.type()); 139 } 140 141 /** 142 * Returns a {@link OptionalType} for {@code type}. 143 * 144 * @throws IllegalArgumentException if {@code type} is not an {@code Optional} type 145 */ from(TypeMirror type)146 public static OptionalType from(TypeMirror type) { 147 checkArgument(isOptional(type), "%s must be an Optional", type); 148 return new AutoValue_OptionalType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type))); 149 } 150 151 /** 152 * Returns a {@link OptionalType} for {@code key}'s {@link Key#type() type}. 153 * 154 * @throws IllegalArgumentException if {@code key.type()} is not an {@code Optional} type 155 */ from(Key key)156 public static OptionalType from(Key key) { 157 return from(key.type()); 158 } 159 } 160