1 /* 2 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import combo.ComboInstance; 25 import combo.ComboParameter; 26 import combo.ComboTask.Result; 27 import combo.ComboTestHelper; 28 29 import javax.lang.model.element.Element; 30 import java.util.stream.Stream; 31 32 /* 33 * @test 34 * @bug 8176534 35 * @summary Missing check against target-type during applicability inference 36 * @enablePreview 37 * @library /tools/javac/lib 38 * @modules jdk.compiler/com.sun.tools.javac.api 39 * jdk.compiler/com.sun.tools.javac.file 40 * jdk.compiler/com.sun.tools.javac.util 41 * @build combo.ComboTestHelper 42 * 43 * @run main TestUncheckedCalls 44 */ 45 public class TestUncheckedCalls extends ComboInstance<TestUncheckedCalls> { 46 enum InputExpressionKind implements ComboParameter { 47 A("(A)null"), 48 A_STRING("(A<String>)null"), 49 B("(B)null"), 50 B_STRING("(B<String>)null"); 51 52 String inputExpr; 53 54 InputExpressionKind(String inputExpr) { 55 this.inputExpr = inputExpr; 56 } 57 58 59 @Override 60 public String expand(String optParameter) { 61 return inputExpr; 62 } 63 } 64 65 enum TypeKind implements ComboParameter { 66 Z("Z"), 67 C_T("#C<T>"), 68 C_STRING("#C<String>"), 69 C("#C"); 70 71 String typeTemplate; 72 73 TypeKind(String typeTemplate) { 74 this.typeTemplate = typeTemplate; 75 } 76 77 boolean hasTypeVars() { 78 return this == Z || this == C_T; 79 } 80 81 @Override 82 public String expand(String className) { 83 return typeTemplate.replaceAll("#C", className); 84 } 85 } 86 87 enum TypeVarsKind implements ComboParameter { 88 NONE("", "Object"), 89 Z_T("<Z extends #C<T>, T>", "Z"); 90 91 String typeVarsTemplate; 92 String paramString; 93 94 TypeVarsKind(String typeVarsTemplate, String paramString) { 95 this.typeVarsTemplate = typeVarsTemplate; 96 this.paramString = paramString; 97 } 98 99 100 @Override 101 public String expand(String className) { 102 if (className.equals("Z")) { 103 return paramString; 104 } else { 105 return typeVarsTemplate.replaceAll("#C", className); 106 } 107 } 108 } 109 110 enum CallKind implements ComboParameter { 111 M("M(#{IN}, #{IN})"), 112 M_G("M(G(#{IN}, #{IN}), #{IN})"), 113 M_G_G("M(G(#{IN}, #{IN}), G(#{IN}, #{IN}))"); 114 115 String callExpr; 116 117 CallKind(String callExpr) { 118 this.callExpr = callExpr; 119 } 120 121 122 @Override 123 public String expand(String optParameter) { 124 return callExpr; 125 } 126 } 127 128 enum DeclKind implements ComboParameter { 129 NONE(""), 130 ONE("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"), 131 TWO("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }\n" + 132 " #{TVARS[#M_IDX].I2} #{RET[#M_IDX].B} #M(#{ARG[#M_IDX].B} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"); 133 134 String declTemplate; 135 136 DeclKind(String declTemplate) { 137 this.declTemplate = declTemplate; 138 } 139 140 @Override 141 public String expand(String methName) { 142 return declTemplate.replaceAll("#M_IDX", methName.equals("M") ? "0" : "1") 143 .replaceAll("#M", methName); 144 145 } 146 } 147 148 static final String sourceTemplate = 149 "class Test {\n" + 150 " interface I1<X> { }\n" + 151 " interface I2<X> { }\n" + 152 " static class A<X> implements I1<X> { }\n" + 153 " static class B<X> implements I2<X> { }\n" + 154 " #{DECL[0].M}\n" + 155 " #{DECL[1].G}\n" + 156 " void test() {\n" + 157 " #{CALL};\n" + 158 " }\n" + 159 "}\n"; 160 161 public static void main(String... args) throws Exception { 162 new ComboTestHelper<TestUncheckedCalls>() 163 .withFilter(TestUncheckedCalls::arityFilter) 164 .withFilter(TestUncheckedCalls::declFilter) 165 .withFilter(TestUncheckedCalls::tvarFilter) 166 .withFilter(TestUncheckedCalls::inputExprFilter) 167 .withDimension("IN", (x, expr) -> x.inputExpressionKind = expr, InputExpressionKind.values()) 168 .withDimension("CALL", (x, expr) -> x.callKind = expr, CallKind.values()) 169 .withArrayDimension("DECL", (x, decl, idx) -> x.decls[idx] = x.new Decl(decl, idx), 2, DeclKind.values()) 170 .withArrayDimension("TVARS", (x, tvars, idx) -> x.typeVarsKinds[idx] = tvars, 2, TypeVarsKind.values()) 171 .withArrayDimension("RET", (x, ret, idx) -> x.returnKinds[idx] = ret, 2, TypeKind.values()) 172 .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKinds[idx] = arg, 2, TypeKind.values()) 173 .run(TestUncheckedCalls::new); 174 } 175 176 class Decl { 177 private DeclKind declKind; 178 private int index; 179 180 Decl(DeclKind declKind, int index) { 181 this.declKind = declKind; 182 this.index = index; 183 } 184 185 boolean hasKind(DeclKind declKind) { 186 return this.declKind == declKind; 187 } 188 189 boolean isGeneric() { 190 return typeVarsKind() == TypeVarsKind.Z_T; 191 } 192 193 TypeKind returnKind() { 194 return returnKinds[index]; 195 } 196 197 TypeKind argumentsKind() { 198 return argumentKinds[index]; 199 } 200 201 TypeVarsKind typeVarsKind() { 202 return typeVarsKinds[index]; 203 } 204 } 205 206 CallKind callKind; 207 InputExpressionKind inputExpressionKind; 208 TypeKind[] returnKinds = new TypeKind[2]; 209 TypeKind[] argumentKinds = new TypeKind[2]; 210 TypeVarsKind[] typeVarsKinds = new TypeVarsKind[2]; 211 Decl[] decls = new Decl[2]; 212 213 boolean arityFilter() { 214 return (callKind == CallKind.M || !decls[1].hasKind(DeclKind.NONE)) && 215 !decls[0].hasKind(DeclKind.NONE); 216 } 217 218 boolean declFilter() { 219 return Stream.of(decls) 220 .filter(d -> d.hasKind(DeclKind.NONE)) 221 .flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind(), d.typeVarsKind())) 222 .noneMatch((Enum<? extends Enum<?>> tk) -> tk.ordinal() != 0); 223 } 224 225 boolean tvarFilter() { 226 return Stream.of(decls) 227 .filter(d -> !d.hasKind(DeclKind.NONE)) 228 .filter(d -> !d.isGeneric()) 229 .flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind())) 230 .noneMatch(TypeKind::hasTypeVars); 231 } 232 233 boolean inputExprFilter() { 234 return (inputExpressionKind != InputExpressionKind.B && inputExpressionKind != InputExpressionKind.B_STRING) || 235 Stream.of(decls).allMatch(d -> d.declKind == DeclKind.TWO); 236 } 237 238 @Override 239 public void doWork() throws Throwable { 240 newCompilationTask() 241 .withSourceFromTemplate(sourceTemplate) 242 .analyze(this::check); 243 } 244 245 void check(Result<Iterable<? extends Element>> result) { 246 if (result.hasErrors()) { 247 fail("compiler error:\n" + 248 result.compilationInfo()); 249 } 250 } 251 }