Thu, 24 Oct 2013 16:52:27 -0700
8027220: DefaultMethodsTest: Change test to match spec
Reviewed-by: ksrini
1 /*
2 * Copyright (c) 2012, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package org.openjdk.tests.separate;
28 import java.util.*;
29 import java.io.StringWriter;
30 import java.io.PrintWriter;
32 public class SourceModel {
34 public static final String stdMethodName = "m";
36 public static interface SourceProcessor {
37 // Called with a generated source file
38 void process(String name, String content);
39 }
41 public static abstract class Element {
43 protected abstract void generate(PrintWriter pw);
45 public String toString() {
46 StringWriter sw = new StringWriter();
47 PrintWriter pw = new PrintWriter(sw);
48 generate(pw);
49 return sw.toString();
50 }
51 };
53 public static class AccessFlag extends Element {
54 private String flag;
56 public AccessFlag(String name) { flag = name; }
58 protected void generate(PrintWriter pw) {
59 pw.print(flag);
60 }
62 public String toString() { return flag; }
64 public static final AccessFlag PUBLIC = new AccessFlag("public");
65 public static final AccessFlag PRIVATE = new AccessFlag("private");
66 public static final AccessFlag PROTECTED = new AccessFlag("protected");
67 public static final AccessFlag STATIC = new AccessFlag("static");
68 public static final AccessFlag FINAL = new AccessFlag("final");
69 public static final AccessFlag SYNCHRONIZED = new AccessFlag("synchronized");
70 public static final AccessFlag VOLATILE = new AccessFlag("volatile");
71 public static final AccessFlag NATIVE = new AccessFlag("native");
72 public static final AccessFlag ABSTRACT = new AccessFlag("abstract");
73 public static final AccessFlag STRICTFP = new AccessFlag("strictfp");
74 public static final AccessFlag DEFAULT = new AccessFlag("default");
75 }
77 public static class TypeParameter extends Element {
78 private String parameter;
80 public TypeParameter(String str) {
81 this.parameter = str;
82 }
84 protected void generate(PrintWriter pw) {
85 pw.print(parameter);
86 }
87 }
89 public static class TypeArgument extends Element {
90 private String argument;
92 public TypeArgument(String str) {
93 this.argument = str;
94 }
96 protected void generate(PrintWriter pw) {
97 pw.print(argument);
98 }
99 }
101 public static class MethodParameter extends Element {
102 private String type;
103 private String name;
105 public MethodParameter(String type, String name) {
106 this.type = type;
107 this.name = name;
108 }
110 protected void generate(PrintWriter pw) {
111 pw.printf("%s %s", this.type, this.name);
112 }
114 public String toString() { return type + " " + name; }
115 }
117 public static abstract class Type extends Element {
118 private String name;
119 private List<AccessFlag> accessFlags;
120 private List<TypeParameter> parameters;
121 private List<Extends> supertypes;
122 private List<Method> methods;
124 // methods from superclasses that are required for compilation
125 // (and thus will be present in stubs)
126 private Set<Method> methodDependencies;
127 private List<Type> typeDependencies;
129 protected Type(String name,
130 List<AccessFlag> flags, List<TypeParameter> params,
131 List<Extends> ifaces, List<Method> methods) {
132 this.name = name;
133 this.accessFlags = flags == null ? new ArrayList<>() : flags;
134 this.parameters = params == null ? new ArrayList<>() : params;
135 this.supertypes = ifaces == null ? new ArrayList<>() : ifaces;
136 this.methods = methods == null ? new ArrayList<>() : methods;
137 this.methodDependencies = new HashSet<>();
138 this.typeDependencies = new ArrayList<>();
139 }
141 public String getName() { return this.name; }
142 public List<AccessFlag> getAccessFlags() { return this.accessFlags; }
143 public List<TypeParameter> getParameters() { return this.parameters; }
144 public List<Extends> getSupertypes() { return this.supertypes; }
145 public List<Method> getMethods() { return this.methods; }
146 public Set<Method> methodDependencies() {
147 return this.methodDependencies;
148 }
150 public Class getSuperclass() { return null; }
151 protected abstract void setSuperClass(Extends supertype);
153 public void addSuperType(Extends sup) {
154 assert sup.getType() instanceof Interface : "Must be an interface";
155 this.supertypes.add(sup);
156 }
157 public void addSuperType(Interface iface) {
158 this.supertypes.add(new Extends(iface));
159 }
161 public void addMethod(Method m) {
162 this.methods.add(m);
163 }
165 public void addAccessFlag(AccessFlag f) {
166 this.accessFlags.add(f);
167 }
169 // Convenience method for creation. Parameters are interpreted
170 // according to their type. Class (or Extends with a Class type) is
171 // considered a superclass (only one allowed). TypeParameters are
172 // generic parameter names. Interface (or Extends with an Interface
173 // type) is an implemented supertype. Methods are methods (duh!).
174 protected void addComponent(Element p) {
175 if (p instanceof Class) {
176 setSuperClass(new Extends((Class)p));
177 } else if (p instanceof Extends) {
178 Extends ext = (Extends)p;
179 if (ext.supertype instanceof Class) {
180 setSuperClass(ext);
181 } else if (ext.supertype instanceof Interface) {
182 addSuperType(ext);
183 } else {
184 assert false : "What is this thing?";
185 }
186 } else if (p instanceof Interface) {
187 addSuperType((Interface)p);
188 } else if (p instanceof TypeParameter) {
189 this.parameters.add((TypeParameter)p);
190 } else if (p instanceof Method) {
191 addMethod((Method)p);
192 } else if (p instanceof AccessFlag) {
193 addAccessFlag((AccessFlag)p);
194 } else {
195 assert false : "What is this thing?";
196 }
197 }
199 // Find and return the first method that has name 'name'
200 public Method findMethod(String name) {
201 for (Method m : methods) {
202 if (m.name.equals(name)) {
203 return m;
204 }
205 }
206 return null;
207 }
209 public void addCompilationDependency(Type t) {
210 typeDependencies.add(t);
211 }
213 public void addCompilationDependency(Method m) {
214 methodDependencies.add(m);
215 }
217 // Convenience method for creating an Extends object using this
218 // class and specified type arguments.
219 public Extends with(String ... args) {
220 return new Extends(this, args);
221 }
223 public abstract void generate(SourceProcessor sp);
224 public abstract void generateAsDependency(
225 SourceProcessor sp, Set<Method> neededMethods);
227 protected void generateName(PrintWriter pw) {
228 pw.print(this.name);
229 toJoinedString(this.parameters, ",", "<", ">", "");
230 pw.print(toJoinedString(this.parameters, ",", "<", ">", ""));
231 pw.print(" ");
232 }
234 protected void generateBody(PrintWriter pw, String superSpec) {
235 pw.print(toJoinedString(this.supertypes, ",", superSpec + " ", " ", ""));
236 pw.println("{ ");
237 pw.print(toJoinedString(this.methods, "\n ", "\n ", "\n", ""));
238 pw.println("}");
239 }
241 protected void generateAccessFlags(PrintWriter pw) {
242 pw.print(toJoinedString(this.accessFlags, " ", "", " "));
243 }
245 protected void generateBodyAsDependency(
246 PrintWriter pw, Set<Method> neededMethods) {
247 pw.println(" {");
248 for (Method m : this.methods) {
249 if (neededMethods.contains(m)) {
250 pw.print(" ");
251 m.generate(pw);
252 pw.println();
253 }
254 }
255 pw.println("}");
256 }
258 public Collection<Type> typeDependencies() {
259 HashMap<String,Type> dependencies = new HashMap<>();
260 Type superclass = getSuperclass();
261 if (superclass != null) {
262 dependencies.put(superclass.getName(), superclass);
263 }
264 for (Extends e : getSupertypes())
265 dependencies.put(e.getType().getName(), e.getType());
266 // Do these last so that they override
267 for (Type t : this.typeDependencies)
268 dependencies.put(t.getName(), t);
269 return dependencies.values();
270 }
271 }
273 public static class Class extends Type {
274 private Extends superClass;
276 public Class(String name, List<AccessFlag> flags,
277 List<TypeParameter> params, Extends sprClass,
278 List<Extends> interfaces, List<Method> methods) {
279 super(name, flags, params, interfaces, methods);
280 this.superClass = sprClass;
281 addAccessFlag(AccessFlag.PUBLIC); // should remove this
282 }
284 public Class(String name, Element ... components) {
285 super(name, null, null, null, null);
286 this.superClass = null;
288 for (Element p : components) {
289 addComponent(p);
290 }
291 addAccessFlag(AccessFlag.PUBLIC); // should remove this
292 }
294 public boolean isAbstract() {
295 for (AccessFlag flag : getAccessFlags()) {
296 if (flag == AccessFlag.ABSTRACT) {
297 return true;
298 }
299 }
300 return false;
301 }
303 @Override
304 public void setSuperClass(Extends ext) {
305 assert this.superClass == null : "Multiple superclasses defined";
306 assert ext.getType() instanceof Class : "Must be a class";
307 this.superClass = ext;
308 }
310 public void setSuperClass(Class c) {
311 setSuperClass(new Extends(c));
312 }
314 @Override
315 public Class getSuperclass() {
316 return superClass == null ? null : (Class)superClass.supertype;
317 }
319 public void generate(SourceProcessor processor) {
320 StringWriter sw = new StringWriter();
321 PrintWriter pw = new PrintWriter(sw);
322 generate(pw);
323 processor.process(getName(), sw.toString());
324 }
326 public void generate(PrintWriter pw) {
327 generateAccessFlags(pw);
328 pw.print("class ");
329 generateName(pw);
330 if (superClass != null) {
331 pw.print("extends ");
332 superClass.generate(pw);
333 pw.print(" ");
334 }
335 generateBody(pw, "implements");
336 }
338 public void generateAsDependency(
339 SourceProcessor processor, Set<Method> neededMethods) {
340 StringWriter sw = new StringWriter();
341 PrintWriter pw = new PrintWriter(sw);
342 generateAccessFlags(pw);
343 pw.print("class ");
344 generateName(pw);
345 pw.print(" ");
346 generateBodyAsDependency(pw, neededMethods);
348 processor.process(getName(), sw.toString());
349 }
350 }
352 public static class Interface extends Type {
354 public Interface(String name,
355 List<AccessFlag> flags, List<TypeParameter> params,
356 List<Extends> interfaces, List<Method> methods) {
357 super(name, flags, params, interfaces, methods);
358 }
360 public Interface(String name, Element ... components) {
361 super(name, null, null, null, null);
362 for (Element c : components) {
363 addComponent(c);
364 }
365 }
367 protected void setSuperClass(Extends ext) {
368 assert false : "Interfaces cannot have Class supertypes";
369 }
371 public void generate(SourceProcessor processor) {
372 StringWriter sw = new StringWriter();
373 PrintWriter pw = new PrintWriter(sw);
374 generate(pw);
375 processor.process(getName(), sw.toString());
376 }
378 public void generate(PrintWriter pw) {
379 generateAccessFlags(pw);
380 pw.print("interface ");
381 generateName(pw);
382 pw.print(" ");
383 generateBody(pw, "extends");
384 }
386 public void generateAsDependency(
387 SourceProcessor processor, Set<Method> neededMethods) {
388 StringWriter sw = new StringWriter();
389 PrintWriter pw = new PrintWriter(sw);
391 generateAccessFlags(pw);
392 pw.print("interface ");
393 generateName(pw);
394 pw.print(" ");
395 generateBodyAsDependency(pw, neededMethods);
397 processor.process(getName(), sw.toString());
398 }
399 }
401 /**
402 * Represents a type extension that might contain type arguments
403 */
404 public static class Extends extends Element {
405 private final Type supertype;
406 private final List<TypeArgument> arguments;
408 public Type getType() { return supertype; }
409 public List<TypeArgument> getArguments() {
410 return arguments;
411 }
413 public Extends(Type supertype, String ... args) {
414 assert supertype != null : "Null supertype";
415 this.supertype = supertype;
416 this.arguments = new ArrayList<>();
417 for (String arg : args) {
418 this.arguments.add(new TypeArgument(arg));
419 }
420 }
422 public void generate(PrintWriter pw) {
423 pw.print(supertype.getName());
424 pw.print(toJoinedString(getArguments(), ",", "<", ">", ""));
425 }
426 }
428 public static abstract class Method extends Element {
429 private String name;
430 private String returnType;
431 private List<AccessFlag> accessFlags;
432 private List<MethodParameter> parameters;
433 private boolean emitSuppressWarnings;
435 protected Method(String ret, String name, Element ... params) {
436 this.name = name;
437 this.returnType = ret;
438 this.accessFlags = new ArrayList<>();
439 this.parameters = new ArrayList<>();
440 this.emitSuppressWarnings = false;
442 for (Element e : params) {
443 if (e instanceof MethodParameter) {
444 this.parameters.add((MethodParameter) e);
445 } else if (e instanceof AccessFlag) {
446 this.accessFlags.add((AccessFlag) e);
447 }
448 }
449 assert accessFlags.size() + parameters.size() == params.length :
450 "Non method parameters or access flags in constructor";
451 }
453 public String getName() { return this.name; }
454 public String getReturnType() { return this.returnType; }
455 public List<MethodParameter> getParameters() {
456 return this.parameters;
457 }
458 public List<AccessFlag> getAccessFlags() {
459 return this.accessFlags;
460 }
461 public Element[] getElements() {
462 ArrayList<Element> elements = new ArrayList<>();
463 elements.addAll(getParameters());
464 elements.addAll(getAccessFlags());
465 return elements.toArray(new Element[0]);
466 }
468 public void suppressWarnings() { this.emitSuppressWarnings = true; }
470 public void generateWarningSuppression(PrintWriter pw) {
471 if (this.emitSuppressWarnings) {
472 pw.printf("@SuppressWarnings(\"unchecked\")\n ");
473 }
474 }
476 protected void generateDecl(PrintWriter pw) {
477 generateWarningSuppression(pw);
478 pw.print(toJoinedString(this.accessFlags, " ", "", " "));
479 pw.printf("%s %s(", returnType, name);
480 pw.print(toJoinedString(parameters, ","));
481 pw.print(")");
482 }
483 }
485 public static class AbstractMethod extends Method {
486 public AbstractMethod(
487 String ret, String name, Element ... params) {
488 super(ret, name, params);
489 this.getAccessFlags().add(AccessFlag.ABSTRACT);
490 }
492 public void generate(PrintWriter pw) {
493 generateDecl(pw);
494 pw.print(";");
495 }
497 public static AbstractMethod std() {
498 return new AbstractMethod(
499 "int", SourceModel.stdMethodName, AccessFlag.PUBLIC);
500 }
501 }
503 public static class ConcreteMethod extends Method {
504 protected String body;
506 public ConcreteMethod(String ret, String name,
507 String body, Element ... params) {
508 super(ret, name, params);
509 this.body = body;
510 }
512 public void generate(PrintWriter pw) {
513 generateDecl(pw);
514 pw.printf(" { %s }", this.body);
515 }
517 public static ConcreteMethod std(String value) {
518 return new ConcreteMethod(
519 "int", SourceModel.stdMethodName, "return " + value + ";",
520 AccessFlag.PUBLIC);
521 }
522 }
524 // When the default method flag gets moved into the traditional
525 // access flags location, we can remove this class completely and
526 // use a ConcreteMethod with an AccessFlag("default") in the constructor
527 public static class DefaultMethod extends Method {
528 protected String body;
530 public DefaultMethod(String ret, String name, String body,
531 Element ... params) {
532 super(ret, name, params);
533 this.body = body;
534 this.getAccessFlags().add(AccessFlag.DEFAULT);
535 }
537 public void generate(PrintWriter pw) {
538 generateDecl(pw);
539 pw.printf(" { %s }", this.body);
540 }
542 public static DefaultMethod std(String value) {
543 return new DefaultMethod(
544 "int", SourceModel.stdMethodName, "return " + value + ";");
545 }
546 }
548 private static <T> String toJoinedString(List<T> list, String... p) {
549 StringBuilder sb = new StringBuilder();
550 String sep = "";
551 String init = "";
552 String end = "";
553 String empty = null;
554 switch (p.length) {
555 case 4:
556 empty = p[3];
557 /*fall-through*/
558 case 3:
559 end = p[2];
560 /*fall-through*/
561 case 2:
562 init = p[1];
563 /*fall-through*/
564 case 1:
565 sep = p[0];
566 break;
567 }
568 if (empty != null && list.isEmpty()) {
569 return empty;
570 } else {
571 sb.append(init);
572 for (T x : list) {
573 if (sb.length() != init.length()) {
574 sb.append(sep);
575 }
576 sb.append(x.toString());
577 }
578 sb.append(end);
579 return sb.toString();
580 }
581 }
582 }