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