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