blob: 4e2307a6cb89beeb61985230431f1a265ca499ed [file] [log] [blame]
/*
* Copyright (C) 2015 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dagger.internal.codegen.base;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.common.base.Equivalence;
import dagger.model.Key;
import java.util.Map;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
/**
* Information about a {@link Map} {@link TypeMirror}.
*/
@AutoValue
public abstract class MapType {
/**
* The map type itself, wrapped using {@link MoreTypes#equivalence()}. Use
* {@link #declaredMapType()} instead.
*/
protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredMapType();
/**
* The map type itself.
*/
private DeclaredType declaredMapType() {
return wrappedDeclaredMapType().get();
}
/**
* {@code true} if the map type is the raw {@link Map} type.
*/
public boolean isRawType() {
return declaredMapType().getTypeArguments().isEmpty();
}
/**
* The map key type.
*
* @throws IllegalStateException if {@link #isRawType()} is true.
*/
public TypeMirror keyType() {
checkState(!isRawType());
return declaredMapType().getTypeArguments().get(0);
}
/**
* The map value type.
*
* @throws IllegalStateException if {@link #isRawType()} is true.
*/
public TypeMirror valueType() {
checkState(!isRawType());
return declaredMapType().getTypeArguments().get(1);
}
/**
* {@code true} if {@link #valueType()} is a {@code clazz}.
*
* @throws IllegalStateException if {@link #isRawType()} is true.
*/
public boolean valuesAreTypeOf(Class<?> clazz) {
return MoreTypes.isType(valueType()) && MoreTypes.isTypeOf(clazz, valueType());
}
/**
* Returns {@code true} if the {@linkplain #valueType() value type} of the {@link Map} is a
* {@linkplain FrameworkTypes#isFrameworkType(TypeMirror) framework type}.
*/
public boolean valuesAreFrameworkType() {
return FrameworkTypes.isFrameworkType(valueType());
}
/**
* {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code
* Producer<V>}.
*
* @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
* framework type
*/
public TypeMirror unwrappedFrameworkValueType() {
checkState(
valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", declaredMapType());
return uncheckedUnwrappedValueType();
}
/**
* {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}.
*
* @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
* {@code WrappingClass<V>}
* @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
* parameter
*/
public TypeMirror unwrappedValueType(Class<?> wrappingClass) {
checkArgument(
wrappingClass.getTypeParameters().length == 1,
"%s must have exactly one type parameter",
wrappingClass);
checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this);
return uncheckedUnwrappedValueType();
}
private TypeMirror uncheckedUnwrappedValueType() {
return MoreTypes.asDeclared(valueType()).getTypeArguments().get(0);
}
/**
* {@code true} if {@code type} is a {@link Map} type.
*/
public static boolean isMap(TypeMirror type) {
return MoreTypes.isType(type) && MoreTypes.isTypeOf(Map.class, type);
}
/**
* {@code true} if {@code key.type()} is a {@link Map} type.
*/
public static boolean isMap(Key key) {
return isMap(key.type());
}
/**
* Returns a {@link MapType} for {@code type}.
*
* @throws IllegalArgumentException if {@code type} is not a {@link Map} type
*/
public static MapType from(TypeMirror type) {
checkArgument(isMap(type), "%s is not a Map", type);
return new AutoValue_MapType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
}
/**
* Returns a {@link MapType} for {@code key}'s {@link Key#type() type}.
*
* @throws IllegalArgumentException if {@code key.type()} is not a {@link Map} type
*/
public static MapType from(Key key) {
return from(key.type());
}
}