/* * Copyright (C) 2021 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.xprocessing; import static androidx.room.compiler.processing.XElementKt.isConstructor; import static androidx.room.compiler.processing.XElementKt.isField; import static androidx.room.compiler.processing.XElementKt.isMethod; import static androidx.room.compiler.processing.XElementKt.isMethodParameter; import static androidx.room.compiler.processing.XElementKt.isTypeElement; import static androidx.room.compiler.processing.XElementKt.isVariableElement; import static androidx.room.compiler.processing.compat.XConverters.toJavac; import static com.google.common.base.Preconditions.checkState; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import androidx.room.compiler.processing.XAnnotated; import androidx.room.compiler.processing.XAnnotation; import androidx.room.compiler.processing.XConstructorElement; import androidx.room.compiler.processing.XElement; import androidx.room.compiler.processing.XEnumEntry; import androidx.room.compiler.processing.XExecutableElement; import androidx.room.compiler.processing.XExecutableParameterElement; import androidx.room.compiler.processing.XFieldElement; import androidx.room.compiler.processing.XMethodElement; import androidx.room.compiler.processing.XTypeElement; import androidx.room.compiler.processing.XVariableElement; import com.google.common.collect.ImmutableSet; import com.squareup.javapoet.ClassName; import java.util.Collection; import java.util.Optional; import javax.lang.model.element.ElementKind; // TODO(bcorso): Consider moving these methods into XProcessing library. /** A utility class for {@link XElement} helper methods. */ public final class XElements { // TODO(bcorso): Replace usages with getJvmName() once it exists. /** Returns the simple name of the element. */ public static String getSimpleName(XElement element) { return toJavac(element).getSimpleName().toString(); } /** * Returns the closest enclosing element that is a {@link XTypeElement} or throws an {@link * IllegalStateException} if one doesn't exists. */ public static XTypeElement closestEnclosingTypeElement(XElement element) { return optionalClosestEnclosingTypeElement(element) .orElseThrow(() -> new IllegalStateException("No enclosing TypeElement for: " + element)); } private static Optional optionalClosestEnclosingTypeElement(XElement element) { if (isTypeElement(element)) { return Optional.of(asTypeElement(element)); } else if (isConstructor(element)) { return Optional.of(asConstructor(element).getEnclosingElement()); } else if (isMethod(element)) { return optionalClosestEnclosingTypeElement(asMethod(element).getEnclosingElement()); } else if (isField(element)) { return optionalClosestEnclosingTypeElement(asField(element).getEnclosingElement()); } else if (isMethodParameter(element)) { return optionalClosestEnclosingTypeElement( asMethodParameter(element).getEnclosingMethodElement()); } return Optional.empty(); } public static boolean isEnumEntry(XElement element) { return element instanceof XEnumEntry; } public static boolean isEnum(XElement element) { return toJavac(element).getKind() == ElementKind.ENUM; } public static boolean isExecutable(XElement element) { return isConstructor(element) || isMethod(element); } public static XExecutableElement asExecutable(XElement element) { checkState(isExecutable(element)); return (XExecutableElement) element; } public static XTypeElement asTypeElement(XElement element) { checkState(isTypeElement(element)); return (XTypeElement) element; } // TODO(bcorso): Rename this and the XElementKt.isMethodParameter to isExecutableParameter. public static XExecutableParameterElement asMethodParameter(XElement element) { checkState(isMethodParameter(element)); return (XExecutableParameterElement) element; } public static XFieldElement asField(XElement element) { checkState(isField(element)); return (XFieldElement) element; } public static XVariableElement asVariable(XElement element) { checkState(isVariableElement(element)); return (XVariableElement) element; } public static XConstructorElement asConstructor(XElement element) { checkState(isConstructor(element)); return (XConstructorElement) element; } public static XMethodElement asMethod(XElement element) { checkState(isMethod(element)); return (XMethodElement) element; } public static ImmutableSet getAnnotatedAnnotations( XAnnotated annotated, ClassName annotationName) { return annotated.getAllAnnotations().stream() .filter(annotation -> annotation.getType().getTypeElement().hasAnnotation(annotationName)) .collect(toImmutableSet()); } /** Returns {@code true} if {@code annotated} is annotated with any of the given annotations. */ public static boolean hasAnyAnnotation(XAnnotated annotated, ClassName... annotations) { return hasAnyAnnotation(annotated, ImmutableSet.copyOf(annotations)); } /** Returns {@code true} if {@code annotated} is annotated with any of the given annotations. */ public static boolean hasAnyAnnotation(XAnnotated annotated, Collection annotations) { return annotations.stream().anyMatch(annotated::hasAnnotation); } /** * Returns any annotation from {@code annotations} that annotates {@code annotated} or else {@code * Optional.empty()}. */ public static Optional getAnyAnnotation( XAnnotated annotated, ClassName... annotations) { return getAnyAnnotation(annotated, ImmutableSet.copyOf(annotations)); } /** * Returns any annotation from {@code annotations} that annotates {@code annotated} or else * {@code Optional.empty()}. */ public static Optional getAnyAnnotation( XAnnotated annotated, Collection annotations) { return annotations.stream() .filter(annotated::hasAnnotation) .map(annotated::getAnnotation) .findFirst(); } /** Returns all annotations from {@code annotations} that annotate {@code annotated}. */ public static ImmutableSet getAllAnnotations( XAnnotated annotated, Collection annotations) { return annotations.stream() .filter(annotated::hasAnnotation) .map(annotated::getAnnotation) .collect(toImmutableSet()); } private XElements() {} }