1 /*
2  * Copyright (c) 2011, 2015, 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 /*
25  * @test
26  * @bug 7030687
27  * @summary Diamond: compiler accepts erroneous code where diamond is used with non-generic inner class
28  * @modules jdk.compiler
29  */
30 
31 import com.sun.source.util.JavacTask;
32 import java.net.URI;
33 import java.util.Arrays;
34 import javax.tools.Diagnostic;
35 import javax.tools.JavaCompiler;
36 import javax.tools.JavaFileObject;
37 import javax.tools.SimpleJavaFileObject;
38 import javax.tools.StandardJavaFileManager;
39 import javax.tools.ToolProvider;
40 
41 public class ParserTest {
42 
43     enum TypeArgumentKind {
44         NONE(""),
45         EXPLICIT("<String>"),
46         DIAMOND("<>");
47 
48         String typeargStr;
49 
TypeArgumentKind(String typeargStr)50         private TypeArgumentKind(String typeargStr) {
51             this.typeargStr = typeargStr;
52         }
53     }
54 
55     enum TypeQualifierArity {
56         ONE(1, "A1#TA1"),
57         TWO(2, "A1#TA1.A2#TA2"),
58         THREE(3, "A1#TA1.A2#TA2.A3#TA3"),
59         FOUR(4, "A1#TA1.A2#TA2.A3#TA3.A4#TA4");
60 
61         int n;
62         String qualifierStr;
63 
TypeQualifierArity(int n, String qualifierStr)64         private TypeQualifierArity(int n, String qualifierStr) {
65             this.n = n;
66             this.qualifierStr = qualifierStr;
67         }
68 
getType(TypeArgumentKind... typeArgumentKinds)69         String getType(TypeArgumentKind... typeArgumentKinds) {
70             String res = qualifierStr;
71             for (int i = 1 ; i <= typeArgumentKinds.length ; i++) {
72                 res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr);
73             }
74             return res;
75         }
76     }
77 
main(String... args)78     public static void main(String... args) throws Exception {
79 
80         //create default shared JavaCompiler - reused across multiple compilations
81         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
82         try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
83 
84             for (TypeQualifierArity arity : TypeQualifierArity.values()) {
85                 for (TypeArgumentKind tak1 : TypeArgumentKind.values()) {
86                     if (arity == TypeQualifierArity.ONE) {
87                         new ParserTest(arity, tak1).run(comp, fm);
88                         continue;
89                     }
90                     for (TypeArgumentKind tak2 : TypeArgumentKind.values()) {
91                         if (arity == TypeQualifierArity.TWO) {
92                             new ParserTest(arity, tak1, tak2).run(comp, fm);
93                             continue;
94                         }
95                         for (TypeArgumentKind tak3 : TypeArgumentKind.values()) {
96                             if (arity == TypeQualifierArity.THREE) {
97                                 new ParserTest(arity, tak1, tak2, tak3).run(comp, fm);
98                                 continue;
99                             }
100                             for (TypeArgumentKind tak4 : TypeArgumentKind.values()) {
101                                 new ParserTest(arity, tak1, tak2, tak3, tak4).run(comp, fm);
102                             }
103                         }
104                     }
105                 }
106             }
107         }
108     }
109 
110     TypeQualifierArity qualifierArity;
111     TypeArgumentKind[] typeArgumentKinds;
112     JavaSource source;
113     DiagnosticChecker diagChecker;
114 
ParserTest(TypeQualifierArity qualifierArity, TypeArgumentKind... typeArgumentKinds)115     ParserTest(TypeQualifierArity qualifierArity, TypeArgumentKind... typeArgumentKinds) {
116         this.qualifierArity = qualifierArity;
117         this.typeArgumentKinds = typeArgumentKinds;
118         this.source = new JavaSource();
119         this.diagChecker = new DiagnosticChecker();
120     }
121 
122     class JavaSource extends SimpleJavaFileObject {
123 
124         String template = "class Test {\n" +
125                               "R res = new #T();\n" +
126                           "}\n";
127 
128         String source;
129 
JavaSource()130         public JavaSource() {
131             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
132             source = template.replace("#T", qualifierArity.getType(typeArgumentKinds));
133         }
134 
135         @Override
getCharContent(boolean ignoreEncodingErrors)136         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
137             return source;
138         }
139     }
140 
run(JavaCompiler tool, StandardJavaFileManager fm)141     void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
142         JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
143                 null, null, Arrays.asList(source));
144         ct.parse();
145         check();
146     }
147 
check()148     void check() {
149 
150         boolean errorExpected = false;
151 
152         for (int i = 0 ; i < qualifierArity.n - 1 ; i++) {
153             if (typeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
154                 errorExpected = true;
155                 break;
156             }
157         }
158 
159         if (errorExpected != diagChecker.errorFound) {
160             throw new Error("invalid diagnostics for source:\n" +
161                 source.getCharContent(true) +
162                 "\nFound error: " + diagChecker.errorFound +
163                 "\nExpected error: " + errorExpected);
164         }
165     }
166 
167     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
168 
169         boolean errorFound;
170 
report(Diagnostic<? extends JavaFileObject> diagnostic)171         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
172             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
173                 errorFound = true;
174             }
175         }
176     }
177 }
178