Wed, 26 Jan 2011 13:45:25 -0800
7013272: Automatically generate info about how compiler resource keys are used
Reviewed-by: mcimadamore
jjg@428 | 1 | /* |
ohair@554 | 2 | * Copyright (c) 2009, 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@428 | 39 | import com.sun.tools.javac.code.TypeTags; |
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@428 | 439 | if (t.tag == TypeTags.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 | } |