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