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; 18 19 import static androidx.room.compiler.processing.util.ProcessorTestExtKt.runProcessorTest; 20 import static com.google.common.truth.Truth.assertThat; 21 import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement; 22 import static dagger.internal.codegen.xprocessing.XTypes.stripVariances; 23 24 import androidx.room.compiler.processing.XMethodElement; 25 import androidx.room.compiler.processing.XProcessingEnvConfig; 26 import androidx.room.compiler.processing.XTypeElement; 27 import androidx.room.compiler.processing.util.Source; 28 import androidx.room.compiler.processing.util.XTestInvocation; 29 import com.google.common.collect.ImmutableList; 30 import com.google.common.collect.ImmutableMap; 31 import com.squareup.javapoet.TypeName; 32 import dagger.testing.compile.CompilerTests; 33 import java.util.function.Function; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.junit.runners.JUnit4; 37 38 @RunWith(JUnit4.class) 39 public class XTypesStripTypeNameTest { 40 @Test fooExtendsBar()41 public void fooExtendsBar() { 42 assertStrippedWildcardTypeNameEquals( 43 /* source = */ 44 CompilerTests.javaSource( 45 "Subject", 46 "interface Subject {", 47 " Foo<? extends Bar<? extends Baz>> method();", 48 "", 49 " interface Foo<T> {}", 50 " interface Bar<T> {}", 51 " interface Baz {}", 52 "}"), 53 /* strippedTypeName = */ "Foo<Bar<Baz>>"); 54 } 55 56 @Test fooSuperBar()57 public void fooSuperBar() { 58 assertStrippedWildcardTypeNameEquals( 59 /* source = */ 60 CompilerTests.javaSource( 61 "Subject", 62 "interface Subject {", 63 " Foo<? super Bar<? super Baz>> method();", 64 "", 65 " interface Foo<T> {}", 66 " interface Bar<T> {}", 67 " interface Baz {}", 68 "}"), 69 /* strippedTypeName = */ "Foo<Bar<Baz>>"); 70 } 71 72 @Test multipleParameters()73 public void multipleParameters() { 74 assertStrippedWildcardTypeNameEquals( 75 /* source = */ 76 CompilerTests.javaSource( 77 "Subject", 78 "interface Subject {", 79 " Foo<Bar<? extends Baz>, Bar<? super Baz>> method();", 80 "", 81 " interface Foo<T1, T2> {}", 82 " interface Bar<T> {}", 83 " interface Baz {}", 84 "}"), 85 /* strippedTypeName = */ "Foo<Bar<Baz>, Bar<Baz>>"); 86 } 87 88 @Test multipleParametersSameArgument()89 public void multipleParametersSameArgument() { 90 assertStrippedWildcardTypeNameEquals( 91 /* source = */ 92 CompilerTests.javaSource( 93 "Subject", 94 "interface Subject {", 95 " Foo<Bar<? extends Baz>, Bar<? extends Baz>> method();", 96 "", 97 " interface Foo<T1, T2> {}", 98 " interface Bar<T> {}", 99 " interface Baz {}", 100 "}"), 101 /* strippedTypeName = */ "Foo<Bar<Baz>, Bar<Baz>>"); 102 } 103 104 @Test multipleParametersCrossReferencing()105 public void multipleParametersCrossReferencing() { 106 assertStrippedWildcardTypeNameEquals( 107 /* source = */ 108 CompilerTests.javaSource( 109 "Subject", 110 "interface Subject {", 111 " Foo<Bar<? extends Baz>, Bar<? extends Bar<? extends Baz>>> method();", 112 "", 113 " interface Foo<T1, T2 extends Bar<? extends T1>> {}", 114 " interface Bar<T> {}", 115 " interface Baz {}", 116 "}"), 117 /* strippedTypeName = */ "Foo<Bar<Baz>, Bar<Bar<Baz>>>"); 118 } 119 120 @Test selfReferencing()121 public void selfReferencing() { 122 assertStrippedWildcardTypeNameEquals( 123 /* source = */ 124 CompilerTests.javaSource( 125 "Subject", 126 "interface Subject {", 127 " <T extends Foo<T>> Foo<T> method();", 128 "", 129 " interface Foo<T extends Foo<T>> {}", 130 "}"), 131 /* strippedTypeName = */ "Foo<T>"); 132 } 133 134 @Test arrayType()135 public void arrayType() { 136 assertStrippedWildcardTypeNameEquals( 137 /* source = */ 138 CompilerTests.javaSource( 139 "Subject", 140 "interface Subject {", 141 " Foo<? extends Bar<? extends Baz>>[] method();", 142 "", 143 " interface Foo<T> {}", 144 " interface Bar<T> {}", 145 " interface Baz {}", 146 "}"), 147 /* strippedTypeName = */ "Foo<Bar<Baz>>[]"); 148 } 149 150 @Test typeVariableSameVariableName()151 public void typeVariableSameVariableName() { 152 runTest( 153 CompilerTests.javaSource( 154 "Subject", 155 "interface Subject {", 156 " <T extends Bar> Foo<T> method1();", 157 " <T extends Baz> Foo<T> method2();", 158 "", 159 " interface Foo<T> {}", 160 " interface Bar {}", 161 " interface Baz {}", 162 "}"), 163 invocation -> { 164 XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject"); 165 TypeName method1ReturnTypeName = 166 getDeclaredMethod(subject, "method1").getReturnType().getTypeName(); 167 TypeName method2ReturnTypeName = 168 getDeclaredMethod(subject, "method2").getReturnType().getTypeName(); 169 assertThat(method1ReturnTypeName).isEqualTo(method2ReturnTypeName); 170 return null; 171 }); 172 } 173 assertStrippedWildcardTypeNameEquals(Source source, String strippedTypeName)174 private static void assertStrippedWildcardTypeNameEquals(Source source, String strippedTypeName) { 175 runTest( 176 source, 177 invocation -> { 178 XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject"); 179 TypeName returnTypeName = 180 getDeclaredMethod(subject, "method").getReturnType().getTypeName(); 181 assertThat(stripVariances(returnTypeName).toString().replace("Subject.", "")) 182 .isEqualTo(strippedTypeName); 183 return null; 184 }); 185 } 186 runTest(Source source, Function<XTestInvocation, Void> handler)187 private static void runTest(Source source, Function<XTestInvocation, Void> handler) { 188 runProcessorTest( 189 ImmutableList.of(source), 190 /* classpath = */ ImmutableList.of(), 191 /* options = */ ImmutableMap.of(), 192 /* javacArguments = */ ImmutableList.of(), 193 /* kotlincArguments = */ ImmutableList.of(), 194 /* config = */ new XProcessingEnvConfig.Builder().build(), 195 /* handler = */ invocation -> { 196 handler.apply(invocation); 197 return null; 198 }); 199 } 200 getDeclaredMethod(XTypeElement typeElement, String jvmName)201 private static XMethodElement getDeclaredMethod(XTypeElement typeElement, String jvmName) { 202 return typeElement.getDeclaredMethods().stream() 203 .filter(method -> method.getJvmName().contentEquals(jvmName)) 204 .collect(onlyElement()); 205 } 206 } 207