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