• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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