• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.uber.nullaway.handlers;
2 
3 /*
4  * Copyright (c) 2017 Uber Technologies, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.errorprone.predicates.type.DescendantOf;
27 import com.google.errorprone.suppliers.Suppliers;
28 import com.uber.nullaway.handlers.stream.StreamModelBuilder;
29 import com.uber.nullaway.handlers.stream.StreamTypeRecord;
30 
31 public class StreamNullabilityPropagatorFactory {
32 
33   /** Returns a handler for the standard Java 8 stream APIs. */
getJavaStreamNullabilityPropagator()34   public static StreamNullabilityPropagator getJavaStreamNullabilityPropagator() {
35     ImmutableList<StreamTypeRecord> streamModels =
36         StreamModelBuilder.start()
37             .addStreamType(new DescendantOf(Suppliers.typeFromString("java.util.stream.Stream")))
38             // Names of all the methods of java.util.stream.Stream that behave like .filter(...)
39             // (must take exactly 1 argument)
40             .withFilterMethodFromSignature("filter(java.util.function.Predicate<? super T>)")
41             // Names and relevant arguments of all the methods of java.util.stream.Stream that
42             // behave
43             // like .map(...) for the purposes of this checker (the listed arguments are those that
44             // take the potentially filtered objects from the stream)
45             .withMapMethodFromSignature(
46                 "<R>map(java.util.function.Function<? super T,? extends R>)",
47                 "apply",
48                 ImmutableSet.of(0))
49             .withMapMethodFromSignature(
50                 "mapToInt(java.util.function.ToIntFunction<? super T>)",
51                 "applyAsInt",
52                 ImmutableSet.of(0))
53             .withMapMethodFromSignature(
54                 "mapToLong(java.util.function.ToLongFunction<? super T>)",
55                 "applyAsLong",
56                 ImmutableSet.of(0))
57             .withMapMethodFromSignature(
58                 "mapToDouble(java.util.function.ToDoubleFunction<? super T>)",
59                 "applyAsDouble",
60                 ImmutableSet.of(0))
61             .withMapMethodFromSignature(
62                 "forEach(java.util.function.Consumer<? super T>)", "accept", ImmutableSet.of(0))
63             .withMapMethodFromSignature(
64                 "forEachOrdered(java.util.function.Consumer<? super T>)",
65                 "accept",
66                 ImmutableSet.of(0))
67             .withMapMethodAllFromName("flatMap", "apply", ImmutableSet.of(0))
68             // List of methods of java.util.stream.Stream through which we just propagate the
69             // nullability information of the last call, e.g. m() in
70             // Observable.filter(...).m().map(...) means the
71             // nullability information from filter(...) should still be propagated to map(...),
72             // ignoring the interleaving call to m().
73             .withPassthroughMethodFromSignature("distinct()")
74             // List of methods of java.util.stream.Stream that both use the nullability information
75             // internally (like map does), but also don't change the values flowing through the
76             // stream
77             // and thus propagate
78             // the nullability information of the last call.
79             .end();
80     return new StreamNullabilityPropagator(streamModels);
81   }
82 
83   /** Returns a handler for io.reactivex.* stream APIs */
getRxStreamNullabilityPropagator()84   public static StreamNullabilityPropagator getRxStreamNullabilityPropagator() {
85     ImmutableList<StreamTypeRecord> rxModels =
86         StreamModelBuilder.start()
87             .addStreamType(new DescendantOf(Suppliers.typeFromString("io.reactivex.Observable")))
88             // Names of all the methods of io.reactivex.Observable that behave like .filter(...)
89             // (must take exactly 1 argument)
90             .withFilterMethodFromSignature("filter(io.reactivex.functions.Predicate<? super T>)")
91             // Names and relevant arguments of all the methods of io.reactivex.Observable that
92             // behave
93             // like .map(...) for the purposes of this checker (the listed arguments are those that
94             // take the potentially filtered objects from the stream)
95             .withMapMethodFromSignature(
96                 "<R>map(io.reactivex.functions.Function<? super T,? extends R>)",
97                 "apply",
98                 ImmutableSet.of(0))
99             .withMapMethodAllFromName("flatMap", "apply", ImmutableSet.of(0))
100             .withMapMethodAllFromName("flatMapSingle", "apply", ImmutableSet.of(0))
101             .withMapMethodFromSignature(
102                 "distinctUntilChanged(io.reactivex.functions.BiPredicate<? super T,? super T>)",
103                 "test",
104                 ImmutableSet.of(0, 1))
105             // List of methods of io.reactivex.Observable through which we just propagate the
106             // nullability information of the last call, e.g. m() in
107             // Observable.filter(...).m().map(...) means the
108             // nullability information from filter(...) should still be propagated to map(...),
109             // ignoring the interleaving call to m().
110             .withPassthroughMethodFromSignature("distinct()")
111             .withPassthroughMethodFromSignature("distinctUntilChanged()")
112             .withPassthroughMethodAllFromName("observeOn")
113             // List of methods of io.reactivex.Observable that both use the nullability information
114             // internally (like map does), but also don't change the values flowing through the
115             // stream
116             // and thus propagate
117             // the nullability information of the last call.
118             .withUseAndPassthroughMethodAllFromName("doOnNext", "accept", ImmutableSet.of(0))
119             .addStreamType(new DescendantOf(Suppliers.typeFromString("io.reactivex.Maybe")))
120             .withFilterMethodFromSignature("filter(io.reactivex.functions.Predicate<? super T>)")
121             .withMapMethodFromSignature(
122                 "<R>map(io.reactivex.functions.Function<? super T,? extends R>)",
123                 "apply",
124                 ImmutableSet.of(0))
125             .withMapMethodAllFromName("flatMap", "apply", ImmutableSet.of(0))
126             .withMapMethodAllFromName("flatMapSingle", "apply", ImmutableSet.of(0))
127             .withPassthroughMethodAllFromName("observeOn")
128             .withUseAndPassthroughMethodAllFromName("doOnNext", "accept", ImmutableSet.of(0))
129             .addStreamType(new DescendantOf(Suppliers.typeFromString("io.reactivex.Single")))
130             .withFilterMethodFromSignature("filter(io.reactivex.functions.Predicate<? super T>)")
131             .withMapMethodFromSignature(
132                 "<R>map(io.reactivex.functions.Function<? super T,? extends R>)",
133                 "apply",
134                 ImmutableSet.of(0))
135             .withMapMethodAllFromName("flatMap", "apply", ImmutableSet.of(0))
136             .withMapMethodAllFromName("flatMapSingle", "apply", ImmutableSet.of(0))
137             .withPassthroughMethodAllFromName("observeOn")
138             .withUseAndPassthroughMethodAllFromName("doOnNext", "accept", ImmutableSet.of(0))
139             .end();
140 
141     return new StreamNullabilityPropagator(rxModels);
142   }
143 
144   /**
145    * Create a new StreamNullabilityPropagator from a list of StreamTypeRecord specs.
146    *
147    * <p>This is used to create a new StreamNullabilityPropagator based on stream API specs provided
148    * by library models.
149    *
150    * @param streamNullabilitySpecs the list of StreamTypeRecord objects defining one or more stream
151    *     APIs (from {@link StreamModelBuilder}).
152    * @return A handler corresponding to the stream APIs defined by the given specs.
153    */
fromSpecs( ImmutableList<StreamTypeRecord> streamNullabilitySpecs)154   public static StreamNullabilityPropagator fromSpecs(
155       ImmutableList<StreamTypeRecord> streamNullabilitySpecs) {
156     return new StreamNullabilityPropagator(streamNullabilitySpecs);
157   }
158 }
159