Generate documentation based on annotations attached to classes and methods

Allow users to pass in a text file of the format:
   annotationname:Documentation String
   annotation2:More Documentation
that will get inserted into the docs when a class or method has
that annotation.

Bug: 19931569
Change-Id: Ic2334dd2fcba638526cf2d67e25e27cf8e39b6fe
diff --git a/res/assets/templates/class.cs b/res/assets/templates/class.cs
index e8cdafd..595dbb8 100644
--- a/res/assets/templates/class.cs
+++ b/res/assets/templates/class.cs
@@ -155,9 +155,12 @@
 
 <div class="jd-descr">
 <?cs call:deprecated_warning(class) ?>
-<?cs if:subcount(class.descr) ?>
+<?cs if:subcount(class.descr) || subcount(class.annotationdocumentation)  ?>
 <h2>Class Overview</h2>
-<p itemprop="articleBody"><?cs call:tag_list(class.descr) ?></p>
+<?cs if:subcount(class.descr) ?><p itemprop="articleBody"><?cs call:tag_list(class.descr) ?></p><?cs /if ?>
+<?cs if:subcount(class.annotationdocumentation) ?><?cs each:annodoc = class.annotationdocumentation ?>
+<p></?cs var:annodoc.text ?></p>
+<?cs /each ?><? /if ?>
 <?cs /if ?>
 
 <?cs call:see_also_tags(class.seeAlso) ?>
diff --git a/res/assets/templates/macros.cs b/res/assets/templates/macros.cs
index 317b36e..eed8737 100644
--- a/res/assets/templates/macros.cs
+++ b/res/assets/templates/macros.cs
@@ -137,6 +137,10 @@
     /if ?>
     <?cs call:tag_list(obj.deprecated) ?></em><?cs
   else ?><?cs call:tag_list(obj.shortDescr) ?><?cs
+  if:subcount(obj.annotationdocumentation)?><?cs
+    each:annodoc=obj.annotationdocumentation ?>
+    <div><?cs var:annodoc.text?></div><?cs
+    /each?><?cs /if?><?cs
   /if ?><?cs
 /def ?>
 
@@ -196,6 +200,10 @@
 def:description(obj) ?><?cs 
   call:deprecated_warning(obj) ?>
   <div class="jd-tagdata jd-tagdescr"><p><?cs call:tag_list(obj.descr) ?></p></div><?cs 
+  if:subcount(obj.annotationdocumentation)?><?cs
+    each:annodoc=obj.annotationdocumentation ?>
+    <div class="jd-tagdata" style="display:block"><?cs var:annodoc.text?></div><?cs
+    /each?><?cs /if?><?cs
   if:subcount(obj.attrRefs) ?>
   <div class="jd-tagdata">
       <h5 class="jd-tagtitle">Related XML Attributes</h5>
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
index 14cd99c..a5ee7d4 100644
--- a/src/com/google/doclava/ClassInfo.java
+++ b/src/com/google/doclava/ClassInfo.java
@@ -1234,6 +1234,17 @@
       data.setValue("class.abstract", "abstract");
     }
 
+    int numAnnotationDocumentation = 0;
+    for (AnnotationInstanceInfo aii : annotations()) {
+      String annotationDocumentation = Doclava.getDocumentationStringForAnnotation(
+          aii.type().qualifiedName());
+      if (annotationDocumentation != null) {
+        data.setValue("class.annotationdocumentation." + numAnnotationDocumentation + ".text",
+            annotationDocumentation);
+        numAnnotationDocumentation++;
+      }
+    }
+
     ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
     AnnotationInstanceInfo.makeLinkListHDF(
       data,
diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java
index 6e46123..94331ee 100644
--- a/src/com/google/doclava/Doclava.java
+++ b/src/com/google/doclava/Doclava.java
@@ -95,6 +95,9 @@
   private static boolean generateDocs = true;
   private static boolean parseComments = false;
   private static String yamlNavFile = null;
+  public static boolean documentAnnotations = false;
+  public static String documentAnnotationsPath = null;
+  public static Map<String, String> annotationDocumentationMap = null;
 
   public static JSilver jSilver = null;
 
@@ -273,6 +276,9 @@
         // Don't copy the doclava assets to devsite output (ie use proj assets only)
         includeDefaultAssets = false;
         outputPathHtmlDirs = outputPathHtmlDirs + "/" + devsiteRoot;
+      } else if (a[0].equals("-documentannotations")) {
+        documentAnnotations = true;
+        documentAnnotationsPath = a[1];
       }
     }
 
@@ -663,6 +669,9 @@
     if (option.equals("-metadataDebug")) {
       return 1;
     }
+    if (option.equals("-documentannotations")) {
+      return 2;
+    }
     return 0;
   }
   public static boolean validOptions(String[][] options, DocErrorReporter r) {
@@ -1816,4 +1825,31 @@
     }
   }
 
+  public static String getDocumentationStringForAnnotation(String annotationName) {
+    if (!documentAnnotations) return null;
+    if (annotationDocumentationMap == null) {
+      // parse the file for map
+      annotationDocumentationMap = new HashMap<String, String>();
+      try {
+        BufferedReader in = new BufferedReader(
+            new FileReader(documentAnnotationsPath));
+        try {
+          String line = in.readLine();
+          String[] split;
+          while (line != null) {
+            split = line.split(":");
+            annotationDocumentationMap.put(split[0], split[1]);
+            line = in.readLine();
+          }
+        } finally {
+          in.close();
+        }
+      } catch (IOException e) {
+        System.err.println("Unable to open annotations documentation file for reading: "
+            + documentAnnotationsPath);
+      }
+    }
+    return annotationDocumentationMap.get(annotationName);
+  }
+
 }
diff --git a/src/com/google/doclava/MethodInfo.java b/src/com/google/doclava/MethodInfo.java
index eb360cd..f1659f3 100644
--- a/src/com/google/doclava/MethodInfo.java
+++ b/src/com/google/doclava/MethodInfo.java
@@ -592,6 +592,18 @@
       TypeInfo.makeHDF(data, base + ".generic.typeArguments", mTypeParameters, false);
     }
 
+    int numAnnotationDocumentation = 0;
+    for (AnnotationInstanceInfo aii : annotations()) {
+      String annotationDocumentation = Doclava.getDocumentationStringForAnnotation(
+          aii.type().qualifiedName());
+      if (annotationDocumentation != null) {
+        data.setValue(base + ".annotationdocumentation." + numAnnotationDocumentation + ".text",
+            annotationDocumentation);
+        numAnnotationDocumentation++;
+      }
+    }
+
+
     AnnotationInstanceInfo.makeLinkListHDF(
       data,
       base + ".showAnnotations",