949N/A/*
949N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
949N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
949N/A *
949N/A * This code is free software; you can redistribute it and/or modify it
949N/A * under the terms of the GNU General Public License version 2 only, as
949N/A * published by the Free Software Foundation.
949N/A *
949N/A * This code is distributed in the hope that it will be useful, but WITHOUT
949N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
949N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
949N/A * version 2 for more details (a copy is included in the LICENSE file that
949N/A * accompanied this code).
949N/A *
949N/A * You should have received a copy of the GNU General Public License version
949N/A * 2 along with this work; if not, write to the Free Software Foundation,
949N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
949N/A *
949N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
949N/A * or visit www.oracle.com if you need additional information or have any
949N/A * questions.
949N/A */
949N/A
949N/A/*
949N/A * @test
992N/A * @bug 7030150 7039931
949N/A * @summary Type inference for generic instance creation failed for formal type parameter
949N/A */
949N/A
949N/Aimport com.sun.source.util.JavacTask;
949N/Aimport java.net.URI;
949N/Aimport java.util.Arrays;
949N/Aimport javax.tools.Diagnostic;
949N/Aimport javax.tools.JavaCompiler;
949N/Aimport javax.tools.JavaFileObject;
949N/Aimport javax.tools.SimpleJavaFileObject;
949N/Aimport javax.tools.StandardJavaFileManager;
949N/Aimport javax.tools.ToolProvider;
949N/A
949N/Apublic class GenericConstructorAndDiamondTest {
949N/A
949N/A enum BoundKind {
949N/A NO_BOUND(""),
949N/A STRING_BOUND("extends String"),
949N/A INTEGER_BOUND("extends Integer");
949N/A
949N/A String boundStr;
949N/A
949N/A private BoundKind(String boundStr) {
949N/A this.boundStr = boundStr;
949N/A }
949N/A
949N/A boolean matches(TypeArgumentKind tak) {
949N/A switch (tak) {
949N/A case NONE: return true;
949N/A case STRING: return this != INTEGER_BOUND;
949N/A case INTEGER: return this != STRING_BOUND;
949N/A default: return false;
949N/A }
949N/A }
949N/A }
949N/A
949N/A enum ConstructorKind {
949N/A NON_GENERIC("Foo(Object o) {}"),
949N/A GENERIC_NO_BOUND("<T> Foo(T t) {}"),
949N/A GENERIC_STRING_BOUND("<T extends String> Foo(T t) {}"),
949N/A GENERIC_INTEGER_BOUND("<T extends Integer> Foo(T t) {}");
949N/A
949N/A String constrStr;
949N/A
949N/A private ConstructorKind(String constrStr) {
949N/A this.constrStr = constrStr;
949N/A }
949N/A
949N/A boolean matches(ArgumentKind ak) {
949N/A switch (ak) {
949N/A case STRING: return this != GENERIC_INTEGER_BOUND;
949N/A case INTEGER: return this != GENERIC_STRING_BOUND;
949N/A default: return false;
949N/A }
949N/A }
949N/A }
949N/A
949N/A enum TypeArgArity {
949N/A ONE(1),
949N/A TWO(2),
949N/A THREE(3);
949N/A
949N/A int n;
949N/A
949N/A private TypeArgArity(int n) {
949N/A this.n = n;
949N/A }
949N/A }
949N/A
949N/A enum TypeArgumentKind {
949N/A NONE(""),
949N/A STRING("String"),
949N/A INTEGER("Integer");
949N/A
949N/A String typeargStr;
949N/A
949N/A private TypeArgumentKind(String typeargStr) {
949N/A this.typeargStr = typeargStr;
949N/A }
949N/A
949N/A String getArgs(TypeArgArity arity) {
949N/A if (this == NONE) return "";
949N/A else {
949N/A StringBuilder buf = new StringBuilder();
949N/A String sep = "";
949N/A for (int i = 0 ; i < arity.n ; i++) {
949N/A buf.append(sep);
949N/A buf.append(typeargStr);
949N/A sep = ",";
949N/A }
949N/A return "<" + buf.toString() + ">";
949N/A }
949N/A }
949N/A
949N/A boolean matches(ArgumentKind ak) {
949N/A switch (ak) {
949N/A case STRING: return this != INTEGER;
949N/A case INTEGER: return this != STRING;
949N/A default: return false;
949N/A }
949N/A }
992N/A
992N/A boolean matches(TypeArgumentKind other) {
992N/A switch (other) {
992N/A case STRING: return this != INTEGER;
992N/A case INTEGER: return this != STRING;
992N/A default: return true;
992N/A }
992N/A }
949N/A }
949N/A
949N/A enum ArgumentKind {
949N/A STRING("\"\""),
949N/A INTEGER("1");
949N/A
949N/A String argStr;
949N/A
949N/A private ArgumentKind(String argStr) {
949N/A this.argStr = argStr;
949N/A }
949N/A }
949N/A
949N/A public static void main(String... args) throws Exception {
949N/A
949N/A //create default shared JavaCompiler - reused across multiple compilations
949N/A JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
949N/A StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
949N/A
949N/A for (BoundKind boundKind : BoundKind.values()) {
949N/A for (ConstructorKind constructorKind : ConstructorKind.values()) {
949N/A for (TypeArgumentKind declArgKind : TypeArgumentKind.values()) {
949N/A for (TypeArgArity arity : TypeArgArity.values()) {
949N/A for (TypeArgumentKind useArgKind : TypeArgumentKind.values()) {
992N/A for (TypeArgumentKind diamondArgKind : TypeArgumentKind.values()) {
992N/A for (ArgumentKind argKind : ArgumentKind.values()) {
992N/A new GenericConstructorAndDiamondTest(boundKind, constructorKind,
992N/A declArgKind, arity, useArgKind, diamondArgKind, argKind).run(comp, fm);
992N/A }
949N/A }
949N/A }
949N/A }
949N/A }
949N/A }
949N/A }
949N/A }
949N/A
949N/A BoundKind boundKind;
949N/A ConstructorKind constructorKind;
949N/A TypeArgumentKind declTypeArgumentKind;
949N/A TypeArgArity useTypeArgArity;
949N/A TypeArgumentKind useTypeArgumentKind;
992N/A TypeArgumentKind diamondTypeArgumentKind;
949N/A ArgumentKind argumentKind;
949N/A JavaSource source;
949N/A DiagnosticChecker diagChecker;
949N/A
949N/A GenericConstructorAndDiamondTest(BoundKind boundKind, ConstructorKind constructorKind,
949N/A TypeArgumentKind declTypeArgumentKind, TypeArgArity useTypeArgArity,
992N/A TypeArgumentKind useTypeArgumentKind, TypeArgumentKind diamondTypeArgumentKind,
992N/A ArgumentKind argumentKind) {
949N/A this.boundKind = boundKind;
949N/A this.constructorKind = constructorKind;
949N/A this.declTypeArgumentKind = declTypeArgumentKind;
949N/A this.useTypeArgArity = useTypeArgArity;
949N/A this.useTypeArgumentKind = useTypeArgumentKind;
992N/A this.diamondTypeArgumentKind = diamondTypeArgumentKind;
949N/A this.argumentKind = argumentKind;
949N/A this.source = new JavaSource();
949N/A this.diagChecker = new DiagnosticChecker();
949N/A }
949N/A
949N/A class JavaSource extends SimpleJavaFileObject {
949N/A
949N/A String template = "class Foo<X #BK> {\n" +
949N/A "#CK\n" +
949N/A "}\n" +
949N/A "class Test {\n" +
949N/A "void test() {\n" +
992N/A "Foo#TA1 f = new #TA2 Foo<#TA3>(#A);\n" +
949N/A "}\n" +
949N/A "}\n";
949N/A
949N/A String source;
949N/A
949N/A public JavaSource() {
949N/A super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
949N/A source = template.replace("#BK", boundKind.boundStr).
949N/A replace("#CK", constructorKind.constrStr)
949N/A .replace("#TA1", declTypeArgumentKind.getArgs(TypeArgArity.ONE))
949N/A .replace("#TA2", useTypeArgumentKind.getArgs(useTypeArgArity))
992N/A .replace("#TA3", diamondTypeArgumentKind.typeargStr)
949N/A .replace("#A", argumentKind.argStr);
949N/A }
949N/A
949N/A @Override
949N/A public CharSequence getCharContent(boolean ignoreEncodingErrors) {
949N/A return source;
949N/A }
949N/A }
949N/A
949N/A void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
949N/A JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
949N/A null, null, Arrays.asList(source));
949N/A ct.analyze();
949N/A check();
949N/A }
949N/A
949N/A void check() {
949N/A boolean badActual = !constructorKind.matches(argumentKind);
949N/A
949N/A boolean badArity = constructorKind != ConstructorKind.NON_GENERIC &&
949N/A useTypeArgumentKind != TypeArgumentKind.NONE &&
949N/A useTypeArgArity != TypeArgArity.ONE;
949N/A
949N/A boolean badMethodTypeArg = constructorKind != ConstructorKind.NON_GENERIC &&
949N/A !useTypeArgumentKind.matches(argumentKind);
949N/A
992N/A boolean badExplicitParams = (useTypeArgumentKind != TypeArgumentKind.NONE &&
992N/A diamondTypeArgumentKind == TypeArgumentKind.NONE) ||
992N/A !boundKind.matches(diamondTypeArgumentKind);
949N/A
992N/A boolean badGenericType = !boundKind.matches(declTypeArgumentKind) ||
992N/A !diamondTypeArgumentKind.matches(declTypeArgumentKind);
992N/A
992N/A boolean shouldFail = badActual || badArity ||
992N/A badMethodTypeArg || badExplicitParams || badGenericType;
949N/A
949N/A if (shouldFail != diagChecker.errorFound) {
949N/A throw new Error("invalid diagnostics for source:\n" +
949N/A source.getCharContent(true) +
949N/A "\nFound error: " + diagChecker.errorFound +
949N/A "\nExpected error: " + shouldFail);
949N/A }
949N/A }
949N/A
949N/A static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
949N/A
949N/A boolean errorFound;
949N/A
949N/A public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
949N/A if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
949N/A errorFound = true;
949N/A }
949N/A }
949N/A }
949N/A}