1 /* 2 * Copyright (C) 2017 The Android Open Source Project 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 com.android.tools.metalava.stub 18 19 import com.android.tools.metalava.testing.java 20 import org.junit.Test 21 22 @SuppressWarnings("ALL") 23 class StubsGenericTest : AbstractStubsTest() { 24 @Test Generate stubs for genericsnull25 fun `Generate stubs for generics`() { 26 // Basic interface with generics; makes sure <T extends Object> is written as just <T> 27 // Also include some more complex generics expressions to make sure they're serialized 28 // correctly (in particular, using fully qualified names instead of what appears in 29 // the source code.) 30 check( 31 checkCompilation = true, 32 sourceFiles = 33 arrayOf( 34 java( 35 """ 36 package test.pkg; 37 @SuppressWarnings("ALL") 38 public interface MyInterface2<T extends Number> 39 extends MyBaseInterface { 40 class TtsSpan<C extends MyInterface<?>> { } 41 abstract class Range<T extends Comparable<? super T>> { } 42 } 43 """ 44 ), 45 java( 46 """ 47 package test.pkg; 48 @SuppressWarnings("ALL") 49 public interface MyInterface<T extends Object> 50 extends MyBaseInterface { 51 } 52 """ 53 ), 54 java( 55 """ 56 package test.pkg; 57 public interface MyBaseInterface { 58 } 59 """ 60 ) 61 ), 62 expectedIssues = "", 63 stubFiles = 64 arrayOf( 65 java( 66 """ 67 package test.pkg; 68 @SuppressWarnings({"unchecked", "deprecation", "all"}) 69 public interface MyInterface2<T extends java.lang.Number> extends test.pkg.MyBaseInterface { 70 @SuppressWarnings({"unchecked", "deprecation", "all"}) 71 public abstract static class Range<T extends java.lang.Comparable<? super T>> { 72 public Range() { throw new RuntimeException("Stub!"); } 73 } 74 @SuppressWarnings({"unchecked", "deprecation", "all"}) 75 public static class TtsSpan<C extends test.pkg.MyInterface<?>> { 76 public TtsSpan() { throw new RuntimeException("Stub!"); } 77 } 78 } 79 """ 80 ), 81 java( 82 """ 83 package test.pkg; 84 @SuppressWarnings({"unchecked", "deprecation", "all"}) 85 public interface MyInterface<T> extends test.pkg.MyBaseInterface { 86 } 87 """ 88 ), 89 java( 90 """ 91 package test.pkg; 92 @SuppressWarnings({"unchecked", "deprecation", "all"}) 93 public interface MyBaseInterface { 94 } 95 """ 96 ) 97 ) 98 ) 99 } 100 101 @Test Check correct throws list for genericsnull102 fun `Check correct throws list for generics`() { 103 checkStubs( 104 sourceFiles = 105 arrayOf( 106 java( 107 """ 108 package test.pkg; 109 110 import java.util.function.Supplier; 111 112 @SuppressWarnings("RedundantThrows") 113 public final class Test<T> { 114 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 115 return null; 116 } 117 } 118 """ 119 ) 120 ), 121 source = 122 """ 123 package test.pkg; 124 @SuppressWarnings({"unchecked", "deprecation", "all"}) 125 public final class Test<T> { 126 public Test() { throw new RuntimeException("Stub!"); } 127 public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X> exceptionSupplier) throws X { throw new RuntimeException("Stub!"); } 128 } 129 """ 130 ) 131 } 132 133 @Test Generate stubs for additional generics scenariosnull134 fun `Generate stubs for additional generics scenarios`() { 135 // Some additional declarations where PSI default type handling diffs from doclava1 136 checkStubs( 137 sourceFiles = 138 arrayOf( 139 java( 140 """ 141 package test.pkg; 142 143 public abstract class Collections { 144 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { 145 return null; 146 } 147 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t); 148 public final class Range<T extends java.lang.Comparable<? super T>> { } 149 } 150 """ 151 ) 152 ), 153 source = 154 """ 155 package test.pkg; 156 @SuppressWarnings({"unchecked", "deprecation", "all"}) 157 public abstract class Collections { 158 public Collections() { throw new RuntimeException("Stub!"); } 159 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t); 160 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { throw new RuntimeException("Stub!"); } 161 @SuppressWarnings({"unchecked", "deprecation", "all"}) 162 public final class Range<T extends java.lang.Comparable<? super T>> { 163 public Range() { throw new RuntimeException("Stub!"); } 164 } 165 } 166 """ 167 ) 168 } 169 170 @Test Generate stubs for even more generics scenariosnull171 fun `Generate stubs for even more generics scenarios`() { 172 // Some additional declarations where PSI default type handling diffs from doclava1 173 checkStubs( 174 sourceFiles = 175 arrayOf( 176 java( 177 """ 178 package test.pkg; 179 180 import java.util.Set; 181 182 @SuppressWarnings("ALL") 183 public class MoreAsserts { 184 public static void assertEquals(String arg1, Set<? extends Object> arg2, Set<? extends Object> arg3) { } 185 public static void assertEquals(Set<? extends Object> arg1, Set<? extends Object> arg2) { } 186 } 187 """ 188 ) 189 ), 190 source = 191 """ 192 package test.pkg; 193 @SuppressWarnings({"unchecked", "deprecation", "all"}) 194 public class MoreAsserts { 195 public MoreAsserts() { throw new RuntimeException("Stub!"); } 196 public static void assertEquals(java.lang.String arg1, java.util.Set<?> arg2, java.util.Set<?> arg3) { throw new RuntimeException("Stub!"); } 197 public static void assertEquals(java.util.Set<?> arg1, java.util.Set<?> arg2) { throw new RuntimeException("Stub!"); } 198 } 199 """, 200 checkTextStubEquivalence = true 201 ) 202 } 203 204 @Test Check generating classes with genericsnull205 fun `Check generating classes with generics`() { 206 checkStubs( 207 sourceFiles = 208 arrayOf( 209 java( 210 """ 211 package test.pkg; 212 213 public class Generics { 214 public <T> Generics(int surfaceSize, Class<T> klass) { 215 } 216 } 217 """ 218 ) 219 ), 220 warnings = "", 221 source = 222 """ 223 package test.pkg; 224 @SuppressWarnings({"unchecked", "deprecation", "all"}) 225 public class Generics { 226 public <T> Generics(int surfaceSize, java.lang.Class<T> klass) { throw new RuntimeException("Stub!"); } 227 } 228 """ 229 ) 230 } 231 232 @Test Generics Variable Rewritingnull233 fun `Generics Variable Rewriting`() { 234 // When we move methods from hidden superclasses into the subclass since they 235 // provide the implementation for a required method, it's possible that the 236 // method we copied in is referencing generics with a different variable than 237 // in the current class, so we need to handle this 238 239 checkStubs( 240 sourceFiles = 241 arrayOf( 242 // TODO: Try using prefixes like "A", and "AA" to make sure my generics 243 // variable renaming doesn't do something really unexpected 244 java( 245 """ 246 package test.pkg; 247 248 import java.util.List; 249 import java.util.Map; 250 251 public class Generics { 252 public class MyClass<X extends Number,Y> extends HiddenParent<X,Y> implements PublicParent<X,Y> { 253 } 254 255 public class MyClass2<W> extends HiddenParent<Float,W> implements PublicParent<Float, W> { 256 } 257 258 public class MyClass3 extends HiddenParent<Float,Double> implements PublicParent<Float,Double> { 259 } 260 261 class HiddenParent<M, N> extends HiddenParent2<M, N> { 262 } 263 264 class HiddenParent2<T, TT> { 265 public Map<T,Map<TT, String>> createMap(List<T> list) { 266 return null; 267 } 268 } 269 270 public interface PublicParent<A extends Number,B> { 271 Map<A,Map<B, String>> createMap(List<A> list); 272 } 273 } 274 """ 275 ) 276 ), 277 warnings = "", 278 source = 279 """ 280 package test.pkg; 281 @SuppressWarnings({"unchecked", "deprecation", "all"}) 282 public class Generics { 283 public Generics() { throw new RuntimeException("Stub!"); } 284 @SuppressWarnings({"unchecked", "deprecation", "all"}) 285 public class MyClass<X extends java.lang.Number, Y> implements test.pkg.Generics.PublicParent<X,Y> { 286 public MyClass() { throw new RuntimeException("Stub!"); } 287 public java.util.Map<X,java.util.Map<Y,java.lang.String>> createMap(java.util.List<X> list) { throw new RuntimeException("Stub!"); } 288 } 289 @SuppressWarnings({"unchecked", "deprecation", "all"}) 290 public class MyClass2<W> implements test.pkg.Generics.PublicParent<java.lang.Float,W> { 291 public MyClass2() { throw new RuntimeException("Stub!"); } 292 public java.util.Map<java.lang.Float,java.util.Map<W,java.lang.String>> createMap(java.util.List<java.lang.Float> list) { throw new RuntimeException("Stub!"); } 293 } 294 @SuppressWarnings({"unchecked", "deprecation", "all"}) 295 public class MyClass3 implements test.pkg.Generics.PublicParent<java.lang.Float,java.lang.Double> { 296 public MyClass3() { throw new RuntimeException("Stub!"); } 297 public java.util.Map<java.lang.Float,java.util.Map<java.lang.Double,java.lang.String>> createMap(java.util.List<java.lang.Float> list) { throw new RuntimeException("Stub!"); } 298 } 299 @SuppressWarnings({"unchecked", "deprecation", "all"}) 300 public static interface PublicParent<A extends java.lang.Number, B> { 301 public java.util.Map<A,java.util.Map<B,java.lang.String>> createMap(java.util.List<A> list); 302 } 303 } 304 """ 305 ) 306 } 307 } 308