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 com.google.common.base.Preconditions.checkNotNull; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 21 import static kotlin.streams.jdk8.StreamsKt.asStream; 22 23 import androidx.room.compiler.processing.XHasModifiers; 24 import androidx.room.compiler.processing.XMethodElement; 25 import androidx.room.compiler.processing.XTypeElement; 26 import androidx.room.compiler.processing.XTypeParameterElement; 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableSet; 29 import com.squareup.javapoet.TypeVariableName; 30 31 // TODO(bcorso): Consider moving these methods into XProcessing library. 32 /** A utility class for {@link XTypeElement} helper methods. */ 33 public final class XTypeElements { 34 private enum Visibility { 35 PUBLIC, 36 PRIVATE, 37 OTHER; 38 39 /** Returns the visibility of the given {@link XTypeElement}. */ of(XTypeElement element)40 private static Visibility of(XTypeElement element) { 41 checkNotNull(element); 42 if (element.isPrivate()) { 43 return Visibility.PRIVATE; 44 } else if (element.isPublic()) { 45 return Visibility.PUBLIC; 46 } else { 47 return Visibility.OTHER; 48 } 49 } 50 } 51 52 // TODO(bcorso): Consider XParameterizable interface to handle both methods and types. 53 /** Returns the type arguments for the given type as a list of {@link TypeVariableName}. */ typeVariableNames(XTypeElement typeElement)54 public static ImmutableList<TypeVariableName> typeVariableNames(XTypeElement typeElement) { 55 return typeElement.getTypeParameters().stream() 56 .map(XTypeParameterElement::getTypeVariableName) 57 .collect(toImmutableList()); 58 } 59 60 /** Returns {@code true} if the given element is nested. */ isNested(XTypeElement typeElement)61 public static boolean isNested(XTypeElement typeElement) { 62 return typeElement.getEnclosingTypeElement() != null; 63 } 64 65 /** Returns {@code true} if the given {@code type} has type parameters. */ hasTypeParameters(XTypeElement typeElement)66 public static boolean hasTypeParameters(XTypeElement typeElement) { 67 return !typeElement.getTypeParameters().isEmpty(); 68 } 69 70 /** Returns all non-private, non-static, abstract methods in {@code type}. */ getAllUnimplementedMethods(XTypeElement type)71 public static ImmutableList<XMethodElement> getAllUnimplementedMethods(XTypeElement type) { 72 return getAllNonPrivateInstanceMethods(type).stream() 73 .filter(XHasModifiers::isAbstract) 74 .collect(toImmutableList()); 75 } 76 77 /** Returns all non-private, non-static methods in {@code type}. */ getAllNonPrivateInstanceMethods(XTypeElement type)78 public static ImmutableList<XMethodElement> getAllNonPrivateInstanceMethods(XTypeElement type) { 79 return getAllMethods(type).stream() 80 .filter(method -> !method.isPrivate() && !method.isStatic()) 81 .collect(toImmutableList()); 82 } 83 84 // TODO(wanyingd): rename this to getAllMethodsWithoutPrivate, since the private method declared 85 // within this element is being filtered out. This doesn't mirror {@code 86 // MoreElements#getAllMethods}'s behavior but have the same name, and can cause confusion to 87 // developers. getAllMethods(XTypeElement type)88 public static ImmutableList<XMethodElement> getAllMethods(XTypeElement type) { 89 return asStream(type.getAllMethods()) 90 .filter(method -> isAccessibleFrom(method, type)) 91 .collect(toImmutableList()); 92 } 93 getAllMethodsIncludingPrivate(XTypeElement type)94 public static ImmutableList<XMethodElement> getAllMethodsIncludingPrivate(XTypeElement type) { 95 return asStream(type.getAllMethods()).collect(toImmutableList()); 96 } 97 isAccessibleFrom(XMethodElement method, XTypeElement type)98 private static boolean isAccessibleFrom(XMethodElement method, XTypeElement type) { 99 if (method.isPublic() || method.isProtected()) { 100 return true; 101 } 102 if (method.isPrivate()) { 103 return false; 104 } 105 return method 106 .getClosestMemberContainer() 107 .getClassName() 108 .packageName() 109 .equals(type.getClassName().packageName()); 110 } 111 isEffectivelyPublic(XTypeElement element)112 public static boolean isEffectivelyPublic(XTypeElement element) { 113 return allVisibilities(element).stream() 114 .allMatch(visibility -> visibility.equals(Visibility.PUBLIC)); 115 } 116 isEffectivelyPrivate(XTypeElement element)117 public static boolean isEffectivelyPrivate(XTypeElement element) { 118 return allVisibilities(element).contains(Visibility.PRIVATE); 119 } 120 isJvmClass(XTypeElement element)121 public static boolean isJvmClass(XTypeElement element) { 122 return element.isClass() || element.isKotlinObject() || element.isCompanionObject(); 123 } 124 125 /** 126 * Returns a list of visibilities containing visibility of the given element and the visibility of 127 * its enclosing elements. 128 */ allVisibilities(XTypeElement element)129 private static ImmutableSet<Visibility> allVisibilities(XTypeElement element) { 130 checkNotNull(element); 131 ImmutableSet.Builder<Visibility> visibilities = ImmutableSet.builder(); 132 XTypeElement currentElement = element; 133 while (currentElement != null) { 134 visibilities.add(Visibility.of(currentElement)); 135 currentElement = currentElement.getEnclosingTypeElement(); 136 } 137 return visibilities.build(); 138 } 139 XTypeElements()140 private XTypeElements() {} 141 } 142