1 /* 2 * Copyright (C) 2021 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.xprocessing; 18 19 import static androidx.room.compiler.processing.XElementKt.isConstructor; 20 import static androidx.room.compiler.processing.XElementKt.isField; 21 import static androidx.room.compiler.processing.XElementKt.isMethod; 22 import static androidx.room.compiler.processing.XElementKt.isMethodParameter; 23 import static androidx.room.compiler.processing.XElementKt.isTypeElement; 24 import static androidx.room.compiler.processing.XElementKt.isVariableElement; 25 import static androidx.room.compiler.processing.compat.XConverters.toJavac; 26 import static com.google.common.base.Preconditions.checkState; 27 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 28 29 import androidx.room.compiler.processing.XAnnotated; 30 import androidx.room.compiler.processing.XAnnotation; 31 import androidx.room.compiler.processing.XConstructorElement; 32 import androidx.room.compiler.processing.XElement; 33 import androidx.room.compiler.processing.XEnumEntry; 34 import androidx.room.compiler.processing.XExecutableElement; 35 import androidx.room.compiler.processing.XExecutableParameterElement; 36 import androidx.room.compiler.processing.XFieldElement; 37 import androidx.room.compiler.processing.XMethodElement; 38 import androidx.room.compiler.processing.XTypeElement; 39 import androidx.room.compiler.processing.XVariableElement; 40 import com.google.common.collect.ImmutableSet; 41 import com.squareup.javapoet.ClassName; 42 import java.util.Collection; 43 import java.util.Optional; 44 import javax.lang.model.element.ElementKind; 45 46 // TODO(bcorso): Consider moving these methods into XProcessing library. 47 /** A utility class for {@link XElement} helper methods. */ 48 public final class XElements { 49 50 // TODO(bcorso): Replace usages with getJvmName() once it exists. 51 /** Returns the simple name of the element. */ getSimpleName(XElement element)52 public static String getSimpleName(XElement element) { 53 return toJavac(element).getSimpleName().toString(); 54 } 55 56 /** 57 * Returns the closest enclosing element that is a {@link XTypeElement} or throws an {@link 58 * IllegalStateException} if one doesn't exists. 59 */ closestEnclosingTypeElement(XElement element)60 public static XTypeElement closestEnclosingTypeElement(XElement element) { 61 return optionalClosestEnclosingTypeElement(element) 62 .orElseThrow(() -> new IllegalStateException("No enclosing TypeElement for: " + element)); 63 } 64 optionalClosestEnclosingTypeElement(XElement element)65 private static Optional<XTypeElement> optionalClosestEnclosingTypeElement(XElement element) { 66 if (isTypeElement(element)) { 67 return Optional.of(asTypeElement(element)); 68 } else if (isConstructor(element)) { 69 return Optional.of(asConstructor(element).getEnclosingElement()); 70 } else if (isMethod(element)) { 71 return optionalClosestEnclosingTypeElement(asMethod(element).getEnclosingElement()); 72 } else if (isField(element)) { 73 return optionalClosestEnclosingTypeElement(asField(element).getEnclosingElement()); 74 } else if (isMethodParameter(element)) { 75 return optionalClosestEnclosingTypeElement( 76 asMethodParameter(element).getEnclosingMethodElement()); 77 } 78 return Optional.empty(); 79 } 80 isEnumEntry(XElement element)81 public static boolean isEnumEntry(XElement element) { 82 return element instanceof XEnumEntry; 83 } 84 isEnum(XElement element)85 public static boolean isEnum(XElement element) { 86 return toJavac(element).getKind() == ElementKind.ENUM; 87 } 88 isExecutable(XElement element)89 public static boolean isExecutable(XElement element) { 90 return isConstructor(element) || isMethod(element); 91 } 92 asExecutable(XElement element)93 public static XExecutableElement asExecutable(XElement element) { 94 checkState(isExecutable(element)); 95 return (XExecutableElement) element; 96 } 97 asTypeElement(XElement element)98 public static XTypeElement asTypeElement(XElement element) { 99 checkState(isTypeElement(element)); 100 return (XTypeElement) element; 101 } 102 103 // TODO(bcorso): Rename this and the XElementKt.isMethodParameter to isExecutableParameter. asMethodParameter(XElement element)104 public static XExecutableParameterElement asMethodParameter(XElement element) { 105 checkState(isMethodParameter(element)); 106 return (XExecutableParameterElement) element; 107 } 108 asField(XElement element)109 public static XFieldElement asField(XElement element) { 110 checkState(isField(element)); 111 return (XFieldElement) element; 112 } 113 asVariable(XElement element)114 public static XVariableElement asVariable(XElement element) { 115 checkState(isVariableElement(element)); 116 return (XVariableElement) element; 117 } 118 asConstructor(XElement element)119 public static XConstructorElement asConstructor(XElement element) { 120 checkState(isConstructor(element)); 121 return (XConstructorElement) element; 122 } 123 asMethod(XElement element)124 public static XMethodElement asMethod(XElement element) { 125 checkState(isMethod(element)); 126 return (XMethodElement) element; 127 } 128 getAnnotatedAnnotations( XAnnotated annotated, ClassName annotationName)129 public static ImmutableSet<XAnnotation> getAnnotatedAnnotations( 130 XAnnotated annotated, ClassName annotationName) { 131 return annotated.getAllAnnotations().stream() 132 .filter(annotation -> annotation.getType().getTypeElement().hasAnnotation(annotationName)) 133 .collect(toImmutableSet()); 134 } 135 136 /** Returns {@code true} if {@code annotated} is annotated with any of the given annotations. */ hasAnyAnnotation(XAnnotated annotated, ClassName... annotations)137 public static boolean hasAnyAnnotation(XAnnotated annotated, ClassName... annotations) { 138 return hasAnyAnnotation(annotated, ImmutableSet.copyOf(annotations)); 139 } 140 141 /** Returns {@code true} if {@code annotated} is annotated with any of the given annotations. */ hasAnyAnnotation(XAnnotated annotated, Collection<ClassName> annotations)142 public static boolean hasAnyAnnotation(XAnnotated annotated, Collection<ClassName> annotations) { 143 return annotations.stream().anyMatch(annotated::hasAnnotation); 144 } 145 146 /** 147 * Returns any annotation from {@code annotations} that annotates {@code annotated} or else {@code 148 * Optional.empty()}. 149 */ getAnyAnnotation( XAnnotated annotated, ClassName... annotations)150 public static Optional<XAnnotation> getAnyAnnotation( 151 XAnnotated annotated, ClassName... annotations) { 152 return getAnyAnnotation(annotated, ImmutableSet.copyOf(annotations)); 153 } 154 155 /** 156 * Returns any annotation from {@code annotations} that annotates {@code annotated} or else 157 * {@code Optional.empty()}. 158 */ getAnyAnnotation( XAnnotated annotated, Collection<ClassName> annotations)159 public static Optional<XAnnotation> getAnyAnnotation( 160 XAnnotated annotated, Collection<ClassName> annotations) { 161 return annotations.stream() 162 .filter(annotated::hasAnnotation) 163 .map(annotated::getAnnotation) 164 .findFirst(); 165 } 166 167 /** Returns all annotations from {@code annotations} that annotate {@code annotated}. */ getAllAnnotations( XAnnotated annotated, Collection<ClassName> annotations)168 public static ImmutableSet<XAnnotation> getAllAnnotations( 169 XAnnotated annotated, Collection<ClassName> annotations) { 170 return annotations.stream() 171 .filter(annotated::hasAnnotation) 172 .map(annotated::getAnnotation) 173 .collect(toImmutableSet()); 174 } 175 XElements()176 private XElements() {} 177 } 178