8000612: Discrepancy between resources provided in javadoc resource files and resources required by code
authorjjg
Tue, 06 Nov 2012 14:32:49 -0800
changeset 14447 6f87132c2e54
parent 14446 88145bb2ddcd
child 14448 91aa6570b59a
8000612: Discrepancy between resources provided in javadoc resource files and resources required by code Reviewed-by: bpatel
langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java
langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java
langtools/src/share/classes/com/sun/tools/javadoc/resources/javadoc.properties
langtools/test/tools/javac/diags/CheckResourceKeys.java
langtools/test/tools/javadoc/CheckResourceKeys.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties	Tue Nov 06 14:45:27 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties	Tue Nov 06 14:32:49 2012 -0800
@@ -41,32 +41,21 @@
 doclet.Help=Help
 doclet.Skip_navigation_links=Skip navigation links
 doclet.New_Page=NewPage
-doclet.None=None
-doclet.Factory_Method_Detail=Static Factory Method Detail
 doclet.navDeprecated=Deprecated
-doclet.Deprecated_List=Deprecated List
 doclet.Window_Deprecated_List=Deprecated List
-doclet.Note_0_is_deprecated=Note: {0} is deprecated.
 doclet.Overrides=Overrides:
 doclet.in_class=in class
-doclet.0_Fields_and_Methods="{0}" Fields and Methods
-doclet.Index_of_Fields_and_Methods=Index of Fields and Methods
 doclet.Static_variable_in=Static variable in {0}
 doclet.Variable_in=Variable in {0}
 doclet.Constructor_for=Constructor for {0}
 doclet.Static_method_in=Static method in {0}
 doclet.Method_in=Method in {0}
-doclet.throws=throws
 doclet.package=package
 doclet.MalformedURL=Malformed URL: {0}
 doclet.File_error=Error reading file: {0}
 doclet.URL_error=Error fetching URL: {0}
-doclet.No_Package_Comment_File=For Package {0} Package.Comment file not found
-doclet.No_Source_For_Class=Source information for class {0} not available.
 doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
 doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
-doclet.see.malformed_tag=Tag {0}: Malformed: {1}
-doclet.Inherited_API_Summary=Inherited API Summary
 doclet.Deprecated_API=Deprecated API
 doclet.Deprecated_Packages=Deprecated Packages
 doclet.Deprecated_Classes=Deprecated Classes
@@ -92,10 +81,7 @@
 doclet.deprecated_methods=deprecated methods
 doclet.deprecated_enum_constants=deprecated enum constants
 doclet.deprecated_annotation_type_members=deprecated annotation type elements
-doclet.Frame_Output=Frame Output
-doclet.Docs_generated_by_Javadoc=Documentation generated by Javadoc.
 doclet.Generated_Docs_Untitled=Generated Documentation (Untitled)
-doclet.Blank=Blank
 doclet.Other_Packages=Other Packages
 doclet.Package_Description=Package {0} Description
 doclet.Description=Description
@@ -105,32 +91,24 @@
 doclet.Subinterfaces=All Known Subinterfaces:
 doclet.Implementing_Classes=All Known Implementing Classes:
 doclet.also=also
-doclet.Option=Option
-doclet.Or=Or
+doclet.FRAMES=FRAMES
 doclet.Frames=Frames
+doclet.NO_FRAMES=NO FRAMES
 doclet.No_Frames=No Frames
 doclet.Package_Hierarchies=Package Hierarchies:
 doclet.Hierarchy_For_Package=Hierarchy For Package {0}
-doclet.Source_Code=Source Code:
 doclet.Hierarchy_For_All_Packages=Hierarchy For All Packages
-doclet.Cannot_handle_no_packages=Cannot handle no packages.
 doclet.Frame_Alert=Frame Alert
-doclet.Overview-Member-Frame=Overview Member Frame
 doclet.Frame_Warning_Message=This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to {0}.
 doclet.No_Script_Message=JavaScript is disabled on your browser.
 doclet.Non_Frame_Version=Non-frame version
-doclet.Frame_Version=Frame version
-doclet.Following_From_Class=Following copied from class: {0}
-doclet.Following_From_Interface=Following copied from interface: {0}
 doclet.Description_From_Interface=Description copied from interface:
 doclet.Description_From_Class=Description copied from class:
-doclet.Standard_doclet_invoked=Standard doclet invoked...
 doclet.No_Non_Deprecated_Classes_To_Document=No non-deprecated classes found to document.
 doclet.Interfaces_Italic=Interfaces (italic)
 doclet.Enclosing_Class=Enclosing class:
 doclet.Enclosing_Interface=Enclosing interface:
 doclet.Window_Source_title=Source code
-doclet.Help_title=API Help
 doclet.Window_Help_title=API Help
 doclet.Help_line_1=How This API Document Is Organized
 doclet.Help_line_2=This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
@@ -168,19 +146,6 @@
 doclet.Help_annotation_type_line_1=Each annotation type has its own separate page with the following sections:
 doclet.Help_annotation_type_line_2=Annotation Type declaration
 doclet.Help_annotation_type_line_3=Annotation Type description
-doclet.Style_line_1=Javadoc style sheet
-doclet.Style_line_2=Define colors, fonts and other style attributes here to override the defaults
-doclet.Style_line_3=Page background color
-doclet.Style_Headings=Headings
-doclet.Style_line_4=Table colors
-doclet.Style_line_5=Dark mauve
-doclet.Style_line_6=Light mauve
-doclet.Style_line_7=White
-doclet.Style_line_8=Font used in left-hand frame lists
-doclet.Style_line_9=Example of smaller, sans-serif font in frames
-doclet.Style_line_10=Navigation bar fonts and colors
-doclet.Style_line_11=Dark Blue
-doclet.Style_line_12=Table caption style
 doclet.ClassUse_Packages.that.use.0=Packages that use {0}
 doclet.ClassUse_Uses.of.0.in.1=Uses of {0} in {1}
 doclet.ClassUse_Classes.in.0.used.by.1=Classes in {0} used by {1}
@@ -210,12 +175,9 @@
 doclet.Window_ClassUse_Header=Uses of {0} {1}
 doclet.ClassUse_Title=Uses of {0}<br>{1}
 doclet.navClassUse=Use
-doclet.link_option_twice=Extern URL link option (link or linkoffline) used twice.
 doclet.Error_in_packagelist=Error in using -group option: {0} {1}
 doclet.Groupname_already_used=In -group option, groupname already used: {0}
 doclet.Same_package_name_used=Package name format used twice: {0}
-doclet.Serialization.Excluded_Class=Non-transient field {1} uses excluded class {0}.
-doclet.Serialization.Nonexcluded_Class=Non-transient field {1} uses hidden, non-included class {0}.
 doclet.exception_encountered=Exception encountered while processing {1}\n{0}
 doclet.usage=Provided by Standard doclet:\n\
   -d <directory>                    Destination directory for output files\n\
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties	Tue Nov 06 14:45:27 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties	Tue Nov 06 14:32:49 2012 -0800
@@ -21,10 +21,8 @@
 doclet.Copying_File_0_To_File_1=Copying file {0} to file {1}...
 doclet.No_Public_Classes_To_Document=No public or protected classes found to document.
 doclet.Unable_to_create_directory_0=Unable to create directory {0}
-doclet.destination_directory_not_found_0=Destination directory not found {0}
 doclet.destination_directory_not_directory_0=Destination directory is not a directory {0}
 doclet.destination_directory_not_writable_0=Destination directory not writable {0}
-doclet.Error_creating_tmp_file=Error creating temporary file, using default platform encoding.
 doclet.Encoding_not_supported=Encoding not supported: {0}
 doclet.Building_Tree=Building tree for all the packages and classes...
 doclet.Building_Index=Building index for all the packages and classes...
@@ -74,7 +72,6 @@
 doclet.Enum_Constant_Summary=Enum Constant Summary
 doclet.Constructor_Summary=Constructor Summary
 doclet.Method_Summary=Method Summary
-doclet.Factory_Method_Summary=Static Factory Method Summary
 doclet.Interfaces=Interfaces
 doclet.Enums=Enums
 doclet.AnnotationTypes=Annotation Types
@@ -88,7 +85,6 @@
 doclet.All_Implemented_Interfaces=All Implemented Interfaces:
 doclet.All_classes_and_interfaces=All classes and interfaces (except non-static nested types)
 doclet.Package_class_and_interface_descriptions=Package, class and interface descriptions
-doclet.Members=Members
 doclet.Interface=Interface
 doclet.Class=Class
 doclet.AnnotationType=Annotation Type
@@ -107,18 +103,13 @@
 doclet.Exception=Exception
 doclet.exception=exception
 doclet.exceptions=exceptions
-doclet.extended_by=extended by
-doclet.extends=extends
 doclet.Package_private=(package private)
-doclet.implements=implementsdoclet.Same_package_name_used=Package name format used twice: {0}
 doclet.Nested_Classes_Interfaces_Inherited_From_Class=Nested classes/interfaces inherited from class
 doclet.Nested_Classes_Interface_Inherited_From_Interface=Nested classes/interfaces inherited from interface
 doclet.Methods_Inherited_From_Class=Methods inherited from class
 doclet.Methods_Inherited_From_Interface=Methods inherited from interface
 doclet.Fields_Inherited_From_Class=Fields inherited from class
 doclet.Fields_Inherited_From_Interface=Fields inherited from interface
-doclet.Serializable=Serializable
-doclet.Externalizable=Externalizable
 doclet.Annotation_Type_Member_Detail=Element Detail
 doclet.Enum_Constant_Detail=Enum Constant Detail
 doclet.Constants_Summary=Constant Field Values
@@ -126,7 +117,6 @@
 doclet.Method_Detail=Method Detail
 doclet.Constructor_Detail=Constructor Detail
 doclet.Deprecated=Deprecated.
-doclet.Deprecated_class=This class is deprecated.
 doclet.Groupname_already_used=In -group option, groupname already used: {0}
 doclet.value_tag_invalid_reference={0} (referenced by @value tag) is an unknown reference.
 doclet.value_tag_invalid_constant=@value tag (which references {0}) can only be used in constants.
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java	Tue Nov 06 14:45:27 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java	Tue Nov 06 14:32:49 2012 -0800
@@ -555,7 +555,7 @@
      *
      * @param cd the ClassDoc to check.
      * @param lowerCaseOnly true if you want the name returned in lower case.
-     *                      If false, the first letter of the name is capatilized.
+     *                      If false, the first letter of the name is capitalized.
      * @return
      */
     public static String getTypeName(Configuration config,
--- a/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java	Tue Nov 06 14:45:27 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java	Tue Nov 06 14:32:49 2012 -0800
@@ -267,8 +267,6 @@
             }
 
             if (referencedClass == null) { /* may just not be in this run */
-//                docenv().warning(holder, "tag.see.class_not_found",
-//                                 where, text);
                 // check if it's a package name
                 referencedPackage = docenv().lookupPackage(where);
                 return;
--- a/langtools/src/share/classes/com/sun/tools/javadoc/resources/javadoc.properties	Tue Nov 06 14:45:27 2012 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/resources/javadoc.properties	Tue Nov 06 14:32:49 2012 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -64,7 +64,6 @@
 main.incompatible.access.flags=More than one of -public, -private, -package, or -protected specified.
 main.cant.read=cannot read {0}
 main.Loading_source_files_for_package=Loading source files for package {0}...
-main.Loading_source_file_for_class=Loading source file for class {0}...
 main.Loading_source_file=Loading source file {0}...
 main.Building_tree=Constructing Javadoc information...
 main.no_source_files_for_package=No source files for package {0}
@@ -96,13 +95,12 @@
 tag.see.can_not_find_member=Tag {0}: can''t find {1} in {2}
 tag.see.no_close_bracket_on_url=Tag {0}: missing final ''>'': "{1}"
 tag.see.no_close_quote=Tag {0}: no final close quote: "{1}"
-tag.see.class_not_found=class {0} not found for @see tag: "{1}"
 tag.see.class_not_specified=Tag {0}: class not specified: "{1}"
 tag.see.illegal_character=Tag {0}:illegal character: "{1}" in "{2}"
 tag.see.malformed_see_tag=Tag {0}: malformed: "{1}"
-tag.throws.exception_not_found={0} tag, class {1} not found.
 tag.End_delimiter_missing_for_possible_SeeTag=End Delimiter } missing for possible See Tag in comment string: "{0}"
 tag.Improper_Use_Of_Link_Tag=Missing closing ''}'' character for inline tag: "{0}"
+tag.serialField.illegal_character=illegal character {0} in @serialField tag: {1}.
 javadoc.File_Read_Error=Error while reading file {0}
 javadoc.Body_missing_from_html_file=Body tag missing from HTML file
 javadoc.End_body_missing_from_html_file=Close body tag missing from HTML file
@@ -110,4 +108,3 @@
 javadoc.class_not_found=Class {0} not found.
 javadoc.error=error
 javadoc.warning=warning
-tag.serialField.illegal_character=illegal character {0} in @serialField tag: {1}.
--- a/langtools/test/tools/javac/diags/CheckResourceKeys.java	Tue Nov 06 14:45:27 2012 +0000
+++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java	Tue Nov 06 14:32:49 2012 -0800
@@ -310,9 +310,9 @@
                     pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) {
                 String name = fo.getName();
                 // ignore resource files, and files which are not really part of javac
-                if (name.contains("resources")
-                        || name.contains("Launcher.class")
-                        || name.contains("CreateSymbols.class"))
+                if (name.matches(".*resources.[A-Za-z_0-9]+\\.class")
+                        || name.endsWith("Launcher.class")
+                        || name.endsWith("CreateSymbols.class"))
                     continue;
                 scan(fo, results);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/CheckResourceKeys.java	Tue Nov 06 14:32:49 2012 -0800
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8000612
+ * @summary need test program to validate javadoc resource bundles
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.tools.*;
+import com.sun.tools.classfile.*;
+
+/**
+ * Compare string constants in javadoc classes against keys in javadoc resource bundles.
+ */
+public class CheckResourceKeys {
+    /**
+     * Main program.
+     * Options:
+     * -finddeadkeys
+     *      look for keys in resource bundles that are no longer required
+     * -findmissingkeys
+     *      look for keys in resource bundles that are missing
+     *
+     * @throws Exception if invoked by jtreg and errors occur
+     */
+    public static void main(String... args) throws Exception {
+        CheckResourceKeys c = new CheckResourceKeys();
+        if (c.run(args))
+            return;
+
+        if (is_jtreg())
+            throw new Exception(c.errors + " errors occurred");
+        else
+            System.exit(1);
+    }
+
+    static boolean is_jtreg() {
+        return (System.getProperty("test.src") != null);
+    }
+
+    /**
+     * Main entry point.
+     */
+    boolean run(String... args) throws Exception {
+        boolean findDeadKeys = false;
+        boolean findMissingKeys = false;
+
+        if (args.length == 0) {
+            if (is_jtreg()) {
+                findDeadKeys = true;
+                findMissingKeys = true;
+            } else {
+                System.err.println("Usage: java CheckResourceKeys <options>");
+                System.err.println("where options include");
+                System.err.println("  -finddeadkeys      find keys in resource bundles which are no longer required");
+                System.err.println("  -findmissingkeys   find keys in resource bundles that are required but missing");
+                return true;
+            }
+        } else {
+            for (String arg: args) {
+                if (arg.equalsIgnoreCase("-finddeadkeys"))
+                    findDeadKeys = true;
+                else if (arg.equalsIgnoreCase("-findmissingkeys"))
+                    findMissingKeys = true;
+                else
+                    error("bad option: " + arg);
+            }
+        }
+
+        if (errors > 0)
+            return false;
+
+        Set<String> codeKeys = getCodeKeys();
+        Set<String> resourceKeys = getResourceKeys();
+
+        System.err.println("found " + codeKeys.size() + " keys in code");
+        System.err.println("found " + resourceKeys.size() + " keys in resource bundles");
+
+        if (findDeadKeys)
+            findDeadKeys(codeKeys, resourceKeys);
+
+        if (findMissingKeys)
+            findMissingKeys(codeKeys, resourceKeys);
+
+        return (errors == 0);
+    }
+
+    /**
+     * Find keys in resource bundles which are probably no longer required.
+     * A key is required if there is a string in the code that is a resource key,
+     * or if the key is well-known according to various pragmatic rules.
+     */
+    void findDeadKeys(Set<String> codeKeys, Set<String> resourceKeys) {
+        for (String rk: resourceKeys) {
+            if (codeKeys.contains(rk))
+                continue;
+
+            error("Resource key not found in code: " + rk);
+        }
+    }
+
+    /**
+     * For all strings in the code that look like they might be
+     * a resource key, verify that a key exists.
+     */
+    void findMissingKeys(Set<String> codeKeys, Set<String> resourceKeys) {
+        for (String ck: codeKeys) {
+            if (resourceKeys.contains(ck))
+                continue;
+            error("No resource for \"" + ck + "\"");
+        }
+    }
+
+    /**
+     * Get the set of strings from (most of) the javadoc classfiles.
+     */
+    Set<String> getCodeKeys() throws IOException {
+        Set<String> results = new TreeSet<String>();
+        JavaCompiler c = ToolProvider.getSystemJavaCompiler();
+        JavaFileManager fm = c.getStandardFileManager(null, null, null);
+        JavaFileManager.Location javadocLoc = findJavadocLocation(fm);
+        String[] pkgs = {
+            "com.sun.tools.doclets",
+            "com.sun.tools.javadoc"
+        };
+        for (String pkg: pkgs) {
+            for (JavaFileObject fo: fm.list(javadocLoc,
+                    pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) {
+                String name = fo.getName();
+                // ignore resource files
+                if (name.matches(".*resources.[A-Za-z_0-9]+\\.class"))
+                    continue;
+                scan(fo, results);
+            }
+        }
+
+        // special handling for code strings synthesized in
+        // com.sun.tools.doclets.internal.toolkit.util.Util.getTypeName
+        String[] extras = {
+            "AnnotationType", "Class", "Enum", "Error", "Exception", "Interface"
+        };
+        for (String s: extras) {
+            if (results.contains("doclet." + s))
+                results.add("doclet." + s.toLowerCase());
+        }
+
+        return results;
+    }
+
+    // depending on how the test is run, javadoc may be on bootclasspath or classpath
+    JavaFileManager.Location findJavadocLocation(JavaFileManager fm) {
+        JavaFileManager.Location[] locns =
+            { StandardLocation.PLATFORM_CLASS_PATH, StandardLocation.CLASS_PATH };
+        try {
+            for (JavaFileManager.Location l: locns) {
+                JavaFileObject fo = fm.getJavaFileForInput(l,
+                    "com.sun.tools.javadoc.Main", JavaFileObject.Kind.CLASS);
+                if (fo != null) {
+                    System.err.println("found javadoc in " + l);
+                    return l;
+                }
+            }
+        } catch (IOException e) {
+            throw new Error(e);
+        }
+        throw new IllegalStateException("Cannot find javadoc");
+    }
+
+    /**
+     * Get the set of strings from a class file.
+     * Only strings that look like they might be a resource key are returned.
+     */
+    void scan(JavaFileObject fo, Set<String> results) throws IOException {
+        //System.err.println("scan " + fo.getName());
+        InputStream in = fo.openInputStream();
+        try {
+            ClassFile cf = ClassFile.read(in);
+            for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) {
+                if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) {
+                    String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value;
+                    if (v.matches("(doclet|main|javadoc|tag)\\.[A-Za-z0-9-_.]+"))
+                        results.add(v);
+                }
+            }
+        } catch (ConstantPoolException ignore) {
+        } finally {
+            in.close();
+        }
+    }
+
+    /**
+     * Get the set of keys from the javadoc resource bundles.
+     */
+    Set<String> getResourceKeys() {
+        String[] names = {
+                "com.sun.tools.doclets.formats.html.resources.standard",
+                "com.sun.tools.doclets.internal.toolkit.resources.doclets",
+                "com.sun.tools.javadoc.resources.javadoc",
+        };
+        Set<String> results = new TreeSet<String>();
+        for (String name : names) {
+            ResourceBundle b = ResourceBundle.getBundle(name);
+            results.addAll(b.keySet());
+        }
+        return results;
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}