blob: ef7267cb9166d5c208ae96b5d420aebed42b9f18 [file] [log] [blame]
/*
* 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<TestUncheckedCalls> {
enum InputExpressionKind implements ComboParameter {
A("(A)null"),
A_STRING("(A<String>)null"),
B("(B)null"),
B_STRING("(B<String>)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<T>"),
C_STRING("#C<String>"),
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("<Z extends #C<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<X> { }\n" +
" interface I2<X> { }\n" +
" static class A<X> implements I1<X> { }\n" +
" static class B<X> implements I2<X> { }\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<TestUncheckedCalls>()
.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<Iterable<? extends Element>> result) {
if (result.hasErrors()) {
fail("compiler error:\n" +
result.compilationInfo());
}
}
}