1 /* 2 * Copyright (C) 2015 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 import static com.google.common.base.Preconditions.checkState; 21 import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType; 22 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf; 23 24 import androidx.room.compiler.processing.XType; 25 import com.google.auto.value.AutoValue; 26 import com.squareup.javapoet.ClassName; 27 import com.squareup.javapoet.TypeName; 28 import dagger.internal.codegen.javapoet.TypeNames; 29 import dagger.spi.model.Key; 30 import javax.lang.model.type.TypeMirror; 31 32 /** Information about a {@link java.util.Map} {@link TypeMirror}. */ 33 @AutoValue 34 public abstract class MapType { 35 private XType type; 36 37 /** The map type itself. */ typeName()38 abstract TypeName typeName(); 39 40 /** The map type itself. */ type()41 private XType type() { 42 return type; 43 } 44 45 /** {@code true} if the map type is the raw {@link java.util.Map} type. */ isRawType()46 public boolean isRawType() { 47 return type().getTypeArguments().isEmpty(); 48 } 49 50 /** 51 * The map key type. 52 * 53 * @throws IllegalStateException if {@link #isRawType()} is true. 54 */ keyType()55 public XType keyType() { 56 checkState(!isRawType()); 57 return type().getTypeArguments().get(0); 58 } 59 60 /** 61 * The map value type. 62 * 63 * @throws IllegalStateException if {@link #isRawType()} is true. 64 */ valueType()65 public XType valueType() { 66 checkState(!isRawType()); 67 return type().getTypeArguments().get(1); 68 } 69 70 /** Returns {@code true} if the raw type of {@link #valueType()} is {@code className}. */ valuesAreTypeOf(ClassName className)71 public boolean valuesAreTypeOf(ClassName className) { 72 return !isRawType() && isTypeOf(valueType(), className); 73 } 74 75 /** Returns {@code true} if the raw type of {@link #valueType()} is a framework type. */ valuesAreFrameworkType()76 public boolean valuesAreFrameworkType() { 77 return FrameworkTypes.isFrameworkType(valueType()); 78 } 79 80 /** 81 * {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code 82 * Producer<V>}. 83 * 84 * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a 85 * framework type 86 */ unwrappedFrameworkValueType()87 public XType unwrappedFrameworkValueType() { 88 checkState(valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", type()); 89 return uncheckedUnwrappedValueType(); 90 } 91 92 /** 93 * {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}. 94 * 95 * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a 96 * {@code WrappingClass<V>} 97 */ 98 // TODO(b/202033221): Consider using stricter input type, e.g. FrameworkType. unwrappedValueType(ClassName wrappingClass)99 public XType unwrappedValueType(ClassName wrappingClass) { 100 checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this); 101 return uncheckedUnwrappedValueType(); 102 } 103 uncheckedUnwrappedValueType()104 private XType uncheckedUnwrappedValueType() { 105 return unwrapType(valueType()); 106 } 107 108 /** {@code true} if {@code type} is a {@link java.util.Map} type. */ isMap(XType type)109 public static boolean isMap(XType type) { 110 return isTypeOf(type, TypeNames.MAP); 111 } 112 113 /** {@code true} if {@code key.type()} is a {@link java.util.Map} type. */ isMap(Key key)114 public static boolean isMap(Key key) { 115 return isMap(key.type().xprocessing()); 116 } 117 118 /** 119 * Returns a {@link MapType} for {@code type}. 120 * 121 * @throws IllegalArgumentException if {@code type} is not a {@link java.util.Map} type 122 */ from(XType type)123 public static MapType from(XType type) { 124 checkArgument(isMap(type), "%s is not a Map", type); 125 MapType mapType = new AutoValue_MapType(type.getTypeName()); 126 mapType.type = type; 127 return mapType; 128 } 129 130 /** 131 * Returns a {@link MapType} for {@code key}'s {@link Key#type() type}. 132 * 133 * @throws IllegalArgumentException if {@code key.type()} is not a {@link java.util.Map} type 134 */ from(Key key)135 public static MapType from(Key key) { 136 return from(key.type().xprocessing()); 137 } 138 } 139