1 /* 2 * Copyright (c) 2012, 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 package org.openjdk.tests.separate; 25 26 import java.util.*; 27 import java.io.StringWriter; 28 import java.io.PrintWriter; 29 30 public class SourceModel { 31 32 public static final String stdMethodName = "m"; 33 34 public static interface SourceProcessor { 35 // Called with a generated source file process(String name, String content)36 void process(String name, String content); 37 } 38 39 public static abstract class Element { 40 generate(PrintWriter pw)41 protected abstract void generate(PrintWriter pw); 42 toString()43 public String toString() { 44 StringWriter sw = new StringWriter(); 45 PrintWriter pw = new PrintWriter(sw); 46 generate(pw); 47 return sw.toString(); 48 } 49 } 50 51 public static class AccessFlag extends Element { 52 private String flag; 53 AccessFlag(String name)54 public AccessFlag(String name) { flag = name; } 55 generate(PrintWriter pw)56 protected void generate(PrintWriter pw) { 57 pw.print(flag); 58 } 59 toString()60 public String toString() { return flag; } 61 62 public static final AccessFlag PUBLIC = new AccessFlag("public"); 63 public static final AccessFlag PRIVATE = new AccessFlag("private"); 64 public static final AccessFlag PROTECTED = new AccessFlag("protected"); 65 public static final AccessFlag STATIC = new AccessFlag("static"); 66 public static final AccessFlag FINAL = new AccessFlag("final"); 67 public static final AccessFlag SYNCHRONIZED = new AccessFlag("synchronized"); 68 public static final AccessFlag VOLATILE = new AccessFlag("volatile"); 69 public static final AccessFlag NATIVE = new AccessFlag("native"); 70 public static final AccessFlag ABSTRACT = new AccessFlag("abstract"); 71 public static final AccessFlag STRICTFP = new AccessFlag("strictfp"); 72 public static final AccessFlag DEFAULT = new AccessFlag("default"); 73 } 74 75 public static class TypeParameter extends Element { 76 private String parameter; 77 TypeParameter(String str)78 public TypeParameter(String str) { 79 this.parameter = str; 80 } 81 generate(PrintWriter pw)82 protected void generate(PrintWriter pw) { 83 pw.print(parameter); 84 } 85 } 86 87 public static class TypeArgument extends Element { 88 private String argument; 89 TypeArgument(String str)90 public TypeArgument(String str) { 91 this.argument = str; 92 } 93 generate(PrintWriter pw)94 protected void generate(PrintWriter pw) { 95 pw.print(argument); 96 } 97 } 98 99 public static class MethodParameter extends Element { 100 private String type; 101 private String name; 102 MethodParameter(String type, String name)103 public MethodParameter(String type, String name) { 104 this.type = type; 105 this.name = name; 106 } 107 generate(PrintWriter pw)108 protected void generate(PrintWriter pw) { 109 pw.printf("%s %s", this.type, this.name); 110 } 111 toString()112 public String toString() { return type + " " + name; } 113 } 114 115 public static abstract class Type extends Element { 116 private String name; 117 private List<AccessFlag> accessFlags; 118 private List<TypeParameter> parameters; 119 private List<Extends> supertypes; 120 private List<Method> methods; 121 122 // methods from superclasses that are required for compilation 123 // (and thus will be present in stubs) 124 private Set<Method> methodDependencies; 125 private List<Type> typeDependencies; 126 private boolean fullCompilation; 127 Type(String name, List<AccessFlag> flags, List<TypeParameter> params, List<Extends> ifaces, List<Method> methods)128 protected Type(String name, 129 List<AccessFlag> flags, List<TypeParameter> params, 130 List<Extends> ifaces, List<Method> methods) { 131 this.name = name; 132 this.accessFlags = flags == null ? new ArrayList<>() : flags; 133 this.parameters = params == null ? new ArrayList<>() : params; 134 this.supertypes = ifaces == null ? new ArrayList<>() : ifaces; 135 this.methods = methods == null ? new ArrayList<>() : methods; 136 this.methodDependencies = new HashSet<>(); 137 this.typeDependencies = new ArrayList<>(); 138 } 139 getName()140 public String getName() { return this.name; } getAccessFlags()141 public List<AccessFlag> getAccessFlags() { return this.accessFlags; } getParameters()142 public List<TypeParameter> getParameters() { return this.parameters; } getSupertypes()143 public List<Extends> getSupertypes() { return this.supertypes; } getMethods()144 public List<Method> getMethods() { return this.methods; } methodDependencies()145 public Set<Method> methodDependencies() { 146 return this.methodDependencies; 147 } 148 getSuperclass()149 public Class getSuperclass() { return null; } setSuperClass(Extends supertype)150 protected abstract void setSuperClass(Extends supertype); 151 addSuperType(Extends sup)152 public void addSuperType(Extends sup) { 153 assert sup.getType() instanceof Interface : "Must be an interface"; 154 this.supertypes.add(sup); 155 } addSuperType(Interface iface)156 public void addSuperType(Interface iface) { 157 this.supertypes.add(new Extends(iface)); 158 } 159 addMethod(Method m)160 public void addMethod(Method m) { 161 this.methods.add(m); 162 } 163 addAccessFlag(AccessFlag f)164 public void addAccessFlag(AccessFlag f) { 165 this.accessFlags.add(f); 166 } 167 168 // Convenience method for creation. Parameters are interpreted 169 // according to their type. Class (or Extends with a Class type) is 170 // considered a superclass (only one allowed). TypeParameters are 171 // generic parameter names. Interface (or Extends with an Interface 172 // type) is an implemented supertype. Methods are methods (duh!). addComponent(Element p)173 protected void addComponent(Element p) { 174 if (p instanceof Class) { 175 setSuperClass(new Extends((Class)p)); 176 } else if (p instanceof Extends) { 177 Extends ext = (Extends)p; 178 if (ext.supertype instanceof Class) { 179 setSuperClass(ext); 180 } else if (ext.supertype instanceof Interface) { 181 addSuperType(ext); 182 } else { 183 assert false : "What is this thing?"; 184 } 185 } else if (p instanceof Interface) { 186 addSuperType((Interface)p); 187 } else if (p instanceof TypeParameter) { 188 this.parameters.add((TypeParameter)p); 189 } else if (p instanceof Method) { 190 addMethod((Method)p); 191 } else if (p instanceof AccessFlag) { 192 addAccessFlag((AccessFlag)p); 193 } else { 194 assert false : "What is this thing?"; 195 } 196 } 197 198 // Find and return the first method that has name 'name' findMethod(String name)199 public Method findMethod(String name) { 200 for (Method m : methods) { 201 if (m.name.equals(name)) { 202 return m; 203 } 204 } 205 return null; 206 } 207 addCompilationDependency(Type t)208 public void addCompilationDependency(Type t) { 209 typeDependencies.add(t); 210 } 211 addCompilationDependency(Method m)212 public void addCompilationDependency(Method m) { 213 methodDependencies.add(m); 214 } 215 isFullCompilation()216 public boolean isFullCompilation() { 217 return fullCompilation; 218 } 219 setFullCompilation(boolean fullCompilation)220 public void setFullCompilation(boolean fullCompilation) { 221 this.fullCompilation = fullCompilation; 222 } 223 224 // Convenience method for creating an Extends object using this 225 // class and specified type arguments. with(String .... args)226 public Extends with(String ... args) { 227 return new Extends(this, args); 228 } 229 generate(SourceProcessor sp)230 public abstract void generate(SourceProcessor sp); generateAsDependency( SourceProcessor sp, Set<Method> neededMethods)231 public abstract void generateAsDependency( 232 SourceProcessor sp, Set<Method> neededMethods); 233 generateName(PrintWriter pw)234 protected void generateName(PrintWriter pw) { 235 pw.print(this.name); 236 toJoinedString(this.parameters, ",", "<", ">", ""); 237 pw.print(toJoinedString(this.parameters, ",", "<", ">", "")); 238 pw.print(" "); 239 } 240 generateBody(PrintWriter pw, String superSpec)241 protected void generateBody(PrintWriter pw, String superSpec) { 242 pw.print(toJoinedString(this.supertypes, ",", superSpec + " ", " ", "")); 243 pw.println("{ "); 244 pw.print(toJoinedString(this.methods, "\n ", "\n ", "\n", "")); 245 pw.println("}"); 246 } 247 generateAccessFlags(PrintWriter pw)248 protected void generateAccessFlags(PrintWriter pw) { 249 pw.print(toJoinedString(this.accessFlags, " ", "", " ")); 250 } 251 generateBodyAsDependency( PrintWriter pw, Set<Method> neededMethods)252 protected void generateBodyAsDependency( 253 PrintWriter pw, Set<Method> neededMethods) { 254 pw.println(" {"); 255 for (Method m : this.methods) { 256 if (neededMethods.contains(m)) { 257 pw.print(" "); 258 m.generate(pw); 259 pw.println(); 260 } 261 } 262 pw.println("}"); 263 } 264 typeDependencies(boolean recursive)265 public Collection<Type> typeDependencies(boolean recursive) { 266 HashMap<String,Type> dependencies = new HashMap<>(); 267 Type superclass = getSuperclass(); 268 if (superclass != null) { 269 dependencies.put(superclass.getName(), superclass); 270 if (recursive) { 271 for (Type t : superclass.typeDependencies(true)) 272 dependencies.put(t.getName(), t); 273 } 274 } 275 for (Extends e : getSupertypes()) { 276 dependencies.put(e.getType().getName(), e.getType()); 277 if (recursive) { 278 for (Type t : e.getType().typeDependencies(true)) 279 dependencies.put(t.getName(), t); 280 } 281 } 282 // Do these last so that they override 283 for (Type t : this.typeDependencies) 284 dependencies.put(t.getName(), t); 285 return dependencies.values(); 286 } 287 } 288 289 public static class Class extends Type { 290 private Extends superClass; 291 Class(String name, List<AccessFlag> flags, List<TypeParameter> params, Extends sprClass, List<Extends> interfaces, List<Method> methods)292 public Class(String name, List<AccessFlag> flags, 293 List<TypeParameter> params, Extends sprClass, 294 List<Extends> interfaces, List<Method> methods) { 295 super(name, flags, params, interfaces, methods); 296 this.superClass = sprClass; 297 addAccessFlag(AccessFlag.PUBLIC); // should remove this 298 } 299 Class(String name, Element ... components)300 public Class(String name, Element ... components) { 301 super(name, null, null, null, null); 302 this.superClass = null; 303 304 for (Element p : components) { 305 addComponent(p); 306 } 307 addAccessFlag(AccessFlag.PUBLIC); // should remove this 308 } 309 isAbstract()310 public boolean isAbstract() { 311 for (AccessFlag flag : getAccessFlags()) { 312 if (flag == AccessFlag.ABSTRACT) { 313 return true; 314 } 315 } 316 return false; 317 } 318 319 @Override setSuperClass(Extends ext)320 public void setSuperClass(Extends ext) { 321 assert this.superClass == null : "Multiple superclasses defined"; 322 assert ext.getType() instanceof Class : "Must be a class"; 323 this.superClass = ext; 324 } 325 setSuperClass(Class c)326 public void setSuperClass(Class c) { 327 setSuperClass(new Extends(c)); 328 } 329 330 @Override getSuperclass()331 public Class getSuperclass() { 332 return superClass == null ? null : (Class)superClass.supertype; 333 } 334 generate(SourceProcessor processor)335 public void generate(SourceProcessor processor) { 336 StringWriter sw = new StringWriter(); 337 PrintWriter pw = new PrintWriter(sw); 338 generate(pw); 339 processor.process(getName(), sw.toString()); 340 } 341 generate(PrintWriter pw)342 public void generate(PrintWriter pw) { 343 generateAccessFlags(pw); 344 pw.print("class "); 345 generateName(pw); 346 if (superClass != null) { 347 pw.print("extends "); 348 superClass.generate(pw); 349 pw.print(" "); 350 } 351 generateBody(pw, "implements"); 352 } 353 generateAsDependency( SourceProcessor processor, Set<Method> neededMethods)354 public void generateAsDependency( 355 SourceProcessor processor, Set<Method> neededMethods) { 356 StringWriter sw = new StringWriter(); 357 PrintWriter pw = new PrintWriter(sw); 358 generateAccessFlags(pw); 359 pw.print("class "); 360 generateName(pw); 361 pw.print(" "); 362 generateBodyAsDependency(pw, neededMethods); 363 364 processor.process(getName(), sw.toString()); 365 } 366 } 367 368 public static class Interface extends Type { 369 Interface(String name, List<AccessFlag> flags, List<TypeParameter> params, List<Extends> interfaces, List<Method> methods)370 public Interface(String name, 371 List<AccessFlag> flags, List<TypeParameter> params, 372 List<Extends> interfaces, List<Method> methods) { 373 super(name, flags, params, interfaces, methods); 374 } 375 Interface(String name, Element ... components)376 public Interface(String name, Element ... components) { 377 super(name, null, null, null, null); 378 for (Element c : components) { 379 addComponent(c); 380 } 381 } 382 setSuperClass(Extends ext)383 protected void setSuperClass(Extends ext) { 384 assert false : "Interfaces cannot have Class supertypes"; 385 } 386 generate(SourceProcessor processor)387 public void generate(SourceProcessor processor) { 388 StringWriter sw = new StringWriter(); 389 PrintWriter pw = new PrintWriter(sw); 390 generate(pw); 391 processor.process(getName(), sw.toString()); 392 } 393 generate(PrintWriter pw)394 public void generate(PrintWriter pw) { 395 generateAccessFlags(pw); 396 pw.print("interface "); 397 generateName(pw); 398 pw.print(" "); 399 generateBody(pw, "extends"); 400 } 401 generateAsDependency( SourceProcessor processor, Set<Method> neededMethods)402 public void generateAsDependency( 403 SourceProcessor processor, Set<Method> neededMethods) { 404 StringWriter sw = new StringWriter(); 405 PrintWriter pw = new PrintWriter(sw); 406 407 generateAccessFlags(pw); 408 pw.print("interface "); 409 generateName(pw); 410 pw.print(" "); 411 generateBodyAsDependency(pw, neededMethods); 412 413 processor.process(getName(), sw.toString()); 414 } 415 } 416 417 /** 418 * Represents a type extension that might contain type arguments 419 */ 420 public static class Extends extends Element { 421 private final Type supertype; 422 private final List<TypeArgument> arguments; 423 getType()424 public Type getType() { return supertype; } getArguments()425 public List<TypeArgument> getArguments() { 426 return arguments; 427 } 428 Extends(Type supertype, String ... args)429 public Extends(Type supertype, String ... args) { 430 assert supertype != null : "Null supertype"; 431 this.supertype = supertype; 432 this.arguments = new ArrayList<>(); 433 for (String arg : args) { 434 this.arguments.add(new TypeArgument(arg)); 435 } 436 } 437 generate(PrintWriter pw)438 public void generate(PrintWriter pw) { 439 pw.print(supertype.getName()); 440 pw.print(toJoinedString(getArguments(), ",", "<", ">", "")); 441 } 442 } 443 444 public static abstract class Method extends Element { 445 private String name; 446 private String returnType; 447 private List<AccessFlag> accessFlags; 448 private List<MethodParameter> parameters; 449 private boolean emitSuppressWarnings; 450 Method(String ret, String name, Element ... params)451 protected Method(String ret, String name, Element ... params) { 452 this.name = name; 453 this.returnType = ret; 454 this.accessFlags = new ArrayList<>(); 455 this.parameters = new ArrayList<>(); 456 this.emitSuppressWarnings = false; 457 458 for (Element e : params) { 459 if (e instanceof MethodParameter) { 460 this.parameters.add((MethodParameter) e); 461 } else if (e instanceof AccessFlag) { 462 this.accessFlags.add((AccessFlag) e); 463 } 464 } 465 assert accessFlags.size() + parameters.size() == params.length : 466 "Non method parameters or access flags in constructor"; 467 } 468 getName()469 public String getName() { return this.name; } getReturnType()470 public String getReturnType() { return this.returnType; } getParameters()471 public List<MethodParameter> getParameters() { 472 return this.parameters; 473 } getAccessFlags()474 public List<AccessFlag> getAccessFlags() { 475 return this.accessFlags; 476 } getElements()477 public Element[] getElements() { 478 ArrayList<Element> elements = new ArrayList<>(); 479 elements.addAll(getParameters()); 480 elements.addAll(getAccessFlags()); 481 return elements.toArray(new Element[0]); 482 } 483 suppressWarnings()484 public void suppressWarnings() { this.emitSuppressWarnings = true; } 485 generateWarningSuppression(PrintWriter pw)486 public void generateWarningSuppression(PrintWriter pw) { 487 if (this.emitSuppressWarnings) { 488 pw.printf("@SuppressWarnings(\"unchecked\")\n "); 489 } 490 } 491 generateDecl(PrintWriter pw)492 protected void generateDecl(PrintWriter pw) { 493 generateWarningSuppression(pw); 494 pw.print(toJoinedString(this.accessFlags, " ", "", " ")); 495 pw.printf("%s %s(", returnType, name); 496 pw.print(toJoinedString(parameters, ",")); 497 pw.print(")"); 498 } 499 } 500 501 public static class AbstractMethod extends Method { AbstractMethod( String ret, String name, Element ... params)502 public AbstractMethod( 503 String ret, String name, Element ... params) { 504 super(ret, name, params); 505 this.getAccessFlags().add(AccessFlag.ABSTRACT); 506 } 507 generate(PrintWriter pw)508 public void generate(PrintWriter pw) { 509 generateDecl(pw); 510 pw.print(";"); 511 } 512 std()513 public static AbstractMethod std() { 514 return new AbstractMethod( 515 "int", SourceModel.stdMethodName, AccessFlag.PUBLIC); 516 } 517 } 518 519 public static class ConcreteMethod extends Method { 520 protected String body; 521 ConcreteMethod(String ret, String name, String body, Element ... params)522 public ConcreteMethod(String ret, String name, 523 String body, Element ... params) { 524 super(ret, name, params); 525 this.body = body; 526 } 527 generate(PrintWriter pw)528 public void generate(PrintWriter pw) { 529 generateDecl(pw); 530 pw.printf(" { %s }", this.body); 531 } 532 std(String value)533 public static ConcreteMethod std(String value) { 534 return new ConcreteMethod( 535 "int", SourceModel.stdMethodName, "return " + value + ";", 536 AccessFlag.PUBLIC); 537 } 538 } 539 540 // When the default method flag gets moved into the traditional 541 // access flags location, we can remove this class completely and 542 // use a ConcreteMethod with an AccessFlag("default") in the constructor 543 public static class DefaultMethod extends Method { 544 protected String body; 545 DefaultMethod(String ret, String name, String body, Element ... params)546 public DefaultMethod(String ret, String name, String body, 547 Element ... params) { 548 super(ret, name, params); 549 this.body = body; 550 this.getAccessFlags().add(AccessFlag.DEFAULT); 551 } 552 generate(PrintWriter pw)553 public void generate(PrintWriter pw) { 554 generateDecl(pw); 555 pw.printf(" { %s }", this.body); 556 } 557 std(String value)558 public static DefaultMethod std(String value) { 559 return new DefaultMethod( 560 "int", SourceModel.stdMethodName, "return " + value + ";"); 561 } 562 } 563 toJoinedString(List<T> list, String... p)564 private static <T> String toJoinedString(List<T> list, String... p) { 565 StringBuilder sb = new StringBuilder(); 566 String sep = ""; 567 String init = ""; 568 String end = ""; 569 String empty = null; 570 switch (p.length) { 571 case 4: 572 empty = p[3]; 573 /*fall-through*/ 574 case 3: 575 end = p[2]; 576 /*fall-through*/ 577 case 2: 578 init = p[1]; 579 /*fall-through*/ 580 case 1: 581 sep = p[0]; 582 break; 583 } 584 if (empty != null && list.isEmpty()) { 585 return empty; 586 } else { 587 sb.append(init); 588 for (T x : list) { 589 if (sb.length() != init.length()) { 590 sb.append(sep); 591 } 592 sb.append(x.toString()); 593 } 594 sb.append(end); 595 return sb.toString(); 596 } 597 } 598 } 599