test/tools/javac/6889255/T6889255.java

Thu, 25 Oct 2012 11:09:36 -0700

author
jjg
date
Thu, 25 Oct 2012 11:09:36 -0700
changeset 1374
c002fdee76fd
parent 554
9d9f26857129
child 1792
ec871c3e8337
permissions
-rw-r--r--

7200915: convert TypeTags from a series of small ints to an enum
Reviewed-by: jjg, mcimadamore
Contributed-by: vicente.romero@oracle.com

jjg@428 1 /*
jjg@1374 2 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
jjg@428 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@428 4 *
jjg@428 5 * This code is free software; you can redistribute it and/or modify it
jjg@428 6 * under the terms of the GNU General Public License version 2 only, as
jjg@428 7 * published by the Free Software Foundation.
jjg@428 8 *
jjg@428 9 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@428 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@428 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@428 12 * version 2 for more details (a copy is included in the LICENSE file that
jjg@428 13 * accompanied this code).
jjg@428 14 *
jjg@428 15 * You should have received a copy of the GNU General Public License version
jjg@428 16 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@428 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@428 18 *
ohair@554 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554 20 * or visit www.oracle.com if you need additional information or have any
ohair@554 21 * questions.
jjg@428 22 */
jjg@428 23
jjg@428 24 /*
jjg@428 25 * @test
jjg@428 26 * @bug 6889255
jjg@428 27 * @summary ClassReader does not read parameter names correctly
jjg@428 28 */
jjg@428 29
jjg@428 30 import java.io.*;
jjg@428 31 import java.util.*;
jjg@428 32 import javax.tools.StandardLocation;
jjg@428 33 import com.sun.tools.javac.code.Flags;
jjg@428 34 import com.sun.tools.javac.code.Kinds;
jjg@428 35 import com.sun.tools.javac.code.Scope;
jjg@428 36 import com.sun.tools.javac.code.Symbol.*;
jjg@428 37 import com.sun.tools.javac.code.Type;
jjg@428 38 import com.sun.tools.javac.code.Type.ClassType;
jjg@1374 39 import com.sun.tools.javac.code.TypeTag;
jjg@428 40 import com.sun.tools.javac.file.JavacFileManager;
jjg@428 41 import com.sun.tools.javac.jvm.ClassReader;
jjg@428 42 import com.sun.tools.javac.util.Context;
jjg@428 43 import com.sun.tools.javac.util.Names;
jjg@428 44
jjg@428 45 public class T6889255 {
jjg@428 46 boolean testInterfaces = true;
jjg@428 47 boolean testSyntheticMethods = true;
jjg@428 48
jjg@428 49 // The following enums control the generation of the test methods to be compiled.
jjg@428 50 enum GenericKind {
jjg@428 51 NOT_GENERIC,
jjg@428 52 GENERIC
jjg@428 53 };
jjg@428 54
jjg@428 55 enum ClassKind {
jjg@428 56 CLASS("Clss"),
jjg@428 57 INTERFACE("Intf"),
jjg@428 58 ENUM("Enum");
jjg@428 59 final String base;
jjg@428 60 ClassKind(String base) { this.base = base; }
jjg@428 61 };
jjg@428 62
jjg@428 63 enum NestedKind {
jjg@428 64 /** Declare methods inside the outermost container. */
jjg@428 65 NONE,
jjg@428 66 /** Declare methods inside a container with a 'static' modifier. */
jjg@428 67 NESTED,
jjg@428 68 /** Declare methods inside a container without a 'static' modifier. */
jjg@428 69 INNER,
jjg@428 70 /** Declare methods inside a local class in an initializer. */
jjg@428 71 INIT_LOCAL,
jjg@428 72 /** Declare methods inside an anonymous class in an initializer. */
jjg@428 73 INIT_ANON,
jjg@428 74 /** Declare methods inside a local class in a method. */
jjg@428 75 METHOD_LOCAL,
jjg@428 76 /** Declare methods inside an anonymous class in a method. */
jjg@428 77 METHOD_ANON
jjg@428 78 };
jjg@428 79
jjg@428 80 enum MethodKind {
jjg@428 81 ABSTRACT,
jjg@428 82 CONSTRUCTOR,
jjg@428 83 METHOD,
jjg@428 84 STATIC_METHOD,
jjg@428 85 BRIDGE_METHOD
jjg@428 86 };
jjg@428 87
jjg@428 88 enum FinalKind {
jjg@428 89 /** Method body does not reference external final variables. */
jjg@428 90 NO_FINAL,
jjg@428 91 /** Method body references external final variables. */
jjg@428 92 USE_FINAL
jjg@428 93 };
jjg@428 94
jjg@428 95 public static void main(String... args) throws Exception {
jjg@428 96 new T6889255().run();
jjg@428 97 }
jjg@428 98
jjg@428 99 void run() throws Exception {
jjg@428 100 genTest();
jjg@428 101
jjg@428 102 test("no-args", false);
jjg@428 103 test("g", true, "-g");
jjg@428 104
jjg@428 105 if (errors > 0)
jjg@428 106 throw new Exception(errors + " errors found");
jjg@428 107 }
jjg@428 108
jjg@428 109 /**
jjg@428 110 * Create a file containing lots of method definitions to be tested.
jjg@428 111 * There are 3 sets of nested loops that generate the methods.
jjg@428 112 * 1. The outermost set declares [generic] (class | interface | enum)
jjg@428 113 * 2. The middle set declares [(nested | inner | anon | local)] class
jjg@428 114 * 3. The innermost set declares
jjg@428 115 * [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope]
jjg@428 116 * Invalid combinations are filtered out.
jjg@428 117 */
jjg@428 118 void genTest() throws Exception {
jjg@428 119 BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));
jjg@428 120
jjg@428 121 // This interface is used to force bridge methods to be generated, by
jjg@428 122 // implementing its methods with subtypes of Object
jjg@428 123 out.write("interface Base {\n");
jjg@428 124 out.write(" Object base_m1(int i1);\n");
jjg@428 125 out.write(" Object base_m2(int i1);\n");
jjg@428 126 out.write("}\n");
jjg@428 127
jjg@428 128 int outerNum = 0;
jjg@428 129 // Outermost set of loops, to generate a top level container
jjg@428 130 for (GenericKind outerGenericKind: GenericKind.values()) {
jjg@428 131 for (ClassKind outerClassKind: ClassKind.values()) {
jjg@428 132 if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM)
jjg@428 133 continue;
jjg@428 134 String outerClassName = outerClassKind.base + (outerNum++);
jjg@428 135 String outerTypeArg = outerClassKind.toString().charAt(0) + "T";
jjg@428 136 if (outerClassKind == ClassKind.CLASS)
jjg@428 137 out.write("abstract ");
jjg@428 138 out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName);
jjg@428 139 if (outerGenericKind == GenericKind.GENERIC)
jjg@428 140 out.write("<" + outerTypeArg + ">");
jjg@428 141 if (outerClassKind == ClassKind.INTERFACE)
jjg@428 142 out.write(" extends Base");
jjg@428 143 else
jjg@428 144 out.write(" implements Base");
jjg@428 145 out.write(" {\n");
jjg@428 146 if (outerClassKind == ClassKind.ENUM) {
jjg@428 147 out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
jjg@428 148 out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n");
jjg@428 149 }
jjg@428 150 // Middle set of loops, to generate an optional nested container
jjg@428 151 int nestedNum = 0;
jjg@428 152 int methodNum = 0;
jjg@428 153 for (GenericKind nestedGenericKind: GenericKind.values()) {
jjg@428 154 nextNestedKind:
jjg@428 155 for (NestedKind nestedKind: NestedKind.values()) {
jjg@428 156 // if the nested kind is none, there is no point iterating over all
jjg@428 157 // nested generic kinds, so arbitarily limit it to just one kind
jjg@428 158 if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC)
jjg@428 159 continue;
jjg@428 160 if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
jjg@428 161 && nestedGenericKind == GenericKind.GENERIC)
jjg@428 162 continue;
jjg@428 163 String indent = " ";
jjg@428 164 boolean haveFinal = false;
jjg@428 165 switch (nestedKind) {
jjg@428 166 case METHOD_ANON: case METHOD_LOCAL:
jjg@428 167 if (outerClassKind == ClassKind.INTERFACE)
jjg@428 168 continue nextNestedKind;
jjg@428 169 out.write(indent + "void m" + + (nestedNum++) + "() {\n");
jjg@428 170 indent += " ";
jjg@428 171 out.write(indent + "final int fi1 = 0;\n");
jjg@428 172 haveFinal = true;
jjg@428 173 break;
jjg@428 174 case INIT_ANON: case INIT_LOCAL:
jjg@428 175 if (outerClassKind == ClassKind.INTERFACE)
jjg@428 176 continue nextNestedKind;
jjg@428 177 out.write(indent + "{\n");
jjg@428 178 indent += " ";
jjg@428 179 break;
jjg@428 180 }
jjg@428 181 for (ClassKind nestedClassKind: ClassKind.values()) {
jjg@428 182 if ((nestedGenericKind == GenericKind.GENERIC)
jjg@428 183 && (nestedClassKind == ClassKind.ENUM))
jjg@428 184 continue;
jjg@428 185 if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL
jjg@428 186 || nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)
jjg@428 187 && nestedClassKind != ClassKind.CLASS)
jjg@428 188 continue;
jjg@428 189 // if the nested kind is none, there is no point iterating over all
jjg@428 190 // nested class kinds, so arbitarily limit it to just one kind
jjg@428 191 if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS)
jjg@428 192 continue;
jjg@428 193
jjg@428 194 ClassKind methodClassKind;
jjg@428 195 String methodClassName;
jjg@428 196 boolean allowAbstractMethods;
jjg@428 197 boolean allowStaticMethods;
jjg@428 198 switch (nestedKind) {
jjg@428 199 case NONE:
jjg@428 200 methodClassKind = outerClassKind;
jjg@428 201 methodClassName = outerClassName;
jjg@428 202 allowAbstractMethods = (outerClassKind == ClassKind.CLASS);
jjg@428 203 allowStaticMethods = (outerClassKind != ClassKind.INTERFACE);
jjg@428 204 break;
jjg@428 205 case METHOD_ANON:
jjg@428 206 case INIT_ANON:
jjg@428 207 out.write(indent + "new Base() {\n");
jjg@428 208 indent += " ";
jjg@428 209 methodClassKind = ClassKind.CLASS;
jjg@428 210 methodClassName = null;
jjg@428 211 allowAbstractMethods = false;
jjg@428 212 allowStaticMethods = false;
jjg@428 213 break;
jjg@428 214 default: { // INNER, NESTED, LOCAL
jjg@428 215 String nestedClassName = "N" + nestedClassKind.base + (nestedNum++);
jjg@428 216 String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T";
jjg@428 217 out.write(indent);
jjg@428 218 if (nestedKind == NestedKind.NESTED)
jjg@428 219 out.write("static ");
jjg@428 220 if (nestedClassKind == ClassKind.CLASS)
jjg@428 221 out.write("abstract ");
jjg@428 222 out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName);
jjg@428 223 if (nestedGenericKind == GenericKind.GENERIC)
jjg@428 224 out.write("<" + nestedTypeArg + ">");
jjg@428 225 if (nestedClassKind == ClassKind.INTERFACE)
jjg@428 226 out.write(" extends Base ");
jjg@428 227 else
jjg@428 228 out.write(" implements Base ");
jjg@428 229 out.write(" {\n");
jjg@428 230 indent += " ";
jjg@428 231 if (nestedClassKind == ClassKind.ENUM) {
jjg@428 232 out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
jjg@428 233 out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n");
jjg@428 234 }
jjg@428 235 methodClassKind = nestedClassKind;
jjg@428 236 methodClassName = nestedClassName;
jjg@428 237 allowAbstractMethods = (nestedClassKind == ClassKind.CLASS);
jjg@428 238 allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE);
jjg@428 239 break;
jjg@428 240 }
jjg@428 241 }
jjg@428 242
jjg@428 243 // Innermost loops, to generate methods
jjg@428 244 for (GenericKind methodGenericKind: GenericKind.values()) {
jjg@428 245 for (FinalKind finalKind: FinalKind.values()) {
jjg@428 246 for (MethodKind methodKind: MethodKind.values()) {
jjg@428 247 // out.write("// " + outerGenericKind
jjg@428 248 // + " " + outerClassKind
jjg@428 249 // + " " + nestedKind
jjg@428 250 // + " " + nestedGenericKind
jjg@428 251 // + " " + nestedClassKind
jjg@428 252 // + " " + methodGenericKind
jjg@428 253 // + " " + finalKind
jjg@428 254 // + " " + methodKind
jjg@428 255 // + "\n");
jjg@428 256 switch (methodKind) {
jjg@428 257 case CONSTRUCTOR:
jjg@428 258 if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
jjg@428 259 break;
jjg@428 260 if (methodClassKind != ClassKind.CLASS)
jjg@428 261 break;
jjg@428 262 if (finalKind == FinalKind.USE_FINAL && !haveFinal)
jjg@428 263 break;
jjg@428 264 out.write(indent);
jjg@428 265 if (methodGenericKind == GenericKind.GENERIC) {
jjg@428 266 out.write("<CT> " + methodClassName + "(CT c1, CT c2");
jjg@428 267 } else {
jjg@428 268 out.write(methodClassName + "(boolean b1, char c2");
jjg@428 269 }
jjg@428 270 if (finalKind == FinalKind.USE_FINAL) {
jjg@428 271 // add a dummy parameter to avoid duplicate declaration
jjg@428 272 out.write(", int i3) { int i = fi1; }\n");
jjg@428 273 } else
jjg@428 274 out.write(") { }\n");
jjg@428 275 break;
jjg@428 276 case ABSTRACT:
jjg@428 277 if (!allowAbstractMethods)
jjg@428 278 continue;
jjg@428 279 // fallthrough
jjg@428 280 case METHOD:
jjg@428 281 if (finalKind == FinalKind.USE_FINAL && !haveFinal)
jjg@428 282 break;
jjg@428 283 out.write(indent);
jjg@428 284 if (methodKind == MethodKind.ABSTRACT)
jjg@428 285 out.write("abstract ");
jjg@428 286 if (methodGenericKind == GenericKind.GENERIC)
jjg@428 287 out.write("<MT> ");
jjg@428 288 out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)");
jjg@428 289 if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE)
jjg@428 290 out.write(";\n");
jjg@428 291 else {
jjg@428 292 out.write(" {");
jjg@428 293 if (finalKind == FinalKind.USE_FINAL)
jjg@428 294 out.write(" int i = fi1;");
jjg@428 295 out.write(" }\n");
jjg@428 296 }
jjg@428 297 break;
jjg@428 298 case BRIDGE_METHOD:
jjg@428 299 if (methodGenericKind == GenericKind.GENERIC)
jjg@428 300 break;
jjg@428 301 out.write(indent);
jjg@428 302 // methods Base.base_m1 and Base.base_m2 are declared for the
jjg@428 303 // benefit of bridge methods. They need to be implemented
jjg@428 304 // whether or not a final variable is used.
jjg@428 305 String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2");
jjg@428 306 out.write("public String " + methodName + "(int i1)");
jjg@428 307 if (methodClassKind == ClassKind.INTERFACE)
jjg@428 308 out.write(";\n");
jjg@428 309 else {
jjg@428 310 out.write(" {");
jjg@428 311 if (finalKind == FinalKind.USE_FINAL && haveFinal)
jjg@428 312 out.write(" int i = fi1;");
jjg@428 313 out.write(" return null; }\n");
jjg@428 314 }
jjg@428 315 break;
jjg@428 316 case STATIC_METHOD:
jjg@428 317 if (!allowStaticMethods)
jjg@428 318 break;
jjg@428 319 if (finalKind == FinalKind.USE_FINAL && !haveFinal)
jjg@428 320 break;
jjg@428 321 out.write(indent + "static ");
jjg@428 322 if (methodGenericKind == GenericKind.GENERIC)
jjg@428 323 out.write("<MT> ");
jjg@428 324 out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {");
jjg@428 325 if (finalKind == FinalKind.USE_FINAL)
jjg@428 326 out.write(" int i = fi1;");
jjg@428 327 out.write(" }\n");
jjg@428 328 break;
jjg@428 329 }
jjg@428 330
jjg@428 331 }
jjg@428 332 }
jjg@428 333 }
jjg@428 334 if (nestedKind != NestedKind.NONE) {
jjg@428 335 indent = indent.substring(0, indent.length() - 4);
jjg@428 336 out.write(indent + "};\n");
jjg@428 337 }
jjg@428 338 }
jjg@428 339 switch (nestedKind) {
jjg@428 340 case METHOD_ANON: case METHOD_LOCAL:
jjg@428 341 case INIT_ANON: case INIT_LOCAL:
jjg@428 342 indent = indent.substring(0, indent.length() - 4);
jjg@428 343 out.write(indent + "}\n\n");
jjg@428 344 }
jjg@428 345 }
jjg@428 346 }
jjg@428 347 out.write("}\n\n");
jjg@428 348 }
jjg@428 349 }
jjg@428 350 out.close();
jjg@428 351 }
jjg@428 352
jjg@428 353
jjg@428 354 void test(String testName, boolean expectNames, String... opts) throws Exception {
jjg@428 355 System.err.println("Test " + testName
jjg@428 356 + ": expectNames:" + expectNames
jjg@428 357 + " javacOpts:" + Arrays.asList(opts));
jjg@428 358
jjg@428 359 File outDir = new File(testName);
jjg@428 360 outDir.mkdirs();
jjg@428 361 compile(outDir, opts);
jjg@428 362
jjg@428 363 Context ctx = new Context();
jjg@428 364 JavacFileManager fm = new JavacFileManager(ctx, true, null);
jjg@428 365 fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));
jjg@428 366 ClassReader cr = ClassReader.instance(ctx);
jjg@428 367 cr.saveParameterNames = true;
jjg@428 368 Names names = Names.instance(ctx);
jjg@428 369
jjg@428 370 Set<String> classes = getTopLevelClasses(outDir);
jjg@428 371 Deque<String> work = new LinkedList<String>(classes);
jjg@428 372 String classname;
jjg@428 373 while ((classname = work.poll()) != null) {
jjg@428 374 System.err.println("Checking class " + classname);
jjg@428 375 ClassSymbol sym = cr.enterClass(names.table.fromString(classname));
jjg@428 376 sym.complete();
jjg@428 377
jjg@428 378 if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces)
jjg@428 379 continue;
jjg@428 380
jjg@428 381 for (Scope.Entry e = sym.members_field.elems; e != null; e = e.sibling) {
jjg@428 382 System.err.println("Checking member " + e.sym);
jjg@428 383 switch (e.sym.kind) {
jjg@428 384 case Kinds.TYP: {
jjg@428 385 String name = e.sym.flatName().toString();
jjg@428 386 if (!classes.contains(name)) {
jjg@428 387 classes.add(name);
jjg@428 388 work.add(name);
jjg@428 389 }
jjg@428 390 break;
jjg@428 391 }
jjg@428 392 case Kinds.MTH:
jjg@428 393 verify((MethodSymbol) e.sym, expectNames);
jjg@428 394 break;
jjg@428 395 }
jjg@428 396
jjg@428 397 }
jjg@428 398 }
jjg@428 399 }
jjg@428 400
jjg@428 401 void verify(MethodSymbol m, boolean expectNames) {
jjg@428 402 if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods)
jjg@428 403 return;
jjg@428 404
jjg@428 405 //System.err.println("verify: " + m.params());
jjg@428 406 int i = 1;
jjg@428 407 for (VarSymbol v: m.params()) {
jjg@428 408 String expectName;
jjg@428 409 if (expectNames)
jjg@428 410 expectName = getExpectedName(v, i);
jjg@428 411 else
jjg@428 412 expectName = "arg" + (i - 1);
jjg@428 413 checkEqual(expectName, v.name.toString());
jjg@428 414 i++;
jjg@428 415 }
jjg@428 416 }
jjg@428 417
jjg@428 418 String getExpectedName(VarSymbol v, int i) {
jjg@428 419 // special cases:
jjg@428 420 // synthetic method
jjg@428 421 if (((v.owner.owner.flags() & Flags.ENUM) != 0)
jjg@428 422 && v.owner.name.toString().equals("valueOf"))
jjg@428 423 return "name";
jjg@428 424 // interfaces don't have saved names
jjg@428 425 // -- no Code attribute for the LocalVariableTable attribute
jjg@428 426 if ((v.owner.owner.flags() & Flags.INTERFACE) != 0)
jjg@428 427 return "arg" + (i - 1);
jjg@428 428 // abstract methods don't have saved names
jjg@428 429 // -- no Code attribute for the LocalVariableTable attribute
jjg@428 430 if ((v.owner.flags() & Flags.ABSTRACT) != 0)
jjg@428 431 return "arg" + (i - 1);
jjg@428 432 // bridge methods use xN
jjg@428 433 if ((v.owner.flags() & Flags.BRIDGE) != 0)
jjg@428 434 return "x" + (i - 1);
jjg@428 435
jjg@428 436 // The rest of this method assumes the local conventions in the test program
jjg@428 437 Type t = v.type;
jjg@428 438 String s;
jjg@1374 439 if (t.hasTag(TypeTag.CLASS))
jjg@428 440 s = ((ClassType) t).tsym.name.toString();
jjg@428 441 else
jjg@428 442 s = t.toString();
jjg@428 443 return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;
jjg@428 444 }
jjg@428 445
jjg@428 446 void compile(File outDir, String... opts) throws Exception {
jjg@428 447 //File testSrc = new File(System.getProperty("test.src"), ".");
jjg@428 448 List<String> args = new ArrayList<String>();
jjg@428 449 args.add("-d");
jjg@428 450 args.add(outDir.getPath());
jjg@428 451 args.addAll(Arrays.asList(opts));
jjg@428 452 //args.add(new File(testSrc, "Test.java").getPath());
jjg@428 453 args.add("Test.java");
jjg@428 454 StringWriter sw = new StringWriter();
jjg@428 455 PrintWriter pw = new PrintWriter(sw);
jjg@428 456 int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
jjg@428 457 pw.close();
jjg@428 458 if (rc != 0) {
jjg@428 459 System.err.println(sw.toString());
jjg@428 460 throw new Exception("compilation failed unexpectedly");
jjg@428 461 }
jjg@428 462 }
jjg@428 463
jjg@428 464 Set<String> getTopLevelClasses(File outDir) {
jjg@428 465 Set<String> classes = new HashSet<String>();
jjg@428 466 for (String f: outDir.list()) {
jjg@428 467 if (f.endsWith(".class") && !f.contains("$"))
jjg@428 468 classes.add(f.replace(".class", ""));
jjg@428 469 }
jjg@428 470 return classes;
jjg@428 471 }
jjg@428 472
jjg@428 473 void checkEqual(String expect, String found) {
jjg@428 474 if (!expect.equals(found))
jjg@428 475 error("mismatch: expected:" + expect + " found:" + found);
jjg@428 476 }
jjg@428 477
jjg@428 478 void error(String msg) {
jjg@428 479 System.err.println(msg);
jjg@428 480 errors++;
jjg@428 481 throw new Error();
jjg@428 482 }
jjg@428 483
jjg@428 484 int errors;
jjg@428 485 }

mercurial