mcimadamore@1060: /* mcimadamore@1060: * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. mcimadamore@1060: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mcimadamore@1060: * mcimadamore@1060: * This code is free software; you can redistribute it and/or modify it mcimadamore@1060: * under the terms of the GNU General Public License version 2 only, as mcimadamore@1060: * published by the Free Software Foundation. mcimadamore@1060: * mcimadamore@1060: * This code is distributed in the hope that it will be useful, but WITHOUT mcimadamore@1060: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mcimadamore@1060: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mcimadamore@1060: * version 2 for more details (a copy is included in the LICENSE file that mcimadamore@1060: * accompanied this code). mcimadamore@1060: * mcimadamore@1060: * You should have received a copy of the GNU General Public License version mcimadamore@1060: * 2 along with this work; if not, write to the Free Software Foundation, mcimadamore@1060: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mcimadamore@1060: * mcimadamore@1060: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA mcimadamore@1060: * or visit www.oracle.com if you need additional information or have any mcimadamore@1060: * questions. mcimadamore@1060: */ mcimadamore@1060: mcimadamore@1060: /* mcimadamore@1060: * @test mcimadamore@1060: * @bug 7046778 mcimadamore@1060: * @summary Project Coin: problem with diamond and member inner classes mcimadamore@1060: */ mcimadamore@1060: mcimadamore@1060: import com.sun.source.util.JavacTask; mcimadamore@1060: import java.net.URI; mcimadamore@1060: import java.util.Arrays; mcimadamore@1060: import javax.tools.Diagnostic; mcimadamore@1060: import javax.tools.JavaCompiler; mcimadamore@1060: import javax.tools.JavaFileObject; mcimadamore@1060: import javax.tools.SimpleJavaFileObject; mcimadamore@1060: import javax.tools.StandardJavaFileManager; mcimadamore@1060: import javax.tools.ToolProvider; mcimadamore@1060: mcimadamore@1060: public class DiamondAndInnerClassTest { mcimadamore@1060: mcimadamore@1060: static int checkCount = 0; mcimadamore@1060: mcimadamore@1060: enum TypeArgumentKind { mcimadamore@1060: NONE(""), mcimadamore@1060: STRING(""), mcimadamore@1060: INTEGER(""), mcimadamore@1060: DIAMOND("<>"); mcimadamore@1060: mcimadamore@1060: String typeargStr; mcimadamore@1060: mcimadamore@1060: private TypeArgumentKind(String typeargStr) { mcimadamore@1060: this.typeargStr = typeargStr; mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: boolean compatible(TypeArgumentKind that) { mcimadamore@1060: switch (this) { mcimadamore@1060: case NONE: return true; mcimadamore@1060: case STRING: return that != INTEGER; mcimadamore@1060: case INTEGER: return that != STRING; mcimadamore@1060: default: throw new AssertionError("Unexpected decl kind: " + this); mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: boolean compatible(ArgumentKind that) { mcimadamore@1060: switch (this) { mcimadamore@1060: case NONE: return true; mcimadamore@1060: case STRING: return that == ArgumentKind.STRING; mcimadamore@1060: case INTEGER: return that == ArgumentKind.INTEGER; mcimadamore@1060: default: throw new AssertionError("Unexpected decl kind: " + this); mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: enum ArgumentKind { mcimadamore@1060: OBJECT("(Object)null"), mcimadamore@1060: STRING("(String)null"), mcimadamore@1060: INTEGER("(Integer)null"); mcimadamore@1060: mcimadamore@1060: String argStr; mcimadamore@1060: mcimadamore@1060: private ArgumentKind(String argStr) { mcimadamore@1060: this.argStr = argStr; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: enum TypeQualifierArity { mcimadamore@1060: ONE(1, "A1#TA1"), mcimadamore@1060: TWO(2, "A1#TA1.A2#TA2"), mcimadamore@1060: THREE(3, "A1#TA1.A2#TA2.A3#TA3"); mcimadamore@1060: mcimadamore@1060: int n; mcimadamore@1060: String qualifierStr; mcimadamore@1060: mcimadamore@1060: private TypeQualifierArity(int n, String qualifierStr) { mcimadamore@1060: this.n = n; mcimadamore@1060: this.qualifierStr = qualifierStr; mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: String getType(TypeArgumentKind... typeArgumentKinds) { mcimadamore@1060: String res = qualifierStr; mcimadamore@1060: for (int i = 1 ; i <= typeArgumentKinds.length ; i++) { mcimadamore@1060: res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr); mcimadamore@1060: } mcimadamore@1060: return res; mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: boolean matches(InnerClassDeclArity innerClassDeclArity) { mcimadamore@1060: return n ==innerClassDeclArity.n; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: enum InnerClassDeclArity { mcimadamore@1060: ONE(1, "class A1 { A1(X x1) { } #B }"), mcimadamore@1060: TWO(2, "class A1 { class A2 { A2(X1 x1, X2 x2) { } #B } }"), mcimadamore@1060: THREE(3, "class A1 { class A2 { class A3 { A3(X1 x1, X2 x2, X3 x3) { } #B } } }"); mcimadamore@1060: mcimadamore@1060: int n; mcimadamore@1060: String classDeclStr; mcimadamore@1060: mcimadamore@1060: private InnerClassDeclArity(int n, String classDeclStr) { mcimadamore@1060: this.n = n; mcimadamore@1060: this.classDeclStr = classDeclStr; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: enum ArgumentListArity { mcimadamore@1060: ONE(1, "(#A1)"), mcimadamore@1060: TWO(2, "(#A1,#A2)"), mcimadamore@1060: THREE(3, "(#A1,#A2,#A3)"); mcimadamore@1060: mcimadamore@1060: int n; mcimadamore@1060: String argListStr; mcimadamore@1060: mcimadamore@1060: private ArgumentListArity(int n, String argListStr) { mcimadamore@1060: this.n = n; mcimadamore@1060: this.argListStr = argListStr; mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: String getArgs(ArgumentKind... argumentKinds) { mcimadamore@1060: String res = argListStr; mcimadamore@1060: for (int i = 1 ; i <= argumentKinds.length ; i++) { mcimadamore@1060: res = res.replace("#A" + i, argumentKinds[i-1].argStr); mcimadamore@1060: } mcimadamore@1060: return res; mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: boolean matches(InnerClassDeclArity innerClassDeclArity) { mcimadamore@1060: return n ==innerClassDeclArity.n; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: public static void main(String... args) throws Exception { mcimadamore@1060: mcimadamore@1060: //create default shared JavaCompiler - reused across multiple compilations mcimadamore@1060: JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); mcimadamore@1060: StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); mcimadamore@1060: mcimadamore@1060: for (InnerClassDeclArity innerClassDeclArity : InnerClassDeclArity.values()) { mcimadamore@1060: for (TypeQualifierArity declType : TypeQualifierArity.values()) { mcimadamore@1060: if (!declType.matches(innerClassDeclArity)) continue; mcimadamore@1060: for (TypeQualifierArity newClassType : TypeQualifierArity.values()) { mcimadamore@1060: if (!newClassType.matches(innerClassDeclArity)) continue; mcimadamore@1060: for (ArgumentListArity argList : ArgumentListArity.values()) { mcimadamore@1060: if (!argList.matches(innerClassDeclArity)) continue; mcimadamore@1060: for (TypeArgumentKind taDecl1 : TypeArgumentKind.values()) { mcimadamore@1060: boolean isDeclRaw = taDecl1 == TypeArgumentKind.NONE; mcimadamore@1060: //no diamond on decl site mcimadamore@1060: if (taDecl1 == TypeArgumentKind.DIAMOND) continue; mcimadamore@1060: for (TypeArgumentKind taSite1 : TypeArgumentKind.values()) { mcimadamore@1060: boolean isSiteRaw = taSite1 == TypeArgumentKind.NONE; mcimadamore@1060: //diamond only allowed on the last type qualifier mcimadamore@1060: if (taSite1 == TypeArgumentKind.DIAMOND && mcimadamore@1060: innerClassDeclArity != InnerClassDeclArity.ONE) continue; mcimadamore@1060: for (ArgumentKind arg1 : ArgumentKind.values()) { mcimadamore@1060: if (innerClassDeclArity == innerClassDeclArity.ONE) { mcimadamore@1060: new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType, mcimadamore@1060: argList, new TypeArgumentKind[] {taDecl1}, mcimadamore@1060: new TypeArgumentKind[] {taSite1}, new ArgumentKind[] {arg1}).run(comp, fm); mcimadamore@1060: continue; mcimadamore@1060: } mcimadamore@1060: for (TypeArgumentKind taDecl2 : TypeArgumentKind.values()) { mcimadamore@1060: //no rare types mcimadamore@1060: if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE)) continue; mcimadamore@1060: //no diamond on decl site mcimadamore@1060: if (taDecl2 == TypeArgumentKind.DIAMOND) continue; mcimadamore@1060: for (TypeArgumentKind taSite2 : TypeArgumentKind.values()) { mcimadamore@1060: //no rare types mcimadamore@1060: if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE)) continue; mcimadamore@1060: //diamond only allowed on the last type qualifier mcimadamore@1060: if (taSite2 == TypeArgumentKind.DIAMOND && mcimadamore@1060: innerClassDeclArity != InnerClassDeclArity.TWO) continue; mcimadamore@1060: for (ArgumentKind arg2 : ArgumentKind.values()) { mcimadamore@1060: if (innerClassDeclArity == innerClassDeclArity.TWO) { mcimadamore@1060: new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType, mcimadamore@1060: argList, new TypeArgumentKind[] {taDecl1, taDecl2}, mcimadamore@1060: new TypeArgumentKind[] {taSite1, taSite2}, mcimadamore@1060: new ArgumentKind[] {arg1, arg2}).run(comp, fm); mcimadamore@1060: continue; mcimadamore@1060: } mcimadamore@1060: for (TypeArgumentKind taDecl3 : TypeArgumentKind.values()) { mcimadamore@1060: //no rare types mcimadamore@1060: if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE)) continue; mcimadamore@1060: //no diamond on decl site mcimadamore@1060: if (taDecl3 == TypeArgumentKind.DIAMOND) continue; mcimadamore@1060: for (TypeArgumentKind taSite3 : TypeArgumentKind.values()) { mcimadamore@1060: //no rare types mcimadamore@1060: if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE)) continue; mcimadamore@1060: //diamond only allowed on the last type qualifier mcimadamore@1060: if (taSite3 == TypeArgumentKind.DIAMOND && mcimadamore@1060: innerClassDeclArity != InnerClassDeclArity.THREE) continue; mcimadamore@1060: for (ArgumentKind arg3 : ArgumentKind.values()) { mcimadamore@1060: if (innerClassDeclArity == innerClassDeclArity.THREE) { mcimadamore@1060: new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType, mcimadamore@1060: argList, new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3}, mcimadamore@1060: new TypeArgumentKind[] {taSite1, taSite2, taSite3}, mcimadamore@1060: new ArgumentKind[] {arg1, arg2, arg3}).run(comp, fm); mcimadamore@1060: continue; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: System.out.println("Total check executed: " + checkCount); mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: InnerClassDeclArity innerClassDeclArity; mcimadamore@1060: TypeQualifierArity declType; mcimadamore@1060: TypeQualifierArity siteType; mcimadamore@1060: ArgumentListArity argList; mcimadamore@1060: TypeArgumentKind[] declTypeArgumentKinds; mcimadamore@1060: TypeArgumentKind[] siteTypeArgumentKinds; mcimadamore@1060: ArgumentKind[] argumentKinds; mcimadamore@1060: JavaSource source; mcimadamore@1060: DiagnosticChecker diagChecker; mcimadamore@1060: mcimadamore@1060: DiamondAndInnerClassTest(InnerClassDeclArity innerClassDeclArity, mcimadamore@1060: TypeQualifierArity declType, TypeQualifierArity siteType, ArgumentListArity argList, mcimadamore@1060: TypeArgumentKind[] declTypeArgumentKinds, TypeArgumentKind[] siteTypeArgumentKinds, mcimadamore@1060: ArgumentKind[] argumentKinds) { mcimadamore@1060: this.innerClassDeclArity = innerClassDeclArity; mcimadamore@1060: this.declType = declType; mcimadamore@1060: this.siteType = siteType; mcimadamore@1060: this.argList = argList; mcimadamore@1060: this.declTypeArgumentKinds = declTypeArgumentKinds; mcimadamore@1060: this.siteTypeArgumentKinds = siteTypeArgumentKinds; mcimadamore@1060: this.argumentKinds = argumentKinds; mcimadamore@1060: this.source = new JavaSource(); mcimadamore@1060: this.diagChecker = new DiagnosticChecker(); mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: class JavaSource extends SimpleJavaFileObject { mcimadamore@1060: mcimadamore@1060: String bodyTemplate = "#D res = new #S#AL;"; mcimadamore@1060: mcimadamore@1060: String source; mcimadamore@1060: mcimadamore@1060: public JavaSource() { mcimadamore@1060: super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); mcimadamore@1060: source = innerClassDeclArity.classDeclStr.replace("#B", bodyTemplate) mcimadamore@1060: .replace("#D", declType.getType(declTypeArgumentKinds)) mcimadamore@1060: .replace("#S", siteType.getType(siteTypeArgumentKinds)) mcimadamore@1060: .replace("#AL", argList.getArgs(argumentKinds)); mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: @Override mcimadamore@1060: public CharSequence getCharContent(boolean ignoreEncodingErrors) { mcimadamore@1060: return source; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { mcimadamore@1060: JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, mcimadamore@1060: null, null, Arrays.asList(source)); mcimadamore@1060: try { mcimadamore@1060: ct.analyze(); mcimadamore@1060: } catch (Throwable ex) { jjg@1169: throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); mcimadamore@1060: } mcimadamore@1060: check(); mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: void check() { mcimadamore@1060: checkCount++; mcimadamore@1060: mcimadamore@1060: boolean errorExpected = false; mcimadamore@1060: mcimadamore@1060: TypeArgumentKind[] expectedArgKinds = new TypeArgumentKind[innerClassDeclArity.n]; mcimadamore@1060: mcimadamore@1060: for (int i = 0 ; i < innerClassDeclArity.n ; i++) { mcimadamore@1060: if (!declTypeArgumentKinds[i].compatible(siteTypeArgumentKinds[i])) { mcimadamore@1060: errorExpected = true; mcimadamore@1060: break; mcimadamore@1060: } mcimadamore@1060: expectedArgKinds[i] = siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND ? mcimadamore@1060: declTypeArgumentKinds[i] : siteTypeArgumentKinds[i]; mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: if (!errorExpected) { mcimadamore@1060: for (int i = 0 ; i < innerClassDeclArity.n ; i++) { mcimadamore@1060: //System.out.println("check " + expectedArgKinds[i] + " against " + argumentKinds[i]); mcimadamore@1060: if (!expectedArgKinds[i].compatible(argumentKinds[i])) { mcimadamore@1060: errorExpected = true; mcimadamore@1060: break; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: if (errorExpected != diagChecker.errorFound) { mcimadamore@1060: throw new Error("invalid diagnostics for source:\n" + mcimadamore@1060: source.getCharContent(true) + mcimadamore@1060: "\nFound error: " + diagChecker.errorFound + mcimadamore@1060: "\nExpected error: " + errorExpected); mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: mcimadamore@1060: static class DiagnosticChecker implements javax.tools.DiagnosticListener { mcimadamore@1060: mcimadamore@1060: boolean errorFound; mcimadamore@1060: mcimadamore@1060: public void report(Diagnostic diagnostic) { mcimadamore@1060: if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { mcimadamore@1060: errorFound = true; mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: } mcimadamore@1060: }