352 lines
12 KiB
Java
352 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2019 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.auto.common.AnnotationMirrors.getAnnotationValue;
|
|
import static com.google.auto.common.MoreElements.asType;
|
|
import static com.google.auto.common.MoreTypes.asTypeElements;
|
|
import static com.google.auto.common.MoreTypes.isTypeOf;
|
|
import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
|
|
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
|
|
import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_MODULE;
|
|
import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
|
|
|
|
import com.google.auto.value.AutoValue;
|
|
import com.google.auto.value.extension.memoized.Memoized;
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import com.squareup.javapoet.ClassName;
|
|
import dagger.Component;
|
|
import dagger.Subcomponent;
|
|
import dagger.producers.ProductionComponent;
|
|
import dagger.producers.ProductionSubcomponent;
|
|
import java.lang.annotation.Annotation;
|
|
import java.util.Collection;
|
|
import java.util.Optional;
|
|
import javax.lang.model.element.AnnotationMirror;
|
|
import javax.lang.model.element.AnnotationValue;
|
|
import javax.lang.model.element.TypeElement;
|
|
import javax.lang.model.type.TypeMirror;
|
|
|
|
/**
|
|
* A {@code @Component}, {@code @Subcomponent}, {@code @ProductionComponent}, or
|
|
* {@code @ProductionSubcomponent} annotation, or a {@code @Module} or {@code @ProducerModule}
|
|
* annotation that is being treated as a component annotation when validating full binding graphs
|
|
* for modules.
|
|
*/
|
|
public abstract class ComponentAnnotation {
|
|
/** The root component annotation types. */
|
|
private static final ImmutableSet<Class<? extends Annotation>> ROOT_COMPONENT_ANNOTATIONS =
|
|
ImmutableSet.of(Component.class, ProductionComponent.class);
|
|
|
|
/** The subcomponent annotation types. */
|
|
private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_ANNOTATIONS =
|
|
ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
|
|
|
|
// TODO(erichang): Move ComponentCreatorAnnotation into /base and use that here?
|
|
/** The component/subcomponent creator annotation types. */
|
|
private static final ImmutableSet<Class<? extends Annotation>> CREATOR_ANNOTATIONS =
|
|
ImmutableSet.of(
|
|
Component.Builder.class,
|
|
Component.Factory.class,
|
|
ProductionComponent.Builder.class,
|
|
ProductionComponent.Factory.class,
|
|
Subcomponent.Builder.class,
|
|
Subcomponent.Factory.class,
|
|
ProductionSubcomponent.Builder.class,
|
|
ProductionSubcomponent.Factory.class);
|
|
|
|
/** All component annotation types. */
|
|
private static final ImmutableSet<Class<? extends Annotation>> ALL_COMPONENT_ANNOTATIONS =
|
|
ImmutableSet.<Class<? extends Annotation>>builder()
|
|
.addAll(ROOT_COMPONENT_ANNOTATIONS)
|
|
.addAll(SUBCOMPONENT_ANNOTATIONS)
|
|
.build();
|
|
|
|
/** All component and creator annotation types. */
|
|
private static final ImmutableSet<Class<? extends Annotation>>
|
|
ALL_COMPONENT_AND_CREATOR_ANNOTATIONS = ImmutableSet.<Class<? extends Annotation>>builder()
|
|
.addAll(ALL_COMPONENT_ANNOTATIONS)
|
|
.addAll(CREATOR_ANNOTATIONS)
|
|
.build();
|
|
|
|
/** The annotation itself. */
|
|
public abstract AnnotationMirror annotation();
|
|
|
|
/** The simple name of the annotation type. */
|
|
public String simpleName() {
|
|
return MoreAnnotationMirrors.simpleName(annotation()).toString();
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the annotation is a {@code @Subcomponent} or
|
|
* {@code @ProductionSubcomponent}.
|
|
*/
|
|
public abstract boolean isSubcomponent();
|
|
|
|
/**
|
|
* Returns {@code true} if the annotation is a {@code @ProductionComponent},
|
|
* {@code @ProductionSubcomponent}, or {@code @ProducerModule}.
|
|
*/
|
|
public abstract boolean isProduction();
|
|
|
|
/**
|
|
* Returns {@code true} if the annotation is a real component annotation and not a module
|
|
* annotation.
|
|
*/
|
|
public abstract boolean isRealComponent();
|
|
|
|
/** The values listed as {@code dependencies}. */
|
|
public abstract ImmutableList<AnnotationValue> dependencyValues();
|
|
|
|
/** The types listed as {@code dependencies}. */
|
|
public ImmutableList<TypeMirror> dependencyTypes() {
|
|
return dependencyValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
|
|
}
|
|
|
|
/**
|
|
* The types listed as {@code dependencies}.
|
|
*
|
|
* @throws IllegalArgumentException if any of {@link #dependencyTypes()} are error types
|
|
*/
|
|
public ImmutableList<TypeElement> dependencies() {
|
|
return asTypeElements(dependencyTypes()).asList();
|
|
}
|
|
|
|
/** The values listed as {@code modules}. */
|
|
public abstract ImmutableList<AnnotationValue> moduleValues();
|
|
|
|
/** The types listed as {@code modules}. */
|
|
public ImmutableList<TypeMirror> moduleTypes() {
|
|
return moduleValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
|
|
}
|
|
|
|
/**
|
|
* The types listed as {@code modules}.
|
|
*
|
|
* @throws IllegalArgumentException if any of {@link #moduleTypes()} are error types
|
|
*/
|
|
public ImmutableSet<TypeElement> modules() {
|
|
return asTypeElements(moduleTypes());
|
|
}
|
|
|
|
protected final ImmutableList<AnnotationValue> getAnnotationValues(String parameterName) {
|
|
return asAnnotationValues(getAnnotationValue(annotation(), parameterName));
|
|
}
|
|
|
|
/**
|
|
* Returns an object representing a root component annotation, not a subcomponent annotation, if
|
|
* one is present on {@code typeElement}.
|
|
*/
|
|
public static Optional<ComponentAnnotation> rootComponentAnnotation(TypeElement typeElement) {
|
|
return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS);
|
|
}
|
|
|
|
/**
|
|
* Returns an object representing a subcomponent annotation, if one is present on {@code
|
|
* typeElement}.
|
|
*/
|
|
public static Optional<ComponentAnnotation> subcomponentAnnotation(TypeElement typeElement) {
|
|
return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS);
|
|
}
|
|
|
|
/**
|
|
* Returns an object representing a root component or subcomponent annotation, if one is present
|
|
* on {@code typeElement}.
|
|
*/
|
|
public static Optional<ComponentAnnotation> anyComponentAnnotation(TypeElement typeElement) {
|
|
return anyComponentAnnotation(typeElement, ALL_COMPONENT_ANNOTATIONS);
|
|
}
|
|
|
|
private static Optional<ComponentAnnotation> anyComponentAnnotation(
|
|
TypeElement typeElement, Collection<Class<? extends Annotation>> annotations) {
|
|
return getAnyAnnotation(typeElement, annotations).map(ComponentAnnotation::componentAnnotation);
|
|
}
|
|
|
|
/** Returns {@code true} if the argument is a component annotation. */
|
|
public static boolean isComponentAnnotation(AnnotationMirror annotation) {
|
|
return ALL_COMPONENT_ANNOTATIONS.stream()
|
|
.anyMatch(annotationClass -> isTypeOf(annotationClass, annotation.getAnnotationType()));
|
|
}
|
|
|
|
/** Creates an object representing a component or subcomponent annotation. */
|
|
public static ComponentAnnotation componentAnnotation(AnnotationMirror annotation) {
|
|
RealComponentAnnotation.Builder annotationBuilder =
|
|
RealComponentAnnotation.builder().annotation(annotation);
|
|
|
|
if (isTypeOf(Component.class, annotation.getAnnotationType())) {
|
|
return annotationBuilder.isProduction(false).isSubcomponent(false).build();
|
|
}
|
|
if (isTypeOf(Subcomponent.class, annotation.getAnnotationType())) {
|
|
return annotationBuilder.isProduction(false).isSubcomponent(true).build();
|
|
}
|
|
if (isTypeOf(ProductionComponent.class, annotation.getAnnotationType())) {
|
|
return annotationBuilder.isProduction(true).isSubcomponent(false).build();
|
|
}
|
|
if (isTypeOf(ProductionSubcomponent.class, annotation.getAnnotationType())) {
|
|
return annotationBuilder.isProduction(true).isSubcomponent(true).build();
|
|
}
|
|
throw new IllegalArgumentException(
|
|
annotation
|
|
+ " must be a Component, Subcomponent, ProductionComponent, "
|
|
+ "or ProductionSubcomponent annotation");
|
|
}
|
|
|
|
/** Creates a fictional component annotation representing a module. */
|
|
public static ComponentAnnotation fromModuleAnnotation(ModuleAnnotation moduleAnnotation) {
|
|
return new AutoValue_ComponentAnnotation_FictionalComponentAnnotation(moduleAnnotation);
|
|
}
|
|
|
|
/** The root component annotation types. */
|
|
public static ImmutableSet<Class<? extends Annotation>> rootComponentAnnotations() {
|
|
return ROOT_COMPONENT_ANNOTATIONS;
|
|
}
|
|
|
|
/** The subcomponent annotation types. */
|
|
public static ImmutableSet<Class<? extends Annotation>> subcomponentAnnotations() {
|
|
return SUBCOMPONENT_ANNOTATIONS;
|
|
}
|
|
|
|
/** All component annotation types. */
|
|
public static ImmutableSet<Class<? extends Annotation>> allComponentAnnotations() {
|
|
return ALL_COMPONENT_ANNOTATIONS;
|
|
}
|
|
|
|
/** All component and creator annotation types. */
|
|
public static ImmutableSet<Class<? extends Annotation>> allComponentAndCreatorAnnotations() {
|
|
return ALL_COMPONENT_AND_CREATOR_ANNOTATIONS;
|
|
}
|
|
|
|
/**
|
|
* An actual component annotation.
|
|
*
|
|
* @see FictionalComponentAnnotation
|
|
*/
|
|
@AutoValue
|
|
abstract static class RealComponentAnnotation extends ComponentAnnotation {
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableList<AnnotationValue> dependencyValues() {
|
|
return isSubcomponent() ? ImmutableList.of() : getAnnotationValues("dependencies");
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableList<TypeMirror> dependencyTypes() {
|
|
return super.dependencyTypes();
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableList<TypeElement> dependencies() {
|
|
return super.dependencies();
|
|
}
|
|
|
|
@Override
|
|
public boolean isRealComponent() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableList<AnnotationValue> moduleValues() {
|
|
return getAnnotationValues("modules");
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableList<TypeMirror> moduleTypes() {
|
|
return super.moduleTypes();
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableSet<TypeElement> modules() {
|
|
return super.modules();
|
|
}
|
|
|
|
static Builder builder() {
|
|
return new AutoValue_ComponentAnnotation_RealComponentAnnotation.Builder();
|
|
}
|
|
|
|
@AutoValue.Builder
|
|
interface Builder {
|
|
Builder annotation(AnnotationMirror annotation);
|
|
|
|
Builder isSubcomponent(boolean isSubcomponent);
|
|
|
|
Builder isProduction(boolean isProduction);
|
|
|
|
RealComponentAnnotation build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A fictional component annotation used to represent modules or other collections of bindings as
|
|
* a component.
|
|
*/
|
|
@AutoValue
|
|
abstract static class FictionalComponentAnnotation extends ComponentAnnotation {
|
|
|
|
@Override
|
|
public AnnotationMirror annotation() {
|
|
return moduleAnnotation().annotation();
|
|
}
|
|
|
|
@Override
|
|
public boolean isSubcomponent() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isProduction() {
|
|
return ClassName.get(asType(moduleAnnotation().annotation().getAnnotationType().asElement()))
|
|
.equals(PRODUCER_MODULE);
|
|
}
|
|
|
|
@Override
|
|
public boolean isRealComponent() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public ImmutableList<AnnotationValue> dependencyValues() {
|
|
return ImmutableList.of();
|
|
}
|
|
|
|
@Override
|
|
public ImmutableList<AnnotationValue> moduleValues() {
|
|
return moduleAnnotation().includesAsAnnotationValues();
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableList<TypeMirror> moduleTypes() {
|
|
return super.moduleTypes();
|
|
}
|
|
|
|
@Override
|
|
@Memoized
|
|
public ImmutableSet<TypeElement> modules() {
|
|
return super.modules();
|
|
}
|
|
|
|
public abstract ModuleAnnotation moduleAnnotation();
|
|
}
|
|
}
|