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