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 * @library /tools/javac/lib 37 * @modules jdk.compiler/com.sun.tools.javac.api 38 * jdk.compiler/com.sun.tools.javac.file 39 * jdk.compiler/com.sun.tools.javac.util 40 * @build combo.ComboTestHelper 41 * 42 * @run main TestUncheckedCalls 43 */ 44 public class TestUncheckedCalls extends ComboInstance<TestUncheckedCalls> { 45 enum InputExpressionKind implements ComboParameter { 46 A("(A)null"), 47 A_STRING("(A<String>)null"), 48 B("(B)null"), 49 B_STRING("(B<String>)null"); 50 51 String inputExpr; 52 53 InputExpressionKind(String inputExpr) { 54 this.inputExpr = inputExpr; 55 } 56 57 58 @Override 59 public String expand(String optParameter) { 60 return inputExpr; 61 } 62 } 63 64 enum TypeKind implements ComboParameter { 65 Z("Z"), 66 C_T("#C<T>"), 67 C_STRING("#C<String>"), 68 C("#C"); 69 70 String typeTemplate; 71 72 TypeKind(String typeTemplate) { 73 this.typeTemplate = typeTemplate; 74 } 75 76 boolean hasTypeVars() { 77 return this == Z || this == C_T; 78 } 79 80 @Override 81 public String expand(String className) { 82 return typeTemplate.replaceAll("#C", className); 83 } 84 } 85 86 enum TypeVarsKind implements ComboParameter { 87 NONE("", "Object"), 88 Z_T("<Z extends #C<T>, T>", "Z"); 89 90 String typeVarsTemplate; 91 String paramString; 92 93 TypeVarsKind(String typeVarsTemplate, String paramString) { 94 this.typeVarsTemplate = typeVarsTemplate; 95 this.paramString = paramString; 96 } 97 98 99 @Override 100 public String expand(String className) { 101 if (className.equals("Z")) { 102 return paramString; 103 } else { 104 return typeVarsTemplate.replaceAll("#C", className); 105 } 106 } 107 } 108 109 enum CallKind implements ComboParameter { 110 M("M(#{IN}, #{IN})"), 111 M_G("M(G(#{IN}, #{IN}), #{IN})"), 112 M_G_G("M(G(#{IN}, #{IN}), G(#{IN}, #{IN}))"); 113 114 String callExpr; 115 116 CallKind(String callExpr) { 117 this.callExpr = callExpr; 118 } 119 120 121 @Override 122 public String expand(String optParameter) { 123 return callExpr; 124 } 125 } 126 127 enum DeclKind implements ComboParameter { 128 NONE(""), 129 ONE("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"), 130 TWO("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }\n" + 131 " #{TVARS[#M_IDX].I2} #{RET[#M_IDX].B} #M(#{ARG[#M_IDX].B} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"); 132 133 String declTemplate; 134 135 DeclKind(String declTemplate) { 136 this.declTemplate = declTemplate; 137 } 138 139 @Override 140 public String expand(String methName) { 141 return declTemplate.replaceAll("#M_IDX", methName.equals("M") ? "0" : "1") 142 .replaceAll("#M", methName); 143 144 } 145 } 146 147 static final String sourceTemplate = 148 "class Test {\n" + 149 " interface I1<X> { }\n" + 150 " interface I2<X> { }\n" + 151 " static class A<X> implements I1<X> { }\n" + 152 " static class B<X> implements I2<X> { }\n" + 153 " #{DECL[0].M}\n" + 154 " #{DECL[1].G}\n" + 155 " void test() {\n" + 156 " #{CALL};\n" + 157 " }\n" + 158 "}\n"; 159 160 public static void main(String... args) throws Exception { 161 new ComboTestHelper<TestUncheckedCalls>() 162 .withFilter(TestUncheckedCalls::arityFilter) 163 .withFilter(TestUncheckedCalls::declFilter) 164 .withFilter(TestUncheckedCalls::tvarFilter) 165 .withFilter(TestUncheckedCalls::inputExprFilter) 166 .withDimension("IN", (x, expr) -> x.inputExpressionKind = expr, InputExpressionKind.values()) 167 .withDimension("CALL", (x, expr) -> x.callKind = expr, CallKind.values()) 168 .withArrayDimension("DECL", (x, decl, idx) -> x.decls[idx] = x.new Decl(decl, idx), 2, DeclKind.values()) 169 .withArrayDimension("TVARS", (x, tvars, idx) -> x.typeVarsKinds[idx] = tvars, 2, TypeVarsKind.values()) 170 .withArrayDimension("RET", (x, ret, idx) -> x.returnKinds[idx] = ret, 2, TypeKind.values()) 171 .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKinds[idx] = arg, 2, TypeKind.values()) 172 .run(TestUncheckedCalls::new); 173 } 174 175 class Decl { 176 private DeclKind declKind; 177 private int index; 178 179 Decl(DeclKind declKind, int index) { 180 this.declKind = declKind; 181 this.index = index; 182 } 183 184 boolean hasKind(DeclKind declKind) { 185 return this.declKind == declKind; 186 } 187 188 boolean isGeneric() { 189 return typeVarsKind() == TypeVarsKind.Z_T; 190 } 191 192 TypeKind returnKind() { 193 return returnKinds[index]; 194 } 195 196 TypeKind argumentsKind() { 197 return argumentKinds[index]; 198 } 199 200 TypeVarsKind typeVarsKind() { 201 return typeVarsKinds[index]; 202 } 203 } 204 205 CallKind callKind; 206 InputExpressionKind inputExpressionKind; 207 TypeKind[] returnKinds = new TypeKind[2]; 208 TypeKind[] argumentKinds = new TypeKind[2]; 209 TypeVarsKind[] typeVarsKinds = new TypeVarsKind[2]; 210 Decl[] decls = new Decl[2]; 211 212 boolean arityFilter() { 213 return (callKind == CallKind.M || !decls[1].hasKind(DeclKind.NONE)) && 214 !decls[0].hasKind(DeclKind.NONE); 215 } 216 217 boolean declFilter() { 218 return Stream.of(decls) 219 .filter(d -> d.hasKind(DeclKind.NONE)) 220 .flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind(), d.typeVarsKind())) 221 .noneMatch((Enum<? extends Enum<?>> tk) -> tk.ordinal() != 0); 222 } 223 224 boolean tvarFilter() { 225 return Stream.of(decls) 226 .filter(d -> !d.hasKind(DeclKind.NONE)) 227 .filter(d -> !d.isGeneric()) 228 .flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind())) 229 .noneMatch(TypeKind::hasTypeVars); 230 } 231 232 boolean inputExprFilter() { 233 return (inputExpressionKind != InputExpressionKind.B && inputExpressionKind != InputExpressionKind.B_STRING) || 234 Stream.of(decls).allMatch(d -> d.declKind == DeclKind.TWO); 235 } 236 237 @Override 238 public void doWork() throws Throwable { 239 newCompilationTask() 240 .withSourceFromTemplate(sourceTemplate) 241 .analyze(this::check); 242 } 243 244 void check(Result<Iterable<? extends Element>> result) { 245 if (result.hasErrors()) { 246 fail("compiler error:\n" + 247 result.compilationInfo()); 248 } 249 } 250 }