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 */ 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 38 void process(String name, String content); 39 } 40 41 public static abstract class Element { 42 43 protected abstract void generate(PrintWriter pw); 44 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 56 public AccessFlag(String name) { flag = name; } 57 58 protected void generate(PrintWriter pw) { 59 pw.print(flag); 60 } 61 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 80 public TypeParameter(String str) { 81 this.parameter = str; 82 } 83 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 92 public TypeArgument(String str) { 93 this.argument = str; 94 } 95 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 105 public MethodParameter(String type, String name) { 106 this.type = type; 107 this.name = name; 108 } 109 110 protected void generate(PrintWriter pw) { 111 pw.printf("%s %s", this.type, this.name); 112 } 113 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 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 } 140 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 } 149 150 public Class getSuperclass() { return null; } 151 protected abstract void setSuperClass(Extends supertype); 152 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 } 160 161 public void addMethod(Method m) { 162 this.methods.add(m); 163 } 164 165 public void addAccessFlag(AccessFlag f) { 166 this.accessFlags.add(f); 167 } 168 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 } 198 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 } 208 209 public void addCompilationDependency(Type t) { 210 typeDependencies.add(t); 211 } 212 213 public void addCompilationDependency(Method m) { 214 methodDependencies.add(m); 215 } 216 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 } 222 223 public abstract void generate(SourceProcessor sp); 224 public abstract void generateAsDependency( 225 SourceProcessor sp, Set<Method> neededMethods); 226 227 protected void generateName(PrintWriter pw) { 228 pw.print(this.name); 229 StringJoiner joiner = new StringJoiner(",", "<", ">").setEmptyValue(""); 230 this.parameters.stream().map(Element::toString).forEach(joiner::add); 231 pw.print(joiner.toString()); 232 pw.print(" "); 233 } 234 235 protected void generateBody(PrintWriter pw, String superSpec) { 236 StringJoiner joiner = new StringJoiner(",", superSpec + " ", " ") 237 .setEmptyValue(""); 238 supertypes.stream().map(Element::toString).forEach(joiner::add); 239 pw.print(joiner.toString()); 240 pw.println("{ "); 241 joiner = new StringJoiner("\n ", "\n ", "\n").setEmptyValue(""); 242 methods.stream().map(Element::toString).forEach(joiner::add); 243 pw.print(joiner.toString()); 244 pw.println("}"); 245 } 246 247 protected void generateAccessFlags(PrintWriter pw) { 248 StringJoiner joiner = new StringJoiner(" ", "", " "); 249 accessFlags.stream().map(AccessFlag::toString).forEach(joiner::add); 250 pw.print(joiner.toString()); 251 } 252 253 protected void generateBodyAsDependency( 254 PrintWriter pw, Set<Method> neededMethods) { 255 pw.println(" {"); 256 for (Method m : this.methods) { 257 if (neededMethods.contains(m)) { 258 pw.print(" "); 259 m.generate(pw); 260 pw.println(); 261 } 262 } 263 pw.println("}"); 264 } 265 266 public Collection<Type> typeDependencies() { 267 HashMap<String,Type> dependencies = new HashMap<>(); 268 Type superclass = getSuperclass(); 269 if (superclass != null) { 270 dependencies.put(superclass.getName(), superclass); 271 } 272 for (Extends e : getSupertypes()) 273 dependencies.put(e.getType().getName(), e.getType()); 274 // Do these last so that they override 275 for (Type t : this.typeDependencies) 276 dependencies.put(t.getName(), t); 277 return dependencies.values(); 278 } 279 } 280 281 public static class Class extends Type { 282 private Extends superClass; 283 284 public Class(String name, List<AccessFlag> flags, 285 List<TypeParameter> params, Extends sprClass, 286 List<Extends> interfaces, List<Method> methods) { 287 super(name, flags, params, interfaces, methods); 288 this.superClass = sprClass; 289 addAccessFlag(AccessFlag.PUBLIC); // should remove this 290 } 291 292 public Class(String name, Element ... components) { 293 super(name, null, null, null, null); 294 this.superClass = null; 295 296 for (Element p : components) { 297 addComponent(p); 298 } 299 addAccessFlag(AccessFlag.PUBLIC); // should remove this 300 } 301 302 public boolean isAbstract() { 303 for (AccessFlag flag : getAccessFlags()) { 304 if (flag == AccessFlag.ABSTRACT) { 305 return true; 306 } 307 } 308 return false; 309 } 310 311 @Override 312 public void setSuperClass(Extends ext) { 313 assert this.superClass == null : "Multiple superclasses defined"; 314 assert ext.getType() instanceof Class : "Must be a class"; 315 this.superClass = ext; 316 } 317 318 public void setSuperClass(Class c) { 319 setSuperClass(new Extends(c)); 320 } 321 322 @Override 323 public Class getSuperclass() { 324 return superClass == null ? null : (Class)superClass.supertype; 325 } 326 327 public void generate(SourceProcessor processor) { 328 StringWriter sw = new StringWriter(); 329 PrintWriter pw = new PrintWriter(sw); 330 generate(pw); 331 processor.process(getName(), sw.toString()); 332 } 333 334 public void generate(PrintWriter pw) { 335 generateAccessFlags(pw); 336 pw.print("class "); 337 generateName(pw); 338 if (superClass != null) { 339 pw.print("extends "); 340 superClass.generate(pw); 341 pw.print(" "); 342 } 343 generateBody(pw, "implements"); 344 } 345 346 public void generateAsDependency( 347 SourceProcessor processor, Set<Method> neededMethods) { 348 StringWriter sw = new StringWriter(); 349 PrintWriter pw = new PrintWriter(sw); 350 generateAccessFlags(pw); 351 pw.print("class "); 352 generateName(pw); 353 pw.print(" "); 354 generateBodyAsDependency(pw, neededMethods); 355 356 processor.process(getName(), sw.toString()); 357 } 358 } 359 360 public static class Interface extends Type { 361 362 public Interface(String name, 363 List<AccessFlag> flags, List<TypeParameter> params, 364 List<Extends> interfaces, List<Method> methods) { 365 super(name, flags, params, interfaces, methods); 366 } 367 368 public Interface(String name, Element ... components) { 369 super(name, null, null, null, null); 370 for (Element c : components) { 371 addComponent(c); 372 } 373 } 374 375 protected void setSuperClass(Extends ext) { 376 assert false : "Interfaces cannot have Class supertypes"; 377 } 378 379 public void generate(SourceProcessor processor) { 380 StringWriter sw = new StringWriter(); 381 PrintWriter pw = new PrintWriter(sw); 382 generate(pw); 383 processor.process(getName(), sw.toString()); 384 } 385 386 public void generate(PrintWriter pw) { 387 generateAccessFlags(pw); 388 pw.print("interface "); 389 generateName(pw); 390 pw.print(" "); 391 generateBody(pw, "extends"); 392 } 393 394 public void generateAsDependency( 395 SourceProcessor processor, Set<Method> neededMethods) { 396 StringWriter sw = new StringWriter(); 397 PrintWriter pw = new PrintWriter(sw); 398 399 generateAccessFlags(pw); 400 pw.print("interface "); 401 generateName(pw); 402 pw.print(" "); 403 generateBodyAsDependency(pw, neededMethods); 404 405 processor.process(getName(), sw.toString()); 406 } 407 } 408 409 /** 410 * Represents a type extension that might contain type arguments 411 */ 412 public static class Extends extends Element { 413 private final Type supertype; 414 private final List<TypeArgument> arguments; 415 416 public Type getType() { return supertype; } 417 public List<TypeArgument> getArguments() { 418 return arguments; 419 } 420 421 public Extends(Type supertype, String ... args) { 422 assert supertype != null : "Null supertype"; 423 this.supertype = supertype; 424 this.arguments = new ArrayList<>(); 425 for (String arg : args) { 426 this.arguments.add(new TypeArgument(arg)); 427 } 428 } 429 430 public void generate(PrintWriter pw) { 431 StringJoiner joiner = new StringJoiner(",", "<", ">").setEmptyValue(""); 432 getArguments().stream().map(Element::toString).forEach(joiner::add); 433 pw.print(supertype.getName()); 434 pw.print(joiner.toString()); 435 } 436 } 437 438 public static abstract class Method extends Element { 439 private String name; 440 private String returnType; 441 private List<AccessFlag> accessFlags; 442 private List<MethodParameter> parameters; 443 private boolean emitSuppressWarnings; 444 445 protected Method(String ret, String name, Element ... params) { 446 this.name = name; 447 this.returnType = ret; 448 this.accessFlags = new ArrayList<>(); 449 this.parameters = new ArrayList<>(); 450 this.emitSuppressWarnings = false; 451 452 Arrays.asList(params).stream() 453 .filter(x -> x instanceof MethodParameter) 454 .map(x -> (MethodParameter)x) 455 .forEach(this.parameters::add); 456 Arrays.asList(params).stream() 457 .filter(x -> x instanceof AccessFlag) 458 .map(x -> (AccessFlag)x) 459 .forEach(this.accessFlags::add); 460 assert accessFlags.size() + parameters.size() == params.length : 461 "Non method parameters or access flags in constructor"; 462 } 463 464 public String getName() { return this.name; } 465 public String getReturnType() { return this.returnType; } 466 public List<MethodParameter> getParameters() { 467 return this.parameters; 468 } 469 public List<AccessFlag> getAccessFlags() { 470 return this.accessFlags; 471 } 472 public Element[] getElements() { 473 ArrayList<Element> elements = new ArrayList<>(); 474 getParameters().stream().forEach(elements::add); 475 getAccessFlags().stream().forEach(elements::add); 476 return elements.toArray(new Element[elements.size()]); 477 } 478 479 public void suppressWarnings() { this.emitSuppressWarnings = true; } 480 481 public void generateWarningSuppression(PrintWriter pw) { 482 if (this.emitSuppressWarnings) { 483 pw.printf("@SuppressWarnings(\"unchecked\")\n "); 484 } 485 } 486 487 protected void generateDecl(PrintWriter pw) { 488 generateWarningSuppression(pw); 489 StringJoiner joiner = new StringJoiner(" ", "", " "); 490 accessFlags.stream().map(AccessFlag::toString).forEach(joiner::add); 491 pw.print(joiner.toString()); 492 joiner = new StringJoiner(","); 493 pw.printf("%s %s(", returnType, name); 494 parameters.stream().map(MethodParameter::toString).forEach(joiner::add); 495 pw.print(joiner.toString()); 496 pw.print(")"); 497 } 498 } 499 500 public static class AbstractMethod extends Method { 501 public AbstractMethod( 502 String ret, String name, Element ... params) { 503 super(ret, name, params); 504 this.getAccessFlags().add(AccessFlag.ABSTRACT); 505 } 506 507 public void generate(PrintWriter pw) { 508 generateDecl(pw); 509 pw.print(";"); 510 } 511 512 public static AbstractMethod std() { 513 return new AbstractMethod( 514 "int", SourceModel.stdMethodName, AccessFlag.PUBLIC); 515 } 516 } 517 518 public static class ConcreteMethod extends Method { 519 protected String body; 520 521 public ConcreteMethod(String ret, String name, 522 String body, Element ... params) { 523 super(ret, name, params); 524 this.body = body; 525 } 526 527 public void generate(PrintWriter pw) { 528 generateDecl(pw); 529 pw.printf(" { %s }", this.body); 530 } 531 532 public static ConcreteMethod std(String value) { 533 return new ConcreteMethod( 534 "int", SourceModel.stdMethodName, "return " + value + ";", 535 AccessFlag.PUBLIC); 536 } 537 } 538 539 // When the default method flag gets moved into the traditional 540 // access flags location, we can remove this class completely and 541 // use a ConcreteMethod with an AccessFlag("default") in the constructor 542 public static class DefaultMethod extends Method { 543 protected String body; 544 545 public DefaultMethod(String ret, String name, String body, 546 Element ... params) { 547 super(ret, name, params); 548 this.body = body; 549 this.getAccessFlags().add(AccessFlag.DEFAULT); 550 } 551 552 public void generate(PrintWriter pw) { 553 generateDecl(pw); 554 pw.printf(" { %s }", this.body); 555 } 556 557 public static DefaultMethod std(String value) { 558 return new DefaultMethod( 559 "int", SourceModel.stdMethodName, "return " + value + ";"); 560 } 561 } 562 }