/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import combo.ComboInstance; import combo.ComboParameter; import combo.ComboTask.Result; import combo.ComboTestHelper; import javax.lang.model.element.Element; import java.util.stream.Stream; /* * @test * @bug 8176534 * @summary Missing check against target-type during applicability inference * @library /tools/javac/lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.comp * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper * * @run main TestUncheckedCalls */ public class TestUncheckedCalls extends ComboInstance { enum InputExpressionKind implements ComboParameter { A("(A)null"), A_STRING("(A)null"), B("(B)null"), B_STRING("(B)null"); String inputExpr; InputExpressionKind(String inputExpr) { this.inputExpr = inputExpr; } @Override public String expand(String optParameter) { return inputExpr; } } enum TypeKind implements ComboParameter { Z("Z"), C_T("#C"), C_STRING("#C"), C("#C"); String typeTemplate; TypeKind(String typeTemplate) { this.typeTemplate = typeTemplate; } boolean hasTypeVars() { return this == Z || this == C_T; } @Override public String expand(String className) { return typeTemplate.replaceAll("#C", className); } } enum TypeVarsKind implements ComboParameter { NONE("", "Object"), Z_T(", T>", "Z"); String typeVarsTemplate; String paramString; TypeVarsKind(String typeVarsTemplate, String paramString) { this.typeVarsTemplate = typeVarsTemplate; this.paramString = paramString; } @Override public String expand(String className) { if (className.equals("Z")) { return paramString; } else { return typeVarsTemplate.replaceAll("#C", className); } } } enum CallKind implements ComboParameter { M("M(#{IN}, #{IN})"), M_G("M(G(#{IN}, #{IN}), #{IN})"), M_G_G("M(G(#{IN}, #{IN}), G(#{IN}, #{IN}))"); String callExpr; CallKind(String callExpr) { this.callExpr = callExpr; } @Override public String expand(String optParameter) { return callExpr; } } enum DeclKind implements ComboParameter { NONE(""), ONE("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"), TWO("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }\n" + " #{TVARS[#M_IDX].I2} #{RET[#M_IDX].B} #M(#{ARG[#M_IDX].B} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"); String declTemplate; DeclKind(String declTemplate) { this.declTemplate = declTemplate; } @Override public String expand(String methName) { return declTemplate.replaceAll("#M_IDX", methName.equals("M") ? "0" : "1") .replaceAll("#M", methName); } } static final String sourceTemplate = "class Test {\n" + " interface I1 { }\n" + " interface I2 { }\n" + " static class A implements I1 { }\n" + " static class B implements I2 { }\n" + " #{DECL[0].M}\n" + " #{DECL[1].G}\n" + " void test() {\n" + " #{CALL};\n" + " }\n" + "}\n"; public static void main(String... args) throws Exception { new ComboTestHelper() .withFilter(TestUncheckedCalls::arityFilter) .withFilter(TestUncheckedCalls::declFilter) .withFilter(TestUncheckedCalls::tvarFilter) .withFilter(TestUncheckedCalls::inputExprFilter) .withDimension("IN", (x, expr) -> x.inputExpressionKind = expr, InputExpressionKind.values()) .withDimension("CALL", (x, expr) -> x.callKind = expr, CallKind.values()) .withArrayDimension("DECL", (x, decl, idx) -> x.decls[idx] = x.new Decl(decl, idx), 2, DeclKind.values()) .withArrayDimension("TVARS", (x, tvars, idx) -> x.typeVarsKinds[idx] = tvars, 2, TypeVarsKind.values()) .withArrayDimension("RET", (x, ret, idx) -> x.returnKinds[idx] = ret, 2, TypeKind.values()) .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKinds[idx] = arg, 2, TypeKind.values()) .run(TestUncheckedCalls::new); } class Decl { private DeclKind declKind; private int index; Decl(DeclKind declKind, int index) { this.declKind = declKind; this.index = index; } boolean hasKind(DeclKind declKind) { return this.declKind == declKind; } boolean isGeneric() { return typeVarsKind() == TypeVarsKind.Z_T; } TypeKind returnKind() { return returnKinds[index]; } TypeKind argumentsKind() { return argumentKinds[index]; } TypeVarsKind typeVarsKind() { return typeVarsKinds[index]; } } CallKind callKind; InputExpressionKind inputExpressionKind; TypeKind[] returnKinds = new TypeKind[2]; TypeKind[] argumentKinds = new TypeKind[2]; TypeVarsKind[] typeVarsKinds = new TypeVarsKind[2]; Decl[] decls = new Decl[2]; boolean arityFilter() { return (callKind == CallKind.M || !decls[1].hasKind(DeclKind.NONE)) && !decls[0].hasKind(DeclKind.NONE); } boolean declFilter() { return Stream.of(decls) .filter(d -> d.hasKind(DeclKind.NONE)) .flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind(), d.typeVarsKind())) .noneMatch(tk -> tk.ordinal() != 0); } boolean tvarFilter() { return Stream.of(decls) .filter(d -> !d.hasKind(DeclKind.NONE)) .filter(d -> !d.isGeneric()) .flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind())) .noneMatch(TypeKind::hasTypeVars); } boolean inputExprFilter() { return (inputExpressionKind != InputExpressionKind.B && inputExpressionKind != InputExpressionKind.B_STRING) || Stream.of(decls).allMatch(d -> d.declKind == DeclKind.TWO); } @Override public void doWork() throws Throwable { check(newCompilationTask() .withSourceFromTemplate(sourceTemplate) .analyze()); } void check(Result> result) { if (result.hasErrors()) { fail("compiler error:\n" + result.compilationInfo()); } } }