• 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.xprocessing;
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.XAnnotated;
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.google.common.collect.Sets;
32 import com.squareup.javapoet.ClassName;
33 import java.util.Optional;
34 
35 /**
36  * Contains information about the nullability of an element or type.
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(ImmutableSet.of(), ImmutableSet.of(), false);
50 
of(XElement element)51   public static Nullability of(XElement element) {
52     ImmutableSet<ClassName> nonTypeUseNullableAnnotations = getNullableAnnotations(element);
53     Optional<XType> type = getType(element);
54     ImmutableSet<ClassName> typeUseNullableAnnotations =
55     ImmutableSet.of();
56     boolean isKotlinTypeNullable =
57         // Note: Technically, it isn't possible for Java sources to have nullable types like in
58         // Kotlin sources, but for some reason KSP treats certain types as nullable if they have a
59         // specific @Nullable (TYPE_USE target) annotation. Thus, to avoid inconsistencies with
60         // KAPT, just ignore type nullability for elements in java sources.
61         !element.getClosestMemberContainer().isFromJava()
62             && type.isPresent()
63             && type.get().getNullability() == XNullability.NULLABLE;
64     return new AutoValue_Nullability(
65         nonTypeUseNullableAnnotations,
66         // Filter type use annotations that are also found on the element as non-type use
67         // annotations. This prevents them from being applied twice in some scenarios and just
68         // defaults to using them in the way before Dagger supported type use annotations.
69         Sets.difference(typeUseNullableAnnotations, nonTypeUseNullableAnnotations).immutableCopy(),
70         isKotlinTypeNullable);
71   }
72 
getNullableAnnotations(XAnnotated annotated)73   private static ImmutableSet<ClassName> getNullableAnnotations(XAnnotated annotated) {
74     return annotated.getAllAnnotations().stream()
75         .map(XAnnotations::getClassName)
76         .filter(annotation -> annotation.simpleName().contentEquals("Nullable"))
77         .collect(toImmutableSet());
78   }
79 
getType(XElement element)80   private static Optional<XType> getType(XElement element) {
81     if (isMethod(element)) {
82       return Optional.of(asMethod(element).getReturnType());
83     } else if (isVariableElement(element)) {
84       return Optional.of(asVariable(element).getType());
85     }
86     return Optional.empty();
87   }
88 
nonTypeUseNullableAnnotations()89   public abstract ImmutableSet<ClassName> nonTypeUseNullableAnnotations();
90 
typeUseNullableAnnotations()91   public abstract ImmutableSet<ClassName> typeUseNullableAnnotations();
92 
93   /**
94    * Returns {@code true} if the element's type is a Kotlin nullable type, e.g. {@code Foo?}.
95    *
96    * <p>Note that this method ignores any {@code @Nullable} type annotations and only looks for
97    * explicit {@code ?} usages on kotlin types.
98    */
isKotlinTypeNullable()99   public abstract boolean isKotlinTypeNullable();
100 
nullableAnnotations()101   public ImmutableSet<ClassName> nullableAnnotations() {
102     return ImmutableSet.<ClassName>builder()
103         .addAll(nonTypeUseNullableAnnotations())
104         .addAll(typeUseNullableAnnotations()).build();
105   }
106 
isNullable()107   public final boolean isNullable() {
108     return isKotlinTypeNullable() || !nullableAnnotations().isEmpty();
109   }
110 
Nullability()111   Nullability() {}
112 }
113