8004825: javadoc crash DocletAbortException
authorbpatel
Wed, 25 Sep 2013 22:26:42 -0700
changeset 20264 f7527e6828bb
parent 20263 e7ce67bbe293
child 20265 8bd6f1a9ac24
8004825: javadoc crash DocletAbortException Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/ValueTaglet.java
langtools/test/com/sun/javadoc/testValueTag/TestValueTag.java
langtools/test/com/sun/javadoc/testValueTag/pkg1/Class1.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties	Wed Sep 25 14:04:24 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties	Wed Sep 25 22:26:42 2013 -0700
@@ -136,6 +136,7 @@
 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.
+doclet.value_tag_invalid_use=@value tag cannot be used here.
 doclet.dest_dir_create=Creating destination directory: "{0}"
 doclet.in={0} in {1}
 doclet.Use_Table_Summary=Use table, listing {0}, and an explanation
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/ValueTaglet.java	Wed Sep 25 14:04:24 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/ValueTaglet.java	Wed Sep 25 22:26:42 2013 -0700
@@ -105,7 +105,9 @@
     }
 
     /**
-     * Given the name of the field, return the corresponding FieldDoc.
+     * Given the name of the field, return the corresponding FieldDoc. Return null
+     * due to invalid use of value tag if the name is null or empty string and if
+     * the value tag is not used on a field.
      *
      * @param config the current configuration of the doclet.
      * @param tag the value tag.
@@ -114,10 +116,8 @@
      * it is assumed that the field is in the current class.
      *
      * @return the corresponding FieldDoc. If the name is null or empty string,
-     * return field that the value tag was used in.
-     *
-     * @throws DocletAbortException if the value tag does not specify a name to
-     * a value field and it is not used within the comments of a valid field.
+     * return field that the value tag was used in. Return null if the name is null
+     * or empty string and if the value tag is not used on a field.
      */
     private FieldDoc getFieldDoc(Configuration config, Tag tag, String name) {
         if (name == null || name.length() == 0) {
@@ -125,8 +125,9 @@
             if (tag.holder() instanceof FieldDoc) {
                 return (FieldDoc) tag.holder();
             } else {
-                //This should never ever happen.
-                throw new DocletAbortException("should not happen");
+                // If the value tag does not specify a parameter which is a valid field and
+                // it is not used within the comments of a valid field, return null.
+                 return null;
             }
         }
         StringTokenizer st = new StringTokenizer(name, "#");
@@ -165,9 +166,15 @@
         FieldDoc field = getFieldDoc(
             writer.configuration(), tag, tag.text());
         if (field == null) {
-            //Reference is unknown.
-            writer.getMsgRetriever().warning(tag.holder().position(),
-                "doclet.value_tag_invalid_reference", tag.text());
+            if (tag.text().isEmpty()) {
+                //Invalid use of @value
+                writer.getMsgRetriever().warning(tag.holder().position(),
+                        "doclet.value_tag_invalid_use");
+            } else {
+                //Reference is unknown.
+                writer.getMsgRetriever().warning(tag.holder().position(),
+                        "doclet.value_tag_invalid_reference", tag.text());
+            }
         } else if (field.constantValue() != null) {
             return writer.valueTagOutput(field,
                 field.constantValueExpression(),
--- a/langtools/test/com/sun/javadoc/testValueTag/TestValueTag.java	Wed Sep 25 14:04:24 2013 -0700
+++ b/langtools/test/com/sun/javadoc/testValueTag/TestValueTag.java	Wed Sep 25 22:26:42 2013 -0700
@@ -23,13 +23,12 @@
 
 /*
  * @test
- * @bug      4764045
+ * @bug      4764045 8004825
  * @summary  This test ensures that the value tag works in all
  * use cases. The explainations for each test case are written below.
  * @author   jamieh
  * @library  ../lib/
- * @build    JavadocTester
- * @build    TestValueTag
+ * @build    JavadocTester TestValueTag
  * @run main TestValueTag
  */
 
@@ -41,8 +40,14 @@
     //Javadoc arguments.
     private static final String[] ARGS =
         new String[] {
+            "-d", BUG_ID, "-sourcepath", SRC_DIR, "-tag",
+            "todo", "pkg1", "pkg2"
+        };
+
+    private static final String[] ARGS1 =
+        new String[] {
             "-Xdoclint:none",
-            "-d", BUG_ID, "-sourcepath", SRC_DIR, "-tag",
+            "-d", BUG_ID + "-1", "-sourcepath", SRC_DIR, "-tag",
             "todo", "pkg1", "pkg2"
         };
 
@@ -91,16 +96,58 @@
         {BUG_ID + FS + "pkg1" + FS + "CustomTagUsage.html",
             "<dt><span class=\"strong\">Todo:</span></dt>" + NL +
                 "<dd>the value of this constant is 55.</dd>"},
+        //Test @value errors printed dues to invalid use or when used with
+        //non-constant or with bad references.
+        {ERROR_OUTPUT,"error: value does not refer to a constant" + NL +
+            "     * Result:  {@value TEST_12_ERROR}"
+        },
+        {ERROR_OUTPUT,"error: {@value} not allowed here" + NL +
+            "     * Result:  {@value}"
+        },
+        {ERROR_OUTPUT,"error: value does not refer to a constant" + NL +
+            "     * Result:  {@value NULL}"
+        },
+        {ERROR_OUTPUT,"error: {@value} not allowed here" + NL +
+            "     * Invalid (null): {@value}"
+        },
+        {ERROR_OUTPUT,"error: {@value} not allowed here" + NL +
+            "     * Invalid (non-constant field): {@value}"
+        },
+        {ERROR_OUTPUT,"error: value does not refer to a constant" + NL +
+            "     * Here is a bad value reference: {@value UnknownClass#unknownConstant}"
+        },
+        {ERROR_OUTPUT,"error: reference not found" + NL +
+            "     * Here is a bad value reference: {@value UnknownClass#unknownConstant}"
+        },
+        {ERROR_OUTPUT,"error: {@value} not allowed here" + NL +
+            "     * @todo the value of this constant is {@value}"
+        }
+    };
+    private static final String[][] TEST1 = {
         //Test @value warning printed when used with non-constant.
         {WARNING_OUTPUT,"warning - @value tag (which references nonConstant) " +
             "can only be used in constants."
         },
+        {WARNING_OUTPUT,"warning - @value tag (which references NULL) " +
+            "can only be used in constants."
+        },
+        {WARNING_OUTPUT,"warning - @value tag (which references TEST_12_ERROR) " +
+            "can only be used in constants."
+        },
         //Test warning printed for bad reference.
         {WARNING_OUTPUT,"warning - UnknownClass#unknownConstant (referenced by " +
             "@value tag) is an unknown reference."
         },
+        //Test warning printed for invalid use of @value.
+        {WARNING_OUTPUT,"warning - @value tag cannot be used here."
+        }
     };
-    private static final String[][] NEGATED_TEST = NO_TEST;
+    private static final String[][] NEGATED_TEST = {
+        //Base case:  using @value on a constant.
+        {BUG_ID + FS + "pkg1" + FS + "Class1.html",
+            "Result:  <a href=\"../pkg1/Class1.html#TEST_12_ERROR\">\"Test 12 " +
+            "generates an error message\"</a>"},
+    };
 
     /**
      * The entry point of the test.
@@ -109,9 +156,18 @@
     public static void main(String[] args) {
         TestValueTag tester = new TestValueTag();
         run(tester, ARGS, TEST, NEGATED_TEST);
+        checkForException(tester);
+        run(tester, ARGS1, TEST1, NO_TEST);
+        checkForException(tester);
         tester.printSummary();
     }
 
+    public static void checkForException(TestValueTag tester) {
+        if (tester.getErrorOutput().contains("DocletAbortException")) {
+            throw new AssertionError("javadoc threw DocletAbortException");
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
--- a/langtools/test/com/sun/javadoc/testValueTag/pkg1/Class1.java	Wed Sep 25 14:04:24 2013 -0700
+++ b/langtools/test/com/sun/javadoc/testValueTag/pkg1/Class1.java	Wed Sep 25 22:26:42 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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
@@ -45,6 +45,16 @@
     public static final String TEST_11_PASSES = "Test 11 passes";
 
     /**
+     * Invalid (non-constant field): {@value}
+     */
+    public static String TEST_12_ERROR = "Test 12 generates an error message";
+
+    /**
+     * Invalid (null): {@value}
+     */
+    public static final String NULL = null;
+
+    /**
      * Result:  {@value TEST_3_PASSES}
      */
     public int field;
@@ -60,6 +70,21 @@
     public void method() {}
 
     /**
+     * Result:  {@value TEST_12_ERROR}
+     */
+    public void invalidValueTag1() {}
+
+    /**
+     * Result:  {@value}
+     */
+    public void invalidValueTag2() {}
+
+    /**
+     * Result:  {@value NULL}
+     */
+    public void testNullConstant() {}
+
+    /**
      * Result:  {@value pkg1.Class1#TEST_6_PASSES}
      */
     public class NestedClass{}