• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.binding;
18 
19 import static androidx.room.compiler.processing.XElementKt.isMethod;
20 import static androidx.room.compiler.processing.XElementKt.isVariableElement;
21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
22 import static dagger.internal.codegen.xprocessing.XElements.asMethod;
23 import static dagger.internal.codegen.xprocessing.XElements.asVariable;
24 
25 import androidx.room.compiler.processing.XAnnotation;
26 import androidx.room.compiler.processing.XElement;
27 import androidx.room.compiler.processing.XNullability;
28 import androidx.room.compiler.processing.XType;
29 import com.google.auto.value.AutoValue;
30 import com.google.common.collect.ImmutableSet;
31 import com.squareup.javapoet.ClassName;
32 import dagger.internal.codegen.xprocessing.XAnnotations;
33 import java.util.stream.Stream;
34 
35 /**
36  * Contains information about the nullability of an element.
37  *
38  * <p>Note that an element can be nullable if either:
39  *
40  * <ul>
41  *   <li>The element is annotated with {@code Nullable} or
42  *   <li>the associated kotlin type is nullable (i.e. {@code T?} types in Kotlin source).
43  * </ul>
44  */
45 @AutoValue
46 public abstract class Nullability {
47   /** A constant that can represent any non-null element. */
48   public static final Nullability NOT_NULLABLE =
49       new AutoValue_Nullability(false, ImmutableSet.of());
50 
of(XElement element)51   public static Nullability of(XElement element) {
52     return new AutoValue_Nullability(
53         /* isKotlinTypeNullable= */ isKotlinTypeNullable(element),
54         /* nullableAnnotations= */ getNullableAnnotations(element));
55   }
56 
getNullableAnnotations(XElement element)57   private static ImmutableSet<ClassName> getNullableAnnotations(XElement element) {
58     return getNullableAnnotations(element.getAllAnnotations().stream(), ImmutableSet.of());
59   }
60 
getNullableAnnotations( Stream<XAnnotation> annotations, ImmutableSet<ClassName> filterSet)61   private static ImmutableSet<ClassName> getNullableAnnotations(
62       Stream<XAnnotation> annotations,
63       ImmutableSet<ClassName> filterSet) {
64     return annotations
65         .map(XAnnotations::getClassName)
66         .filter(annotation -> annotation.simpleName().contentEquals("Nullable"))
67         .filter(annotation -> !filterSet.contains(annotation))
68         .collect(toImmutableSet());
69   }
70 
71   /**
72    * Returns {@code true} if the element's type is a Kotlin nullable type, e.g. {@code Foo?}.
73    *
74    * <p>Note that this method ignores any {@code @Nullable} type annotations and only looks for
75    * explicit {@code ?} usages on kotlin types.
76    */
isKotlinTypeNullable(XElement element)77   private static boolean isKotlinTypeNullable(XElement element) {
78     if (element.getClosestMemberContainer().isFromJava()) {
79       // Note: Technically, it isn't possible for Java sources to have nullable types like in Kotlin
80       // sources, but for some reason KSP treats certain types as nullable if they have a
81       // specific @Nullable (TYPE_USE target) annotation. Thus, to avoid inconsistencies with KAPT,
82       // just return false if this element is from a java source.
83       return false;
84     } else if (isMethod(element)) {
85       return isKotlinTypeNullable(asMethod(element).getReturnType());
86     } else if (isVariableElement(element)) {
87       return isKotlinTypeNullable(asVariable(element).getType());
88     } else {
89       return false;
90     }
91   }
92 
isKotlinTypeNullable(XType type)93   private static boolean isKotlinTypeNullable(XType type) {
94     return type.getNullability() == XNullability.NULLABLE;
95   }
96 
isKotlinTypeNullable()97   public abstract boolean isKotlinTypeNullable();
98 
nullableAnnotations()99   public abstract ImmutableSet<ClassName> nullableAnnotations();
100 
isNullable()101   public final boolean isNullable() {
102     return isKotlinTypeNullable() || !nullableAnnotations().isEmpty();
103   }
104 
Nullability()105   Nullability() {}
106 }
107