1 /*
2  * Copyright (c) 2011, 2013, 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 7115052 8003280 8006694
27  * @summary Add lambda tests
28  *  Add parser support for method references
29  *  temporarily workaround combo tests are causing time out in several platforms
30  * @library ../lib
31  * @build JavacTestingAbstractThreadedTest
32  * @run main/othervm MethodReferenceParserTest
33  */
34 
35 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
36 // see JDK-8006746
37 
38 import java.net.URI;
39 import java.util.Arrays;
40 import javax.tools.Diagnostic;
41 import javax.tools.JavaFileObject;
42 import javax.tools.SimpleJavaFileObject;
43 import com.sun.source.util.JavacTask;
44 
45 public class MethodReferenceParserTest
46     extends JavacTestingAbstractThreadedTest
47     implements Runnable {
48 
49     enum ReferenceKind {
50         METHOD_REF("#Q::#Gm"),
51         CONSTRUCTOR_REF("#Q::#Gnew"),
52         FALSE_REF("min < max"),
53         ERR_SUPER("#Q::#Gsuper"),
54         ERR_METH0("#Q::#Gm()"),
55         ERR_METH1("#Q::#Gm(X)"),
56         ERR_CONSTR0("#Q::#Gnew()"),
57         ERR_CONSTR1("#Q::#Gnew(X)");
58 
59         String referenceTemplate;
60 
ReferenceKind(String referenceTemplate)61         ReferenceKind(String referenceTemplate) {
62             this.referenceTemplate = referenceTemplate;
63         }
64 
getReferenceString(QualifierKind qk, GenericKind gk)65         String getReferenceString(QualifierKind qk, GenericKind gk) {
66             return referenceTemplate
67                     .replaceAll("#Q", qk.qualifier)
68                     .replaceAll("#G", gk.typeParameters);
69         }
70 
erroneous()71         boolean erroneous() {
72             switch (this) {
73                 case ERR_SUPER:
74                 case ERR_METH0:
75                 case ERR_METH1:
76                 case ERR_CONSTR0:
77                 case ERR_CONSTR1:
78                     return true;
79                 default: return false;
80             }
81         }
82     }
83 
84     enum ContextKind {
85         ASSIGN("SAM s = #E;"),
86         METHOD("m(#E, i);");
87 
88         String contextTemplate;
89 
ContextKind(String contextTemplate)90         ContextKind(String contextTemplate) {
91             this.contextTemplate = contextTemplate;
92         }
93 
contextString(ExprKind ek, ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk)94         String contextString(ExprKind ek, ReferenceKind rk, QualifierKind qk,
95                 GenericKind gk, SubExprKind sk) {
96             return contextTemplate.replaceAll("#E", ek.expressionString(rk, qk, gk, sk));
97         }
98     }
99 
100     enum GenericKind {
101         NONE(""),
102         ONE("<X>"),
103         TWO("<X,Y>");
104 
105         String typeParameters;
106 
GenericKind(String typeParameters)107         GenericKind(String typeParameters) {
108             this.typeParameters = typeParameters;
109         }
110     }
111 
112     enum QualifierKind {
113         THIS("this"),
114         SUPER("super"),
115         NEW("new Foo()"),
116         METHOD("m()"),
117         FIELD("a.f"),
118         UBOUND_SIMPLE("A"),
119         UNBOUND_ARRAY1("int[]"),
120         UNBOUND_ARRAY2("A<G>[][]"),
121         UNBOUND_GENERIC1("A<X>"),
122         UNBOUND_GENERIC2("A<X, Y>"),
123         UNBOUND_GENERIC3("A<? extends X, ? super Y>"),
124         UNBOUND_GENERIC4("A<int[], short[][]>"),
125         NESTED_GENERIC1("A<A<X,Y>, A<X,Y>>"),
126         NESTED_GENERIC2("A<A<A<X,Y>,A<X,Y>>, A<A<X,Y>,A<X,Y>>>");
127 
128         String qualifier;
129 
QualifierKind(String qualifier)130         QualifierKind(String qualifier) {
131             this.qualifier = qualifier;
132         }
133     }
134 
135     enum ExprKind {
136         NONE("#R::S"),
137         SINGLE_PAREN1("(#R#S)"),
138         SINGLE_PAREN2("(#R)#S"),
139         DOUBLE_PAREN1("((#R#S))"),
140         DOUBLE_PAREN2("((#R)#S)"),
141         DOUBLE_PAREN3("((#R))#S");
142 
143         String expressionTemplate;
144 
ExprKind(String expressionTemplate)145         ExprKind(String expressionTemplate) {
146             this.expressionTemplate = expressionTemplate;
147         }
148 
expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk)149         String expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk) {
150             return expressionTemplate
151                     .replaceAll("#R", rk.getReferenceString(qk, gk))
152                     .replaceAll("#S", sk.subExpression);
153         }
154     }
155 
156     enum SubExprKind {
157         NONE(""),
158         SELECT_FIELD(".f"),
159         SELECT_METHOD(".f()"),
160         SELECT_NEW(".new Foo()"),
161         POSTINC("++"),
162         POSTDEC("--");
163 
164         String subExpression;
165 
SubExprKind(String subExpression)166         SubExprKind(String subExpression) {
167             this.subExpression = subExpression;
168         }
169     }
170 
main(String... args)171     public static void main(String... args) throws Exception {
172         for (ReferenceKind rk : ReferenceKind.values()) {
173             for (QualifierKind qk : QualifierKind.values()) {
174                 for (GenericKind gk : GenericKind.values()) {
175                     for (SubExprKind sk : SubExprKind.values()) {
176                         for (ExprKind ek : ExprKind.values()) {
177                             for (ContextKind ck : ContextKind.values()) {
178                                 pool.execute(new MethodReferenceParserTest(rk, qk, gk, sk, ek, ck));
179                             }
180                         }
181                     }
182                 }
183             }
184         }
185 
186         checkAfterExec();
187     }
188 
189     ReferenceKind rk;
190     QualifierKind qk;
191     GenericKind gk;
192     SubExprKind sk;
193     ExprKind ek;
194     ContextKind ck;
195     JavaSource source;
196     DiagnosticChecker diagChecker;
197 
MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek, ContextKind ck)198     MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek, ContextKind ck) {
199         this.rk = rk;
200         this.qk = qk;
201         this.gk = gk;
202         this.sk = sk;
203         this.ek = ek;
204         this.ck = ck;
205         this.source = new JavaSource();
206         this.diagChecker = new DiagnosticChecker();
207     }
208 
209     class JavaSource extends SimpleJavaFileObject {
210 
211         String template = "class Test {\n" +
212                           "   void test() {\n" +
213                           "      #C\n" +
214                           "   }" +
215                           "}";
216 
217         String source;
218 
JavaSource()219         public JavaSource() {
220             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
221             source = template.replaceAll("#C", ck.contextString(ek, rk, qk, gk, sk));
222         }
223 
224         @Override
getCharContent(boolean ignoreEncodingErrors)225         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
226             return source;
227         }
228     }
229 
230     @Override
run()231     public void run() {
232         JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
233                 null, null, Arrays.asList(source));
234         try {
235             ct.parse();
236         } catch (Throwable ex) {
237             processException(ex);
238             return;
239         }
240         check();
241     }
242 
check()243     void check() {
244         checkCount.incrementAndGet();
245 
246         if (diagChecker.errorFound != rk.erroneous()) {
247             throw new Error("invalid diagnostics for source:\n" +
248                 source.getCharContent(true) +
249                 "\nFound error: " + diagChecker.errorFound +
250                 "\nExpected error: " + rk.erroneous());
251         }
252     }
253 
254     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
255 
256         boolean errorFound;
257 
report(Diagnostic<? extends JavaFileObject> diagnostic)258         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
259             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
260                 errorFound = true;
261             }
262         }
263     }
264 
265 }
266