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