1 /* 2 * Copyright (c) 2012, 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 7192246 8006694 8129962 27 * @summary Automatic test for checking correctness of default super/this resolution 28 * temporarily workaround combo tests are causing time out in several platforms 29 * @library /tools/javac/lib 30 * @modules jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.code 32 * jdk.compiler/com.sun.tools.javac.comp 33 * jdk.compiler/com.sun.tools.javac.main 34 * jdk.compiler/com.sun.tools.javac.tree 35 * jdk.compiler/com.sun.tools.javac.util 36 * @build combo.ComboTestHelper 37 * @run main TestDefaultSuperCall 38 */ 39 40 import java.io.IOException; 41 import java.util.ArrayList; 42 import java.util.List; 43 44 import combo.ComboInstance; 45 import combo.ComboParameter; 46 import combo.ComboTask.Result; 47 import combo.ComboTestHelper; 48 49 public class TestDefaultSuperCall extends ComboInstance<TestDefaultSuperCall> { 50 51 enum InterfaceKind implements ComboParameter { 52 DEFAULT("interface A extends B { default void m() { } }"), 53 ABSTRACT("interface A extends B { void m(); }"), 54 NONE("interface A extends B { }"); 55 56 String interfaceStr; 57 InterfaceKind(String interfaceStr)58 InterfaceKind(String interfaceStr) { 59 this.interfaceStr = interfaceStr; 60 } 61 methodDefined()62 boolean methodDefined() { 63 return this == DEFAULT; 64 } 65 66 @Override expand(String optParameter)67 public String expand(String optParameter) { 68 return interfaceStr; 69 } 70 } 71 72 enum PruneKind implements ComboParameter { 73 NO_PRUNE("interface C { }"), 74 PRUNE("interface C extends A { }"); 75 methodDefined(InterfaceKind ik)76 boolean methodDefined(InterfaceKind ik) { 77 return this == PRUNE && 78 ik.methodDefined(); 79 } 80 81 String interfaceStr; 82 PruneKind(String interfaceStr)83 PruneKind(String interfaceStr) { 84 this.interfaceStr = interfaceStr; 85 } 86 87 @Override expand(String optParameter)88 public String expand(String optParameter) { 89 return interfaceStr; 90 } 91 } 92 93 enum QualifierKind implements ComboParameter { 94 DIRECT_1("C"), 95 DIRECT_2("A"), 96 INDIRECT("B"), 97 UNRELATED("E"), 98 ENCLOSING_1("name0"), 99 ENCLOSING_2("name1"); 100 101 String qualifierStr; 102 QualifierKind(String qualifierStr)103 QualifierKind(String qualifierStr) { 104 this.qualifierStr = qualifierStr; 105 } 106 isEnclosing()107 boolean isEnclosing() { 108 return this == ENCLOSING_1 || 109 this == ENCLOSING_2; 110 } 111 allowSuperCall(InterfaceKind ik, PruneKind pk)112 boolean allowSuperCall(InterfaceKind ik, PruneKind pk) { 113 switch (this) { 114 case DIRECT_1: 115 return pk.methodDefined(ik); 116 case DIRECT_2: 117 return ik.methodDefined() && pk == PruneKind.NO_PRUNE; 118 default: 119 return false; 120 } 121 } 122 123 @Override expand(String optParameter)124 public String expand(String optParameter) { 125 return qualifierStr; 126 } 127 } 128 129 enum ExprKind implements ComboParameter { 130 THIS("this"), 131 SUPER("super"); 132 133 String exprStr; 134 ExprKind(String exprStr)135 ExprKind(String exprStr) { 136 this.exprStr = exprStr; 137 } 138 139 @Override expand(String optParameter)140 public String expand(String optParameter) { 141 return exprStr; 142 } 143 } 144 145 enum ElementKind implements ComboParameter { 146 INTERFACE("interface name#CURR { #BODY }", true), 147 INTERFACE_EXTENDS("interface name#CURR extends A, C { #BODY }", true), 148 CLASS("class name#CURR { #BODY }", false), 149 CLASS_EXTENDS("abstract class name#CURR implements A, C { #BODY }", false), 150 STATIC_CLASS("static class name#CURR { #BODY }", true), 151 STATIC_CLASS_EXTENDS("abstract static class name#CURR implements A, C { #BODY }", true), 152 ANON_CLASS("new Object() { #BODY };", false), 153 METHOD("void test() { #BODY }", false), 154 STATIC_METHOD("static void test() { #BODY }", true), 155 DEFAULT_METHOD("default void test() { #BODY }", false); 156 157 String templateDecl; 158 boolean isStatic; 159 ElementKind(String templateDecl, boolean isStatic)160 ElementKind(String templateDecl, boolean isStatic) { 161 this.templateDecl = templateDecl; 162 this.isStatic = isStatic; 163 } 164 isClassDecl()165 boolean isClassDecl() { 166 switch(this) { 167 case METHOD: 168 case STATIC_METHOD: 169 case DEFAULT_METHOD: 170 return false; 171 default: 172 return true; 173 } 174 } 175 isAllowedEnclosing(ElementKind ek, boolean isTop)176 boolean isAllowedEnclosing(ElementKind ek, boolean isTop) { 177 switch (this) { 178 case CLASS: 179 case CLASS_EXTENDS: 180 //class is implicitly static inside interface, so skip this combo 181 return ek.isClassDecl() && 182 ek != INTERFACE && ek != INTERFACE_EXTENDS; 183 case ANON_CLASS: 184 return !ek.isClassDecl(); 185 case METHOD: 186 return ek == CLASS || ek == CLASS_EXTENDS || 187 ek == STATIC_CLASS || ek == STATIC_CLASS_EXTENDS || 188 ek == ANON_CLASS; 189 case INTERFACE: 190 case INTERFACE_EXTENDS: 191 case STATIC_CLASS: 192 case STATIC_CLASS_EXTENDS: 193 case STATIC_METHOD: 194 return (isTop && (ek == CLASS || ek == CLASS_EXTENDS)) || 195 ek == STATIC_CLASS || ek == STATIC_CLASS_EXTENDS; 196 case DEFAULT_METHOD: 197 return ek == INTERFACE || ek == INTERFACE_EXTENDS; 198 default: 199 throw new AssertionError("Bad enclosing element kind" + this); 200 } 201 } 202 isAllowedTop()203 boolean isAllowedTop() { 204 switch (this) { 205 case CLASS: 206 case CLASS_EXTENDS: 207 case INTERFACE: 208 case INTERFACE_EXTENDS: 209 return true; 210 default: 211 return false; 212 } 213 } 214 hasSuper()215 boolean hasSuper() { 216 return this == INTERFACE_EXTENDS || 217 this == STATIC_CLASS_EXTENDS || 218 this == CLASS_EXTENDS; 219 } 220 221 @Override expand(String optParameter)222 public String expand(String optParameter) { 223 int nextDepth = new Integer(optParameter) + 1; 224 String replStr = (nextDepth <= 4) ? 225 String.format("#{ELEM[%d].%d}", nextDepth, nextDepth) : 226 "#{QUAL}.#{EXPR}.#{METH}();"; 227 return templateDecl 228 .replaceAll("#CURR", optParameter) 229 .replaceAll("#BODY", replStr); 230 } 231 } 232 233 static class Shape { 234 235 List<ElementKind> enclosingElements; 236 List<String> enclosingNames; 237 List<String> elementsWithMethod; 238 Shape(ElementKind... elements)239 Shape(ElementKind... elements) { 240 enclosingElements = new ArrayList<>(); 241 enclosingNames = new ArrayList<>(); 242 elementsWithMethod = new ArrayList<>(); 243 int count = 0; 244 String prevName = null; 245 for (ElementKind ek : elements) { 246 String name = "name"+count++; 247 if (ek.isStatic) { 248 enclosingElements = new ArrayList<>(); 249 enclosingNames = new ArrayList<>(); 250 } 251 if (ek.isClassDecl()) { 252 enclosingElements.add(ek); 253 enclosingNames.add(name); 254 } else { 255 elementsWithMethod.add(prevName); 256 } 257 prevName = name; 258 } 259 } 260 } 261 main(String... args)262 public static void main(String... args) throws Exception { 263 new ComboTestHelper<TestDefaultSuperCall>() 264 .withFilter(TestDefaultSuperCall::filterBadTopElement) 265 .withFilter(TestDefaultSuperCall::filterBadIntermediateElement) 266 .withFilter(TestDefaultSuperCall::filterBadTerminalElement) 267 .withDimension("INTF1", (x, ik) -> x.ik = ik, InterfaceKind.values()) 268 .withDimension("INTF2", (x, pk) -> x.pk = pk, PruneKind.values()) 269 .withArrayDimension("ELEM", (x, elem, idx) -> x.elements[idx] = elem, 5, ElementKind.values()) 270 .withDimension("QUAL", (x, qk) -> x.qk = qk, QualifierKind.values()) 271 .withDimension("EXPR", (x, ek) -> x.ek = ek, ExprKind.values()) 272 .run(TestDefaultSuperCall::new); 273 } 274 275 InterfaceKind ik; 276 PruneKind pk; 277 ElementKind[] elements = new ElementKind[5]; 278 QualifierKind qk; 279 ExprKind ek; 280 filterBadTopElement()281 boolean filterBadTopElement() { 282 return elements[0].isAllowedTop(); 283 } 284 filterBadIntermediateElement()285 boolean filterBadIntermediateElement() { 286 for (int i = 1 ; i < 4 ; i++) { 287 if (!elements[i].isAllowedEnclosing(elements[i - 1], i == 1)) { 288 return false; 289 } 290 } 291 return true; 292 } 293 filterBadTerminalElement()294 boolean filterBadTerminalElement() { 295 return elements[4].isAllowedEnclosing(elements[3], false) && !elements[4].isClassDecl(); 296 } 297 298 String template = "interface E {}\n" + 299 "interface B { }\n" + 300 "#{INTF1}\n" + 301 "#{INTF2}\n" + 302 "#{ELEM[0].0}"; 303 304 @Override doWork()305 public void doWork() throws IOException { 306 newCompilationTask() 307 .withSourceFromTemplate(template, this::methodName) 308 .analyze(this::check); 309 } 310 methodName(String parameterName)311 ComboParameter methodName(String parameterName) { 312 switch (parameterName) { 313 case "METH": 314 String methodName = ek == ExprKind.THIS ? "test" : "m"; 315 return new ComboParameter.Constant<String>(methodName); 316 default: 317 return null; 318 } 319 } 320 check(Result<?> res)321 void check(Result<?> res) { 322 Shape sh = new Shape(elements); 323 324 boolean errorExpected = false; 325 326 boolean badEnclosing = false; 327 boolean badThis = false; 328 boolean badSuper = false; 329 330 if (qk == QualifierKind.ENCLOSING_1 && 331 sh.enclosingNames.size() < 1) { 332 errorExpected |= true; 333 badEnclosing = true; 334 } 335 336 if (qk == QualifierKind.ENCLOSING_2 && 337 sh.enclosingNames.size() < 2) { 338 errorExpected |= true; 339 badEnclosing = true; 340 } 341 342 if (ek == ExprKind.THIS) { 343 boolean found = false; 344 for (int i = 0; i < sh.enclosingElements.size(); i++) { 345 if (sh.enclosingElements.get(i) == ElementKind.ANON_CLASS) continue; 346 if (sh.enclosingNames.get(i).equals(qk.qualifierStr)) { 347 found = sh.elementsWithMethod.contains(sh.enclosingNames.get(i)); 348 break; 349 } 350 } 351 errorExpected |= !found; 352 if (!found) { 353 badThis = true; 354 } 355 } 356 357 if (ek == ExprKind.SUPER) { 358 359 int lastIdx = sh.enclosingElements.size() - 1; 360 boolean found = lastIdx == -1 ? false : 361 sh.enclosingElements.get(lastIdx).hasSuper() && 362 qk.allowSuperCall(ik, pk); 363 364 errorExpected |= !found; 365 if (!found) { 366 badSuper = true; 367 } 368 } 369 370 if (res.hasErrors() != errorExpected) { 371 fail("Problem when compiling source:\n" + 372 res.compilationInfo() + 373 "\nenclosingElems: " + sh.enclosingElements + 374 "\nenclosingNames: " + sh.enclosingNames + 375 "\nelementsWithMethod: " + sh.elementsWithMethod + 376 "\nbad encl: " + badEnclosing + 377 "\nbad this: " + badThis + 378 "\nbad super: " + badSuper + 379 "\nqual kind: " + qk + 380 "\nfound error: " + res.hasErrors()); 381 } 382 } 383 } 384