All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas Maven / Gradle / Ivy

The newest version!
/*
 * 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.hilt.processor.internal.definecomponent;

import static androidx.room.compiler.processing.XElementKt.isTypeElement;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;

import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XFieldElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
import dagger.internal.codegen.xprocessing.XAnnotations;
import dagger.internal.codegen.xprocessing.XElements;
import dagger.internal.codegen.xprocessing.XTypes;
import java.util.HashMap;
import java.util.Map;

/** Metadata for types annotated with {@link dagger.hilt.DefineComponent.Builder}. */
final class DefineComponentBuilderMetadatas {
  static DefineComponentBuilderMetadatas create(DefineComponentMetadatas componentMetadatas) {
    return new DefineComponentBuilderMetadatas(componentMetadatas);
  }

  private final Map builderMetadatas = new HashMap<>();
  private final DefineComponentMetadatas componentMetadatas;

  private DefineComponentBuilderMetadatas(DefineComponentMetadatas componentMetadatas) {
    this.componentMetadatas = componentMetadatas;
  }

  DefineComponentBuilderMetadata get(XElement element) {
    if (!builderMetadatas.containsKey(element)) {
      builderMetadatas.put(element, getUncached(element));
    }
    return builderMetadatas.get(element);
  }

  private DefineComponentBuilderMetadata getUncached(XElement element) {
    ProcessorErrors.checkState(
        element.hasAnnotation(ClassNames.DEFINE_COMPONENT_BUILDER),
        element,
        "%s, expected to be annotated with @DefineComponent.Builder. Found: %s",
        XElements.toStableString(element),
        element.getAllAnnotations().stream()
            .map(XAnnotations::toStableString)
            .collect(toImmutableList()));

    // TODO(bcorso): Allow abstract classes?
    ProcessorErrors.checkState(
        isTypeElement(element) && asTypeElement(element).isInterface(),
        element,
        "@DefineComponent.Builder is only allowed on interfaces. Found: %s",
        XElements.toStableString(element));
    XTypeElement builder = asTypeElement(element);

    // TODO(bcorso): Allow extending interfaces?
    ProcessorErrors.checkState(
        builder.getSuperInterfaces().isEmpty(),
        builder,
        "@DefineComponent.Builder %s, cannot extend a super class or interface. Found: %s",
        XElements.toStableString(builder),
        builder.getSuperInterfaces().stream()
            .map(XTypes::toStableString)
            .collect(toImmutableList()));

    // TODO(bcorso): Allow type parameters?
    ProcessorErrors.checkState(
        builder.getTypeParameters().isEmpty(),
        builder,
        "@DefineComponent.Builder %s, cannot have type parameters.",
        XTypes.toStableString(builder.getType()));

    ImmutableList nonStaticFields =
        builder.getDeclaredFields().stream()
            .filter(field -> !field.isStatic())
            .collect(toImmutableList());

    ProcessorErrors.checkState(
        nonStaticFields.isEmpty(),
        builder,
        "@DefineComponent.Builder %s, cannot have non-static fields. Found: %s",
        XElements.toStableString(builder),
        nonStaticFields.stream()
            .map(XElements::toStableString)
            .collect(toImmutableList()));

    ImmutableList buildMethods =
        builder.getDeclaredMethods().stream()
            .filter(method -> !method.isStatic())
            .filter(method -> method.getParameters().isEmpty())
            .collect(toImmutableList());

    ProcessorErrors.checkState(
        buildMethods.size() == 1,
        builder,
        "@DefineComponent.Builder %s, must have exactly 1 build method that takes no parameters. "
            + "Found: %s",
        XElements.toStableString(builder),
        buildMethods.stream()
            .map(XElements::toStableString)
            .collect(toImmutableList()));

    XMethodElement buildMethod = buildMethods.get(0);
    XType componentType = buildMethod.getReturnType();
    ProcessorErrors.checkState(
        isDeclared(componentType)
            && componentType.getTypeElement().hasAnnotation(ClassNames.DEFINE_COMPONENT),
        builder,
        "@DefineComponent.Builder method, %s#%s, must return a @DefineComponent type. Found: %s",
        XElements.toStableString(builder),
        XElements.toStableString(buildMethod),
        XTypes.toStableString(componentType));

    ImmutableList nonStaticNonBuilderMethods =
        builder.getDeclaredMethods().stream()
            .filter(method -> !method.isStatic())
            .filter(method -> !method.equals(buildMethod))
            .filter(method -> !method.getReturnType().getTypeName().equals(builder.getClassName()))
            .collect(toImmutableList());

    ProcessorErrors.checkStateX(
        nonStaticNonBuilderMethods.isEmpty(),
        nonStaticNonBuilderMethods,
        "@DefineComponent.Builder %s, all non-static methods must return %s or %s. Found: %s",
        XElements.toStableString(builder),
        XElements.toStableString(builder),
        XTypes.toStableString(componentType),
        nonStaticNonBuilderMethods.stream()
            .map(XElements::toStableString)
            .collect(toImmutableList()));

    return new AutoValue_DefineComponentBuilderMetadatas_DefineComponentBuilderMetadata(
        builder,
        buildMethod,
        componentMetadatas.get(componentType.getTypeElement()));
  }

  @AutoValue
  abstract static class DefineComponentBuilderMetadata {
    abstract XTypeElement builder();

    abstract XMethodElement buildMethod();

    abstract DefineComponentMetadata componentMetadata();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy