Wed, 30 Jun 2010 18:06:29 -0700
6964768: need test program to validate javac resource bundles
Reviewed-by: darcy
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Kinds.java Tue Jun 29 12:06:46 2010 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Kinds.java Wed Jun 30 18:06:29 2010 -0700 1.3 @@ -92,7 +92,7 @@ 1.4 public static final int ABSENT_TYP = ERRONEOUS+8; // missing type 1.5 1.6 public enum KindName implements Formattable { 1.7 - ANNOTATION("kindname.interface"), 1.8 + ANNOTATION("kindname.annotation"), 1.9 CONSTRUCTOR("kindname.constructor"), 1.10 INTERFACE("kindname.interface"), 1.11 ENUM("kindname.enum"),
2.1 --- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Jun 29 12:06:46 2010 -0700 2.2 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jun 30 18:06:29 2010 -0700 2.3 @@ -111,14 +111,14 @@ 2.4 try { 2.5 versionRB = ResourceBundle.getBundle(versionRBName); 2.6 } catch (MissingResourceException e) { 2.7 - return Log.getLocalizedString("version.resource.missing", System.getProperty("java.version")); 2.8 + return Log.getLocalizedString("version.not.available"); 2.9 } 2.10 } 2.11 try { 2.12 return versionRB.getString(key); 2.13 } 2.14 catch (MissingResourceException e) { 2.15 - return Log.getLocalizedString("version.unknown", System.getProperty("java.version")); 2.16 + return Log.getLocalizedString("version.not.available"); 2.17 } 2.18 } 2.19
3.1 --- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java Tue Jun 29 12:06:46 2010 -0700 3.2 +++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java Wed Jun 30 18:06:29 2010 -0700 3.3 @@ -419,7 +419,7 @@ 3.4 putChar(ch); 3.5 } else { 3.6 if (!allowUnderscoresInLiterals) { 3.7 - lexError("unsupported.underscore", source.name); 3.8 + lexError("unsupported.underscore.lit", source.name); 3.9 allowUnderscoresInLiterals = true; 3.10 } 3.11 }
4.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Jun 29 12:06:46 2010 -0700 4.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jun 30 18:06:29 2010 -0700 4.3 @@ -637,6 +637,9 @@ 4.4 compiler.misc.count.warn.plural=\ 4.5 {0} warnings 4.6 4.7 +compiler.misc.version.not.available=\ 4.8 + (version info not available) 4.9 + 4.10 ## extra output when using -verbose (JavaCompiler) 4.11 4.12 compiler.misc.verbose.checking.attribution=\ 4.13 @@ -1036,7 +1039,7 @@ 4.14 ## diagnostics whose key ends in ".1" 4.15 compiler.misc.undetermined.type=\ 4.16 undetermined type 4.17 -ncompiler.misc.type.variable.has.undetermined.type=\ 4.18 +compiler.misc.type.variable.has.undetermined.type=\ 4.19 type variable {0} has undetermined type 4.20 compiler.misc.no.unique.maximal.instance.exists=\ 4.21 no unique maximal instance exists for type variable {0} with upper bounds {1} 4.22 @@ -1122,6 +1125,8 @@ 4.23 @interface 4.24 compiler.misc.kindname.constructor=\ 4.25 constructor 4.26 +compiler.misc.kindname.enum=\ 4.27 + enum 4.28 compiler.misc.kindname.interface=\ 4.29 interface 4.30 compiler.misc.kindname.static=\ 4.31 @@ -1256,6 +1261,10 @@ 4.32 enums are not supported in -source {0}\n\ 4.33 (use -source 5 or higher to enable enums) 4.34 4.35 +compiler.err.diamond.not.supported.in.source=\ 4.36 + diamond operator is not supported in -source {0}\n\ 4.37 +(use -source 7 or higher to enable multi-catch statement) 4.38 + 4.39 compiler.err.multicatch.not.supported.in.source=\ 4.40 multi-catch statement is not supported in -source {0}\n\ 4.41 (use -source 7 or higher to enable multi-catch statement)
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/tools/javac/diags/CheckResourceKeys.java Wed Jun 30 18:06:29 2010 -0700 5.3 @@ -0,0 +1,362 @@ 5.4 +/* 5.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 + 5.27 +/* 5.28 + * @test 5.29 + * @bug 6964768 6964461 6964469 6964487 6964460 6964481 5.30 + * @summary need test program to validate javac resource bundles 5.31 + */ 5.32 + 5.33 +import java.io.*; 5.34 +import java.util.*; 5.35 +import javax.tools.*; 5.36 +import com.sun.tools.classfile.*; 5.37 + 5.38 +/** 5.39 + * Compare string constants in javac classes against keys in javac resource bundles. 5.40 + */ 5.41 +public class CheckResourceKeys { 5.42 + /** 5.43 + * Main program. 5.44 + * Options: 5.45 + * -finddeadkeys 5.46 + * look for keys in resource bundles that are no longer required 5.47 + * -findmissingkeys 5.48 + * look for keys in resource bundles that are missing 5.49 + * 5.50 + * @throws Exception if invoked by jtreg and errors occur 5.51 + */ 5.52 + public static void main(String... args) throws Exception { 5.53 + CheckResourceKeys c = new CheckResourceKeys(); 5.54 + if (c.run(args)) 5.55 + return; 5.56 + 5.57 + if (is_jtreg()) 5.58 + throw new Exception(c.errors + " errors occurred"); 5.59 + else 5.60 + System.exit(1); 5.61 + } 5.62 + 5.63 + static boolean is_jtreg() { 5.64 + return (System.getProperty("test.src") != null); 5.65 + } 5.66 + 5.67 + /** 5.68 + * Main entry point. 5.69 + */ 5.70 + boolean run(String... args) throws Exception { 5.71 + boolean findDeadKeys = false; 5.72 + boolean findMissingKeys = false; 5.73 + 5.74 + if (args.length == 0) { 5.75 + if (is_jtreg()) { 5.76 + findDeadKeys = true; 5.77 + findMissingKeys = true; 5.78 + } else { 5.79 + System.err.println("Usage: java CheckResourceKeys <options>"); 5.80 + System.err.println("where options include"); 5.81 + System.err.println(" -finddeadkeys find keys in resource bundles which are no longer required"); 5.82 + System.err.println(" -findmissingkeys find keys in resource bundles that are required but missing"); 5.83 + return true; 5.84 + } 5.85 + } else { 5.86 + for (String arg: args) { 5.87 + if (arg.equalsIgnoreCase("-finddeadkeys")) 5.88 + findDeadKeys = true; 5.89 + else if (arg.equalsIgnoreCase("-findmissingkeys")) 5.90 + findMissingKeys = true; 5.91 + else 5.92 + error("bad option: " + arg); 5.93 + } 5.94 + } 5.95 + 5.96 + if (errors > 0) 5.97 + return false; 5.98 + 5.99 + Set<String> codeStrings = getCodeStrings(); 5.100 + Set<String> resourceKeys = getResourceKeys(); 5.101 + 5.102 + if (findDeadKeys) 5.103 + findDeadKeys(codeStrings, resourceKeys); 5.104 + 5.105 + if (findMissingKeys) 5.106 + findMissingKeys(codeStrings, resourceKeys); 5.107 + 5.108 + return (errors == 0); 5.109 + } 5.110 + 5.111 + /** 5.112 + * Find keys in resource bundles which are probably no longer required. 5.113 + * A key is probably required if there is a string fragment in the code 5.114 + * that is part of the resource key, or if the key is well-known 5.115 + * according to various pragmatic rules. 5.116 + */ 5.117 + void findDeadKeys(Set<String> codeStrings, Set<String> resourceKeys) { 5.118 + String[] prefixes = { 5.119 + "compiler.err.", "compiler.warn.", "compiler.note.", "compiler.misc.", 5.120 + "javac." 5.121 + }; 5.122 + for (String rk: resourceKeys) { 5.123 + // some keys are used directly, without a prefix. 5.124 + if (codeStrings.contains(rk)) 5.125 + continue; 5.126 + 5.127 + // remove standard prefix 5.128 + String s = null; 5.129 + for (int i = 0; i < prefixes.length && s == null; i++) { 5.130 + if (rk.startsWith(prefixes[i])) { 5.131 + s = rk.substring(prefixes[i].length()); 5.132 + } 5.133 + } 5.134 + if (s == null) { 5.135 + error("Resource key does not start with a standard prefix: " + rk); 5.136 + continue; 5.137 + } 5.138 + 5.139 + if (codeStrings.contains(s)) 5.140 + continue; 5.141 + 5.142 + // keys ending in .1 are often synthesized 5.143 + if (s.endsWith(".1") && codeStrings.contains(s.substring(0, s.length() - 2))) 5.144 + continue; 5.145 + 5.146 + // verbose keys are generated by ClassReader.printVerbose 5.147 + if (s.startsWith("verbose.") && codeStrings.contains(s.substring(8))) 5.148 + continue; 5.149 + 5.150 + // mandatory warning messages are synthesized with no characteristic substring 5.151 + if (isMandatoryWarningString(s)) 5.152 + continue; 5.153 + 5.154 + // check known (valid) exceptions 5.155 + if (knownRequired.contains(rk)) 5.156 + continue; 5.157 + 5.158 + // check known suspects 5.159 + if (needToInvestigate.contains(rk)) 5.160 + continue; 5.161 + 5.162 + error("Resource key not found in code: " + rk); 5.163 + } 5.164 + } 5.165 + 5.166 + /** 5.167 + * The keys for mandatory warning messages are all synthesized and do not 5.168 + * have a significant recognizable substring to look for. 5.169 + */ 5.170 + private boolean isMandatoryWarningString(String s) { 5.171 + String[] bases = { "deprecated", "unchecked", "varargs", "sunapi" }; 5.172 + String[] tails = { ".filename", ".filename.additional", ".plural", ".plural.additional", ".recompile" }; 5.173 + for (String b: bases) { 5.174 + if (s.startsWith(b)) { 5.175 + String tail = s.substring(b.length()); 5.176 + for (String t: tails) { 5.177 + if (tail.equals(t)) 5.178 + return true; 5.179 + } 5.180 + } 5.181 + } 5.182 + return false; 5.183 + } 5.184 + 5.185 + Set<String> knownRequired = new TreeSet<String>(Arrays.asList( 5.186 + // See Resolve.getErrorKey 5.187 + "compiler.err.cant.resolve.args", 5.188 + "compiler.err.cant.resolve.args.params", 5.189 + "compiler.err.cant.resolve.location.args", 5.190 + "compiler.err.cant.resolve.location.args.params", 5.191 + // JavaCompiler, reports #errors and #warnings 5.192 + "compiler.misc.count.error", 5.193 + "compiler.misc.count.error.plural", 5.194 + "compiler.misc.count.warn", 5.195 + "compiler.misc.count.warn.plural", 5.196 + // Used for LintCategory 5.197 + "compiler.warn.lintOption", 5.198 + // Other 5.199 + "compiler.misc.base.membership" // (sic) 5.200 + )); 5.201 + 5.202 + 5.203 + Set<String> needToInvestigate = new TreeSet<String>(Arrays.asList( 5.204 + "compiler.err.cant.read.file", // UNUSED 5.205 + "compiler.err.illegal.self.ref", // UNUSED 5.206 + "compiler.err.io.exception", // UNUSED 5.207 + "compiler.err.limit.pool.in.class", // UNUSED 5.208 + "compiler.err.name.reserved.for.internal.use", // UNUSED 5.209 + "compiler.err.no.match.entry", // UNUSED 5.210 + "compiler.err.not.within.bounds.explain", // UNUSED 5.211 + "compiler.err.signature.doesnt.match.intf", // UNUSED 5.212 + "compiler.err.signature.doesnt.match.supertype", // UNUSED 5.213 + "compiler.err.type.var.more.than.once", // UNUSED 5.214 + "compiler.err.type.var.more.than.once.in.result", // UNUSED 5.215 + "compiler.misc.ccf.found.later.version", // UNUSED 5.216 + "compiler.misc.non.denotable.type", // UNUSED 5.217 + "compiler.misc.unnamed.package", // should be required, CR 6964147 5.218 + "compiler.misc.verbose.retro", // UNUSED 5.219 + "compiler.misc.verbose.retro.with", // UNUSED 5.220 + "compiler.misc.verbose.retro.with.list", // UNUSED 5.221 + "compiler.warn.proc.type.already.exists", // TODO in JavacFiler 5.222 + "javac.err.invalid.arg", // UNUSED ?? 5.223 + "javac.opt.arg.class", // UNUSED ?? 5.224 + "javac.opt.arg.pathname", // UNUSED ?? 5.225 + "javac.opt.moreinfo", // option commented out 5.226 + "javac.opt.nogj", // UNUSED 5.227 + "javac.opt.printflat", // option commented out 5.228 + "javac.opt.printsearch", // option commented out 5.229 + "javac.opt.prompt", // option commented out 5.230 + "javac.opt.retrofit", // UNUSED 5.231 + "javac.opt.s", // option commented out 5.232 + "javac.opt.scramble", // option commented out 5.233 + "javac.opt.scrambleall" // option commented out 5.234 + )); 5.235 + 5.236 + /** 5.237 + * For all strings in the code that look like they might be fragments of 5.238 + * a resource key, verify that a key exists. 5.239 + */ 5.240 + void findMissingKeys(Set<String> codeStrings, Set<String> resourceKeys) { 5.241 + for (String cs: codeStrings) { 5.242 + if (cs.matches("[A-Za-z][^.]*\\..*")) { 5.243 + // ignore filenames (i.e. in SourceFile attribute 5.244 + if (cs.matches(".*\\.java")) 5.245 + continue; 5.246 + // ignore package and class names 5.247 + if (cs.matches("(com|java|javax|sun)\\.[A-Za-z.]+")) 5.248 + continue; 5.249 + // explicit known exceptions 5.250 + if (noResourceRequired.contains(cs)) 5.251 + continue; 5.252 + // look for matching resource 5.253 + if (hasMatch(resourceKeys, cs)) 5.254 + continue; 5.255 + error("no match for \"" + cs + "\""); 5.256 + } 5.257 + } 5.258 + } 5.259 + // where 5.260 + private Set<String> noResourceRequired = new HashSet<String>(Arrays.asList( 5.261 + // system properties 5.262 + "application.home", // in Paths.java 5.263 + "env.class.path", 5.264 + "line.separator", 5.265 + "user.dir", 5.266 + // file names 5.267 + "ct.sym", 5.268 + "rt.jar", 5.269 + "tools.jar", 5.270 + // -XD option names 5.271 + "process.packages", 5.272 + "ignore.symbol.file", 5.273 + // prefix/embedded strings 5.274 + "compiler.", 5.275 + "compiler.misc.", 5.276 + "count.", 5.277 + "illegal.", 5.278 + "javac.", 5.279 + "verbose." 5.280 + )); 5.281 + 5.282 + /** 5.283 + * Look for a resource that ends in this string fragment. 5.284 + */ 5.285 + boolean hasMatch(Set<String> resourceKeys, String s) { 5.286 + for (String rk: resourceKeys) { 5.287 + if (rk.endsWith(s)) 5.288 + return true; 5.289 + } 5.290 + return false; 5.291 + } 5.292 + 5.293 + /** 5.294 + * Get the set of strings from (most of) the javac classfiles. 5.295 + */ 5.296 + Set<String> getCodeStrings() throws IOException { 5.297 + Set<String> results = new TreeSet<String>(); 5.298 + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); 5.299 + JavaFileManager fm = c.getStandardFileManager(null, null, null); 5.300 + String[] pkgs = { 5.301 + "javax.annotation.processing", 5.302 + "javax.lang.model", 5.303 + "javax.tools", 5.304 + "com.sun.source", 5.305 + "com.sun.tools.javac" 5.306 + }; 5.307 + for (String pkg: pkgs) { 5.308 + for (JavaFileObject fo: fm.list(StandardLocation.PLATFORM_CLASS_PATH, 5.309 + pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) { 5.310 + String name = fo.getName(); 5.311 + // ignore resource files, and files which are not really part of javac 5.312 + if (name.contains("resources") 5.313 + || name.contains("Launcher.class") 5.314 + || name.contains("CreateSymbols.class")) 5.315 + continue; 5.316 + scan(fo, results); 5.317 + } 5.318 + } 5.319 + return results; 5.320 + } 5.321 + 5.322 + /** 5.323 + * Get the set of strings from a class file. 5.324 + * Only strings that look like they might be a resource key are returned. 5.325 + */ 5.326 + void scan(JavaFileObject fo, Set<String> results) throws IOException { 5.327 + InputStream in = fo.openInputStream(); 5.328 + try { 5.329 + ClassFile cf = ClassFile.read(in); 5.330 + for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) { 5.331 + if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) { 5.332 + String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value; 5.333 + if (v.matches("[A-Za-z0-9-_.]+")) 5.334 + results.add(v); 5.335 + } 5.336 + } 5.337 + } catch (ConstantPoolException ignore) { 5.338 + } finally { 5.339 + in.close(); 5.340 + } 5.341 + } 5.342 + 5.343 + /** 5.344 + * Get the set of keys from the javac resource bundles. 5.345 + */ 5.346 + Set<String> getResourceKeys() { 5.347 + Set<String> results = new TreeSet<String>(); 5.348 + for (String name : new String[]{"javac", "compiler"}) { 5.349 + ResourceBundle b = 5.350 + ResourceBundle.getBundle("com.sun.tools.javac.resources." + name); 5.351 + results.addAll(b.keySet()); 5.352 + } 5.353 + return results; 5.354 + } 5.355 + 5.356 + /** 5.357 + * Report an error. 5.358 + */ 5.359 + void error(String msg) { 5.360 + System.err.println("Error: " + msg); 5.361 + errors++; 5.362 + } 5.363 + 5.364 + int errors; 5.365 +}
6.1 --- a/test/tools/javac/literals/BadUnderscoreLiterals.6.out Tue Jun 29 12:06:46 2010 -0700 6.2 +++ b/test/tools/javac/literals/BadUnderscoreLiterals.6.out Wed Jun 30 18:06:29 2010 -0700 6.3 @@ -1,4 +1,4 @@ 6.4 -BadUnderscoreLiterals.java:14:17: compiler.err.unsupported.underscore: 1.6 6.5 +BadUnderscoreLiterals.java:14:17: compiler.err.unsupported.underscore.lit: 1.6 6.6 BadUnderscoreLiterals.java:18:15: compiler.err.illegal.underscore 6.7 BadUnderscoreLiterals.java:22:19: compiler.err.illegal.underscore 6.8 BadUnderscoreLiterals.java:25:14: compiler.err.unsupported.binary.lit: 1.6