test/tools/javac/6889255/T6889255.java

changeset 428
2485f5641ed0
child 554
9d9f26857129
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/test/tools/javac/6889255/T6889255.java	Mon Oct 19 13:38:09 2009 -0700
     1.3 @@ -0,0 +1,485 @@
     1.4 +/*
     1.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.24 + * have any questions.
    1.25 + */
    1.26 +
    1.27 +/*
    1.28 + * @test
    1.29 + * @bug 6889255
    1.30 + * @summary ClassReader does not read parameter names correctly
    1.31 + */
    1.32 +
    1.33 +import java.io.*;
    1.34 +import java.util.*;
    1.35 +import javax.tools.StandardLocation;
    1.36 +import com.sun.tools.javac.code.Flags;
    1.37 +import com.sun.tools.javac.code.Kinds;
    1.38 +import com.sun.tools.javac.code.Scope;
    1.39 +import com.sun.tools.javac.code.Symbol.*;
    1.40 +import com.sun.tools.javac.code.Type;
    1.41 +import com.sun.tools.javac.code.Type.ClassType;
    1.42 +import com.sun.tools.javac.code.TypeTags;
    1.43 +import com.sun.tools.javac.file.JavacFileManager;
    1.44 +import com.sun.tools.javac.jvm.ClassReader;
    1.45 +import com.sun.tools.javac.util.Context;
    1.46 +import com.sun.tools.javac.util.Names;
    1.47 +
    1.48 +public class T6889255 {
    1.49 +    boolean testInterfaces = true;
    1.50 +    boolean testSyntheticMethods = true;
    1.51 +
    1.52 +    // The following enums control the generation of the test methods to be compiled.
    1.53 +    enum GenericKind {
    1.54 +        NOT_GENERIC,
    1.55 +        GENERIC
    1.56 +    };
    1.57 +
    1.58 +    enum ClassKind {
    1.59 +        CLASS("Clss"),
    1.60 +        INTERFACE("Intf"),
    1.61 +        ENUM("Enum");
    1.62 +        final String base;
    1.63 +        ClassKind(String base) { this.base = base; }
    1.64 +    };
    1.65 +
    1.66 +    enum NestedKind {
    1.67 +        /** Declare methods inside the outermost container. */
    1.68 +        NONE,
    1.69 +        /** Declare methods inside a container with a 'static' modifier. */
    1.70 +        NESTED,
    1.71 +        /** Declare methods inside a container without a 'static' modifier. */
    1.72 +        INNER,
    1.73 +        /** Declare methods inside a local class in an initializer. */
    1.74 +        INIT_LOCAL,
    1.75 +        /** Declare methods inside an anonymous class in an initializer. */
    1.76 +        INIT_ANON,
    1.77 +        /** Declare methods inside a local class in a method. */
    1.78 +        METHOD_LOCAL,
    1.79 +        /** Declare methods inside an anonymous class in a method. */
    1.80 +        METHOD_ANON
    1.81 +    };
    1.82 +
    1.83 +    enum MethodKind {
    1.84 +        ABSTRACT,
    1.85 +        CONSTRUCTOR,
    1.86 +        METHOD,
    1.87 +        STATIC_METHOD,
    1.88 +        BRIDGE_METHOD
    1.89 +    };
    1.90 +
    1.91 +    enum FinalKind {
    1.92 +        /** Method body does not reference external final variables. */
    1.93 +        NO_FINAL,
    1.94 +        /** Method body references external final variables. */
    1.95 +        USE_FINAL
    1.96 +    };
    1.97 +
    1.98 +    public static void main(String... args) throws Exception {
    1.99 +        new T6889255().run();
   1.100 +    }
   1.101 +
   1.102 +    void run() throws Exception {
   1.103 +        genTest();
   1.104 +
   1.105 +        test("no-args", false);
   1.106 +        test("g",       true,  "-g");
   1.107 +
   1.108 +        if (errors > 0)
   1.109 +            throw new Exception(errors + " errors found");
   1.110 +    }
   1.111 +
   1.112 +    /**
   1.113 +     * Create a file containing lots of method definitions to be tested.
   1.114 +     * There are 3 sets of nested loops that generate the methods.
   1.115 +     * 1. The outermost set declares [generic] (class | interface | enum)
   1.116 +     * 2. The middle set declares [(nested | inner | anon | local)] class
   1.117 +     * 3. The innermost set declares
   1.118 +     *      [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope]
   1.119 +     * Invalid combinations are filtered out.
   1.120 +     */
   1.121 +    void genTest() throws Exception {
   1.122 +        BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));
   1.123 +
   1.124 +        // This interface is used to force bridge methods to be generated, by
   1.125 +        // implementing its methods with subtypes of Object
   1.126 +        out.write("interface Base {\n");
   1.127 +        out.write("    Object base_m1(int i1);\n");
   1.128 +        out.write("    Object base_m2(int i1);\n");
   1.129 +        out.write("}\n");
   1.130 +
   1.131 +        int outerNum = 0;
   1.132 +        // Outermost set of loops, to generate a top level container
   1.133 +        for (GenericKind outerGenericKind: GenericKind.values()) {
   1.134 +            for (ClassKind outerClassKind: ClassKind.values()) {
   1.135 +                if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM)
   1.136 +                    continue;
   1.137 +                String outerClassName = outerClassKind.base + (outerNum++);
   1.138 +                String outerTypeArg = outerClassKind.toString().charAt(0) + "T";
   1.139 +                if (outerClassKind == ClassKind.CLASS)
   1.140 +                    out.write("abstract ");
   1.141 +                out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName);
   1.142 +                if (outerGenericKind == GenericKind.GENERIC)
   1.143 +                    out.write("<" + outerTypeArg + ">");
   1.144 +                if (outerClassKind == ClassKind.INTERFACE)
   1.145 +                    out.write(" extends Base");
   1.146 +                else
   1.147 +                    out.write(" implements Base");
   1.148 +                out.write(" {\n");
   1.149 +                if (outerClassKind == ClassKind.ENUM) {
   1.150 +                    out.write("    E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
   1.151 +                    out.write("    " + outerClassName + "(int i1, int i2, int i3) { }\n");
   1.152 +                }
   1.153 +                // Middle set of loops, to generate an optional nested container
   1.154 +                int nestedNum = 0;
   1.155 +                int methodNum = 0;
   1.156 +                for (GenericKind nestedGenericKind: GenericKind.values()) {
   1.157 +                    nextNestedKind:
   1.158 +                    for (NestedKind nestedKind: NestedKind.values()) {
   1.159 +                        // if the nested kind is none, there is no point iterating over all
   1.160 +                        // nested generic kinds, so arbitarily limit it to just one kind
   1.161 +                        if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC)
   1.162 +                            continue;
   1.163 +                        if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
   1.164 +                                && nestedGenericKind == GenericKind.GENERIC)
   1.165 +                            continue;
   1.166 +                        String indent = "    ";
   1.167 +                        boolean haveFinal = false;
   1.168 +                        switch (nestedKind) {
   1.169 +                            case METHOD_ANON: case METHOD_LOCAL:
   1.170 +                                if (outerClassKind == ClassKind.INTERFACE)
   1.171 +                                    continue nextNestedKind;
   1.172 +                                out.write(indent + "void m" +  + (nestedNum++) + "() {\n");
   1.173 +                                indent += "    ";
   1.174 +                                out.write(indent + "final int fi1 = 0;\n");
   1.175 +                                haveFinal = true;
   1.176 +                                break;
   1.177 +                            case INIT_ANON: case INIT_LOCAL:
   1.178 +                                if (outerClassKind == ClassKind.INTERFACE)
   1.179 +                                    continue nextNestedKind;
   1.180 +                                out.write(indent + "{\n");
   1.181 +                                indent += "    ";
   1.182 +                                break;
   1.183 +                        }
   1.184 +                        for (ClassKind nestedClassKind: ClassKind.values()) {
   1.185 +                            if ((nestedGenericKind == GenericKind.GENERIC)
   1.186 +                                    && (nestedClassKind == ClassKind.ENUM))
   1.187 +                                continue;
   1.188 +                            if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL
   1.189 +                                    || nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)
   1.190 +                                    && nestedClassKind != ClassKind.CLASS)
   1.191 +                                continue;
   1.192 +                            // if the nested kind is none, there is no point iterating over all
   1.193 +                            // nested class kinds, so arbitarily limit it to just one kind
   1.194 +                            if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS)
   1.195 +                                continue;
   1.196 +
   1.197 +                            ClassKind methodClassKind;
   1.198 +                            String methodClassName;
   1.199 +                            boolean allowAbstractMethods;
   1.200 +                            boolean allowStaticMethods;
   1.201 +                            switch (nestedKind) {
   1.202 +                                case NONE:
   1.203 +                                    methodClassKind = outerClassKind;
   1.204 +                                    methodClassName = outerClassName;
   1.205 +                                    allowAbstractMethods = (outerClassKind == ClassKind.CLASS);
   1.206 +                                    allowStaticMethods = (outerClassKind != ClassKind.INTERFACE);
   1.207 +                                    break;
   1.208 +                                case METHOD_ANON:
   1.209 +                                case INIT_ANON:
   1.210 +                                    out.write(indent + "new Base() {\n");
   1.211 +                                    indent += "    ";
   1.212 +                                    methodClassKind = ClassKind.CLASS;
   1.213 +                                    methodClassName = null;
   1.214 +                                    allowAbstractMethods = false;
   1.215 +                                    allowStaticMethods = false;
   1.216 +                                    break;
   1.217 +                                default: { // INNER, NESTED, LOCAL
   1.218 +                                    String nestedClassName = "N" + nestedClassKind.base + (nestedNum++);
   1.219 +                                    String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T";
   1.220 +                                    out.write(indent);
   1.221 +                                    if (nestedKind == NestedKind.NESTED)
   1.222 +                                        out.write("static ");
   1.223 +                                    if (nestedClassKind == ClassKind.CLASS)
   1.224 +                                        out.write("abstract ");
   1.225 +                                    out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName);
   1.226 +                                    if (nestedGenericKind == GenericKind.GENERIC)
   1.227 +                                        out.write("<" + nestedTypeArg + ">");
   1.228 +                                    if (nestedClassKind == ClassKind.INTERFACE)
   1.229 +                                        out.write(" extends Base ");
   1.230 +                                    else
   1.231 +                                        out.write(" implements Base ");
   1.232 +                                    out.write(" {\n");
   1.233 +                                    indent += "    ";
   1.234 +                                    if (nestedClassKind == ClassKind.ENUM) {
   1.235 +                                        out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
   1.236 +                                        out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n");
   1.237 +                                    }
   1.238 +                                    methodClassKind = nestedClassKind;
   1.239 +                                    methodClassName = nestedClassName;
   1.240 +                                    allowAbstractMethods = (nestedClassKind == ClassKind.CLASS);
   1.241 +                                    allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE);
   1.242 +                                    break;
   1.243 +                                }
   1.244 +                            }
   1.245 +
   1.246 +                            // Innermost loops, to generate methods
   1.247 +                            for (GenericKind methodGenericKind: GenericKind.values()) {
   1.248 +                                for (FinalKind finalKind: FinalKind.values()) {
   1.249 +                                    for (MethodKind methodKind: MethodKind.values()) {
   1.250 +//                                        out.write("// " + outerGenericKind
   1.251 +//                                                + " " + outerClassKind
   1.252 +//                                                + " " + nestedKind
   1.253 +//                                                + " " + nestedGenericKind
   1.254 +//                                                + " " + nestedClassKind
   1.255 +//                                                + " " + methodGenericKind
   1.256 +//                                                + " " + finalKind
   1.257 +//                                                + " " + methodKind
   1.258 +//                                                + "\n");
   1.259 +                                        switch (methodKind) {
   1.260 +                                            case CONSTRUCTOR:
   1.261 +                                                if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
   1.262 +                                                    break;
   1.263 +                                                if (methodClassKind != ClassKind.CLASS)
   1.264 +                                                    break;
   1.265 +                                                if (finalKind == FinalKind.USE_FINAL && !haveFinal)
   1.266 +                                                    break;
   1.267 +                                                out.write(indent);
   1.268 +                                                if (methodGenericKind == GenericKind.GENERIC) {
   1.269 +                                                    out.write("<CT> " + methodClassName + "(CT c1, CT c2");
   1.270 +                                                } else {
   1.271 +                                                    out.write(methodClassName + "(boolean b1, char c2");
   1.272 +                                                }
   1.273 +                                                if (finalKind == FinalKind.USE_FINAL) {
   1.274 +                                                    // add a dummy parameter to avoid duplicate declaration
   1.275 +                                                    out.write(", int i3) { int i = fi1; }\n");
   1.276 +                                                } else
   1.277 +                                                    out.write(") { }\n");
   1.278 +                                                break;
   1.279 +                                            case ABSTRACT:
   1.280 +                                                if (!allowAbstractMethods)
   1.281 +                                                    continue;
   1.282 +                                                // fallthrough
   1.283 +                                            case METHOD:
   1.284 +                                                if (finalKind == FinalKind.USE_FINAL && !haveFinal)
   1.285 +                                                    break;
   1.286 +                                                out.write(indent);
   1.287 +                                                if (methodKind == MethodKind.ABSTRACT)
   1.288 +                                                    out.write("abstract ");
   1.289 +                                                if (methodGenericKind == GenericKind.GENERIC)
   1.290 +                                                    out.write("<MT> ");
   1.291 +                                                out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)");
   1.292 +                                                if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE)
   1.293 +                                                    out.write(";\n");
   1.294 +                                                else {
   1.295 +                                                    out.write(" {");
   1.296 +                                                    if (finalKind == FinalKind.USE_FINAL)
   1.297 +                                                        out.write(" int i = fi1;");
   1.298 +                                                    out.write(" }\n");
   1.299 +                                                }
   1.300 +                                                break;
   1.301 +                                            case BRIDGE_METHOD:
   1.302 +                                                if (methodGenericKind == GenericKind.GENERIC)
   1.303 +                                                    break;
   1.304 +                                                out.write(indent);
   1.305 +                                                // methods Base.base_m1 and Base.base_m2 are declared for the
   1.306 +                                                // benefit of bridge methods. They need to be implemented
   1.307 +                                                // whether or not a final variable is used.
   1.308 +                                                String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2");
   1.309 +                                                out.write("public String " + methodName + "(int i1)");
   1.310 +                                                if (methodClassKind == ClassKind.INTERFACE)
   1.311 +                                                    out.write(";\n");
   1.312 +                                                else {
   1.313 +                                                    out.write(" {");
   1.314 +                                                    if (finalKind == FinalKind.USE_FINAL && haveFinal)
   1.315 +                                                        out.write(" int i = fi1;");
   1.316 +                                                    out.write(" return null; }\n");
   1.317 +                                                }
   1.318 +                                                break;
   1.319 +                                            case STATIC_METHOD:
   1.320 +                                                if (!allowStaticMethods)
   1.321 +                                                    break;
   1.322 +                                                if (finalKind == FinalKind.USE_FINAL && !haveFinal)
   1.323 +                                                    break;
   1.324 +                                                out.write(indent + "static ");
   1.325 +                                                if (methodGenericKind == GenericKind.GENERIC)
   1.326 +                                                    out.write("<MT> ");
   1.327 +                                                out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {");
   1.328 +                                                if (finalKind == FinalKind.USE_FINAL)
   1.329 +                                                    out.write(" int i = fi1;");
   1.330 +                                                out.write(" }\n");
   1.331 +                                                break;
   1.332 +                                        }
   1.333 +
   1.334 +                                    }
   1.335 +                                }
   1.336 +                            }
   1.337 +                            if (nestedKind != NestedKind.NONE) {
   1.338 +                                indent = indent.substring(0, indent.length() - 4);
   1.339 +                                out.write(indent + "};\n");
   1.340 +                            }
   1.341 +                        }
   1.342 +                        switch (nestedKind) {
   1.343 +                            case METHOD_ANON: case METHOD_LOCAL:
   1.344 +                            case INIT_ANON: case INIT_LOCAL:
   1.345 +                                indent = indent.substring(0, indent.length() - 4);
   1.346 +                                out.write(indent + "}\n\n");
   1.347 +                        }
   1.348 +                    }
   1.349 +                }
   1.350 +                out.write("}\n\n");
   1.351 +            }
   1.352 +        }
   1.353 +        out.close();
   1.354 +    }
   1.355 +
   1.356 +
   1.357 +    void test(String testName, boolean expectNames, String... opts) throws Exception {
   1.358 +        System.err.println("Test " + testName
   1.359 +                + ": expectNames:" + expectNames
   1.360 +                + " javacOpts:" + Arrays.asList(opts));
   1.361 +
   1.362 +        File outDir = new File(testName);
   1.363 +        outDir.mkdirs();
   1.364 +        compile(outDir, opts);
   1.365 +
   1.366 +        Context ctx = new Context();
   1.367 +        JavacFileManager fm = new JavacFileManager(ctx, true, null);
   1.368 +        fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));
   1.369 +        ClassReader cr = ClassReader.instance(ctx);
   1.370 +        cr.saveParameterNames = true;
   1.371 +        Names names = Names.instance(ctx);
   1.372 +
   1.373 +        Set<String> classes = getTopLevelClasses(outDir);
   1.374 +        Deque<String> work = new LinkedList<String>(classes);
   1.375 +        String classname;
   1.376 +        while ((classname = work.poll()) != null) {
   1.377 +            System.err.println("Checking class " + classname);
   1.378 +            ClassSymbol sym = cr.enterClass(names.table.fromString(classname));
   1.379 +            sym.complete();
   1.380 +
   1.381 +            if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces)
   1.382 +                continue;
   1.383 +
   1.384 +            for (Scope.Entry e = sym.members_field.elems; e != null; e = e.sibling) {
   1.385 +                System.err.println("Checking member " + e.sym);
   1.386 +                switch (e.sym.kind) {
   1.387 +                    case Kinds.TYP: {
   1.388 +                        String name = e.sym.flatName().toString();
   1.389 +                        if (!classes.contains(name)) {
   1.390 +                            classes.add(name);
   1.391 +                            work.add(name);
   1.392 +                        }
   1.393 +                        break;
   1.394 +                    }
   1.395 +                    case Kinds.MTH:
   1.396 +                        verify((MethodSymbol) e.sym, expectNames);
   1.397 +                        break;
   1.398 +                }
   1.399 +
   1.400 +            }
   1.401 +        }
   1.402 +    }
   1.403 +
   1.404 +    void verify(MethodSymbol m, boolean expectNames) {
   1.405 +        if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods)
   1.406 +            return;
   1.407 +
   1.408 +        //System.err.println("verify: " + m.params());
   1.409 +        int i = 1;
   1.410 +        for (VarSymbol v: m.params()) {
   1.411 +            String expectName;
   1.412 +            if (expectNames)
   1.413 +                expectName = getExpectedName(v, i);
   1.414 +            else
   1.415 +                expectName = "arg" + (i - 1);
   1.416 +            checkEqual(expectName, v.name.toString());
   1.417 +            i++;
   1.418 +        }
   1.419 +    }
   1.420 +
   1.421 +    String getExpectedName(VarSymbol v, int i) {
   1.422 +        // special cases:
   1.423 +        // synthetic method
   1.424 +        if (((v.owner.owner.flags() & Flags.ENUM) != 0)
   1.425 +                && v.owner.name.toString().equals("valueOf"))
   1.426 +            return "name";
   1.427 +        // interfaces don't have saved names
   1.428 +        // -- no Code attribute for the LocalVariableTable attribute
   1.429 +        if ((v.owner.owner.flags() & Flags.INTERFACE) != 0)
   1.430 +            return "arg" + (i - 1);
   1.431 +        // abstract methods don't have saved names
   1.432 +        // -- no Code attribute for the LocalVariableTable attribute
   1.433 +        if ((v.owner.flags() & Flags.ABSTRACT) != 0)
   1.434 +            return "arg" + (i - 1);
   1.435 +        // bridge methods use xN
   1.436 +        if ((v.owner.flags() & Flags.BRIDGE) != 0)
   1.437 +            return "x" + (i - 1);
   1.438 +
   1.439 +        // The rest of this method assumes the local conventions in the test program
   1.440 +        Type t = v.type;
   1.441 +        String s;
   1.442 +        if (t.tag == TypeTags.CLASS)
   1.443 +            s = ((ClassType) t).tsym.name.toString();
   1.444 +        else
   1.445 +            s = t.toString();
   1.446 +        return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;
   1.447 +    }
   1.448 +
   1.449 +    void compile(File outDir, String... opts) throws Exception {
   1.450 +        //File testSrc = new File(System.getProperty("test.src"), ".");
   1.451 +        List<String> args = new ArrayList<String>();
   1.452 +        args.add("-d");
   1.453 +        args.add(outDir.getPath());
   1.454 +        args.addAll(Arrays.asList(opts));
   1.455 +        //args.add(new File(testSrc, "Test.java").getPath());
   1.456 +        args.add("Test.java");
   1.457 +        StringWriter sw = new StringWriter();
   1.458 +        PrintWriter pw = new PrintWriter(sw);
   1.459 +        int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
   1.460 +        pw.close();
   1.461 +        if (rc != 0) {
   1.462 +            System.err.println(sw.toString());
   1.463 +            throw new Exception("compilation failed unexpectedly");
   1.464 +        }
   1.465 +    }
   1.466 +
   1.467 +    Set<String> getTopLevelClasses(File outDir) {
   1.468 +        Set<String> classes = new HashSet<String>();
   1.469 +        for (String f: outDir.list()) {
   1.470 +            if (f.endsWith(".class") && !f.contains("$"))
   1.471 +                classes.add(f.replace(".class", ""));
   1.472 +        }
   1.473 +        return classes;
   1.474 +    }
   1.475 +
   1.476 +    void checkEqual(String expect, String found) {
   1.477 +        if (!expect.equals(found))
   1.478 +            error("mismatch: expected:" + expect + " found:" + found);
   1.479 +    }
   1.480 +
   1.481 +    void error(String msg) {
   1.482 +        System.err.println(msg);
   1.483 +        errors++;
   1.484 +        throw new Error();
   1.485 +    }
   1.486 +
   1.487 +    int errors;
   1.488 +}

mercurial