test/jdk/javadoc/tool/CheckResourceKeys.java

Print this page




  89                 else
  90                     error("bad option: " + arg);
  91             }
  92         }
  93 
  94         if (errors > 0)
  95             return false;
  96 
  97         Set<String> codeKeys = getCodeKeys();
  98         Set<String> resourceKeys = getResourceKeys();
  99 
 100         System.err.println("found " + codeKeys.size() + " keys in code");
 101         System.err.println("found " + resourceKeys.size() + " keys in resource bundles");
 102 
 103         if (findDeadKeys)
 104             findDeadKeys(codeKeys, resourceKeys);
 105 
 106         if (findMissingKeys)
 107             findMissingKeys(codeKeys, resourceKeys);
 108 



 109         return (errors == 0);
 110     }
 111 




















 112     /**
 113      * Find keys in resource bundles which are probably no longer required.
 114      * A key is required if there is a string in the code that is a resource key,
 115      * or if the key is well-known according to various pragmatic rules.
 116      */
 117     void findDeadKeys(Set<String> codeKeys, Set<String> resourceKeys) {
 118         for (String rk: resourceKeys) {



 119             if (codeKeys.contains(rk))
 120                 continue;
 121 
 122             error("Resource key not found in code: " + rk);
 123         }
 124     }
 125 
 126     /**
 127      * For all strings in the code that look like they might be
 128      * a resource key, verify that a key exists.
 129      */
 130     void findMissingKeys(Set<String> codeKeys, Set<String> resourceKeys) {
 131         for (String ck: codeKeys) {



 132             if (resourceKeys.contains(ck))
 133                 continue;
 134             error("No resource for \"" + ck + "\"");
 135         }
 136     }
 137 
 138     /**
 139      * Get the set of strings from (most of) the javadoc classfiles.
 140      */
 141     Set<String> getCodeKeys() throws IOException {
 142         Set<String> results = new TreeSet<String>();
 143         JavaCompiler c = ToolProvider.getSystemJavaCompiler();
 144         try (JavaFileManager fm = c.getStandardFileManager(null, null, null)) {
 145             JavaFileManager.Location javadocLoc = findJavadocLocation(fm);
 146             String[] pkgs = {
 147                 "com.sun.tools.doclets",
 148                 "com.sun.tools.javadoc"
 149             };
 150             for (String pkg: pkgs) {
 151                 for (JavaFileObject fo: fm.list(javadocLoc,
 152                         pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) {
 153                     String name = fo.getName();
 154                     // ignore resource files
 155                     if (name.matches(".*resources.[A-Za-z_0-9]+\\.class.*"))
 156                         continue;
 157                     scan(fo, results);
 158                 }
 159             }
 160 
 161             // special handling for code strings synthesized in
 162             // com.sun.tools.doclets.internal.toolkit.util.Util.getTypeName
 163             String[] extras = {
 164                 "AnnotationType", "Class", "Enum", "Error", "Exception", "Interface"
 165             };
 166             for (String s: extras) {
 167                 if (results.contains("doclet." + s))
 168                     results.add("doclet." + s.toLowerCase());
 169             }
 170 
 171             // special handling for code strings synthesized in
 172             // com.sun.tools.javadoc.Messager
 173             results.add("javadoc.error.msg");
 174             results.add("javadoc.note.msg");
 175             results.add("javadoc.note.pos.msg");
 176             results.add("javadoc.warning.msg");
 177 
 178             return results;
 179         }
 180     }
 181 
 182     // depending on how the test is run, javadoc may be on bootclasspath or classpath
 183     JavaFileManager.Location findJavadocLocation(JavaFileManager fm) {
 184         JavaFileManager.Location[] locns =
 185             { StandardLocation.PLATFORM_CLASS_PATH, StandardLocation.CLASS_PATH };
 186         try {
 187             for (JavaFileManager.Location l: locns) {
 188                 JavaFileObject fo = fm.getJavaFileForInput(l,
 189                     "com.sun.tools.javadoc.Main", JavaFileObject.Kind.CLASS);
 190                 if (fo != null) {
 191                     System.err.println("found javadoc in " + l);
 192                     return l;
 193                 }
 194             }
 195         } catch (IOException e) {
 196             throw new Error(e);
 197         }
 198         throw new IllegalStateException("Cannot find javadoc");
 199     }
 200 
 201     /**
 202      * Get the set of strings from a class file.
 203      * Only strings that look like they might be a resource key are returned.
 204      */
 205     void scan(JavaFileObject fo, Set<String> results) throws IOException {
 206         //System.err.println("scan " + fo.getName());
 207         InputStream in = fo.openInputStream();
 208         try {
 209             ClassFile cf = ClassFile.read(in);
 210             for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) {
 211                 if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) {
 212                     String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value;
 213                     if (v.matches("(doclet|main|javadoc|tag)\\.[A-Za-z0-9-_.]+"))
 214                         results.add(v);
 215                 }
 216             }
 217         } catch (ConstantPoolException ignore) {
 218         } finally {
 219             in.close();
 220         }
 221     }
 222 
 223     /**
 224      * Get the set of keys from the javadoc resource bundles.
 225      */
 226     Set<String> getResourceKeys() {
 227         String[] names = {
 228                 "com.sun.tools.doclets.formats.html.resources.standard",
 229                 "com.sun.tools.doclets.internal.toolkit.resources.doclets",
 230                 "com.sun.tools.javadoc.resources.javadoc",
 231         };
 232         Set<String> results = new TreeSet<String>();
 233         for (String name : names) {
 234             ResourceBundle b = ResourceBundle.getBundle(name);
 235             results.addAll(b.keySet());
 236         }
 237         return results;
 238     }
 239 
 240     /**
 241      * Report an error.
 242      */
 243     void error(String msg) {
 244         System.err.println("Error: " + msg);
 245         errors++;
 246     }
 247 
 248     int errors;
 249 }


  89                 else
  90                     error("bad option: " + arg);
  91             }
  92         }
  93 
  94         if (errors > 0)
  95             return false;
  96 
  97         Set<String> codeKeys = getCodeKeys();
  98         Set<String> resourceKeys = getResourceKeys();
  99 
 100         System.err.println("found " + codeKeys.size() + " keys in code");
 101         System.err.println("found " + resourceKeys.size() + " keys in resource bundles");
 102 
 103         if (findDeadKeys)
 104             findDeadKeys(codeKeys, resourceKeys);
 105 
 106         if (findMissingKeys)
 107             findMissingKeys(codeKeys, resourceKeys);
 108 
 109         usageTests(false);
 110         usageTests(true);
 111 
 112         return (errors == 0);
 113     }
 114 
 115     void usageTests(boolean xflag) {
 116         String[] argarray = { xflag ? "-X" : "-help" };
 117         StringWriter sw = new StringWriter();
 118         PrintWriter pw = new PrintWriter(sw);
 119         if (jdk.javadoc.internal.tool.Main.execute(argarray, pw) == 0) {
 120             pw.flush();
 121             String s = sw.toString();
 122             if (s.isEmpty()) {
 123                 error("no javadoc output ?");
 124                 return;
 125             }
 126             if (sw.toString().contains("<MISSING KEY>")) {
 127                 System.out.println(s);
 128                 error("missing resources in output ?");
 129             }
 130         } else {
 131             error("failed to execute javadoc");
 132         }
 133     }
 134 
 135     /**
 136      * Find keys in resource bundles which are probably no longer required.
 137      * A key is required if there is a string in the code that is a resource key,
 138      * or if the key is well-known according to various pragmatic rules.
 139      */
 140     void findDeadKeys(Set<String> codeKeys, Set<String> resourceKeys) {
 141         for (String rk: resourceKeys) {
 142             // ignore these synthesized keys, tested by usageTests
 143             if (rk.startsWith("doclet.usage.") || rk.startsWith("doclet.xusage"))
 144                 continue;
 145             if (codeKeys.contains(rk))
 146                 continue;
 147 
 148             error("Resource key not found in code: " + rk);
 149         }
 150     }
 151 
 152     /**
 153      * For all strings in the code that look like they might be
 154      * a resource key, verify that a key exists.
 155      */
 156     void findMissingKeys(Set<String> codeKeys, Set<String> resourceKeys) {
 157         for (String ck: codeKeys) {
 158             // ignore these synthesized keys, tested by usageTests
 159             if (ck.startsWith("doclet.usage.") || ck.startsWith("doclet.xusage."))
 160                 continue;
 161             if (resourceKeys.contains(ck))
 162                 continue;
 163             error("No resource for \"" + ck + "\"");
 164         }
 165     }
 166 
 167     /**
 168      * Get the set of strings from (most of) the javadoc classfiles.
 169      */
 170     Set<String> getCodeKeys() throws IOException {
 171         Set<String> results = new TreeSet<String>();
 172         JavaCompiler c = ToolProvider.getSystemJavaCompiler();
 173         try (JavaFileManager fm = c.getStandardFileManager(null, null, null)) {
 174             JavaFileManager.Location javadocLoc = findJavadocLocation(fm);
 175             String[] pkgs = {
 176                 "jdk.javadoc.internal.doclets",
 177                 "jdk.javadoc.internal.tool"
 178             };
 179             for (String pkg: pkgs) {
 180                 for (JavaFileObject fo: fm.list(javadocLoc,
 181                         pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) {
 182                     String name = fo.getName();
 183                     // ignore resource files
 184                     if (name.matches(".*resources.[A-Za-z_0-9]+\\.class.*"))
 185                         continue;
 186                     scan(fo, results);
 187                 }
 188             }
 189 
 190             // special handling for code strings synthesized in
 191             // com.sun.tools.doclets.internal.toolkit.util.Util.getTypeName
 192             String[] extras = {
 193                 "AnnotationType", "Class", "Enum", "Error", "Exception", "Interface"
 194             };
 195             for (String s: extras) {
 196                 if (results.contains("doclet." + s))
 197                     results.add("doclet." + s.toLowerCase());
 198             }
 199 
 200             // special handling for code strings synthesized in
 201             // com.sun.tools.javadoc.Messager
 202             results.add("javadoc.error.msg");
 203             results.add("javadoc.note.msg");
 204             results.add("javadoc.note.pos.msg");
 205             results.add("javadoc.warning.msg");
 206 
 207             return results;
 208         }
 209     }
 210 
 211     // depending on how the test is run, javadoc may be on bootclasspath or classpath
 212     JavaFileManager.Location findJavadocLocation(JavaFileManager fm) {
 213         JavaFileManager.Location[] locns =
 214             { StandardLocation.PLATFORM_CLASS_PATH, StandardLocation.CLASS_PATH };
 215         try {
 216             for (JavaFileManager.Location l: locns) {
 217                 JavaFileObject fo = fm.getJavaFileForInput(l,
 218                     "jdk.javadoc.internal.tool.Main", JavaFileObject.Kind.CLASS);
 219                 if (fo != null) {
 220                     System.err.println("found javadoc in " + l);
 221                     return l;
 222                 }
 223             }
 224         } catch (IOException e) {
 225             throw new Error(e);
 226         }
 227         throw new IllegalStateException("Cannot find javadoc");
 228     }
 229 
 230     /**
 231      * Get the set of strings from a class file.
 232      * Only strings that look like they might be a resource key are returned.
 233      */
 234     void scan(JavaFileObject fo, Set<String> results) throws IOException {
 235         //System.err.println("scan " + fo.getName());
 236         InputStream in = fo.openInputStream();
 237         try {
 238             ClassFile cf = ClassFile.read(in);
 239             for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) {
 240                 if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) {
 241                     String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value;
 242                     if (v.matches("(doclet|main|javadoc|tag)\\.[A-Za-z0-9-_.]+"))
 243                         results.add(v);
 244                 }
 245             }
 246         } catch (ConstantPoolException ignore) {
 247         } finally {
 248             in.close();
 249         }
 250     }
 251 
 252     /**
 253      * Get the set of keys from the javadoc resource bundles.
 254      */
 255     Set<String> getResourceKeys() {
 256         String[] names = {
 257                 "jdk.javadoc.internal.doclets.formats.html.resources.standard",
 258                 "jdk.javadoc.internal.doclets.toolkit.resources.doclets",
 259                 "jdk.javadoc.internal.tool.resources.javadoc",
 260         };
 261         Set<String> results = new TreeSet<String>();
 262         for (String name : names) {
 263             ResourceBundle b = ResourceBundle.getBundle(name);
 264             results.addAll(b.keySet());
 265         }
 266         return results;
 267     }
 268 
 269     /**
 270      * Report an error.
 271      */
 272     void error(String msg) {
 273         System.err.println("Error: " + msg);
 274         errors++;
 275     }
 276 
 277     int errors;
 278 }