am 9950dd09: strip <span> tags from document titles for search suggest

* commit '9950dd094869cc176d63050a9e1ac3d0b4053f84':
  strip <span> tags from document titles for search suggest
diff --git a/android-changes.txt b/android-changes.txt
index 025bcd8..a62b071 100644
--- a/android-changes.txt
+++ b/android-changes.txt
@@ -1,6 +1,12 @@
 Changes in this version relative to http://doclava.googlecode.com/
 ------------------------------------------------------------------
 
+* Added a new command line option -showAnnotation <@interface classname>,
+  which takes in a fully qualified annotation classname.  The specified
+  annotation will override any @hide annotations within the javadoc.  To
+  specify multiple annotations to override @hide, use multiple
+  -showAnnotation options.
+
 * Modified the Java stub generator code to write out annotations for
   methods and fields as well, not just classes. This meant adding a
   writeAnnotations call to writeMethod and to writeField
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
index 927b240..d3ed434 100644
--- a/src/com/google/doclava/ClassInfo.java
+++ b/src/com/google/doclava/ClassInfo.java
@@ -247,6 +247,10 @@
     return mIsFinal;
   }
 
+  public boolean isEffectivelyFinal() {
+    return mIsFinal || mApiCheckConstructors.isEmpty();
+  }
+
   public boolean isIncluded() {
     return mIsIncluded;
   }
@@ -1694,10 +1698,25 @@
           + " changed abstract qualifier");
     }
 
-    if (mIsFinal != cl.mIsFinal) {
+    if (!mIsFinal && cl.mIsFinal) {
+      /*
+       * It is safe to make a class final if it did not previously have any public
+       * constructors because it was impossible for an application to create a subclass.
+       */
+      if (mApiCheckConstructors.isEmpty()) {
+        consistent = false;
+        Errors.error(Errors.ADDED_FINAL_UNINSTANTIABLE, cl.position(),
+            "Class " + cl.qualifiedName() + " added final qualifier but "
+            + "was previously uninstantiable and therefore could not be subclassed");
+      } else {
+        consistent = false;
+        Errors.error(Errors.ADDED_FINAL, cl.position(), "Class " + cl.qualifiedName()
+            + " added final qualifier");
+      }
+    } else if (mIsFinal && !cl.mIsFinal) {
       consistent = false;
-      Errors.error(Errors.CHANGED_FINAL, cl.position(), "Class " + cl.qualifiedName()
-          + " changed final qualifier");
+      Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName()
+          + " removed final qualifier");
     }
 
     if (mIsStatic != cl.mIsStatic) {
diff --git a/src/com/google/doclava/Errors.java b/src/com/google/doclava/Errors.java
index 2fc0f0c..e890aa4 100644
--- a/src/com/google/doclava/Errors.java
+++ b/src/com/google/doclava/Errors.java
@@ -134,7 +134,7 @@
   public static Error REMOVED_FIELD = new Error(10, WARNING);
   public static Error REMOVED_INTERFACE = new Error(11, WARNING);
   public static Error CHANGED_STATIC = new Error(12, WARNING);
-  public static Error CHANGED_FINAL = new Error(13, WARNING);
+  public static Error ADDED_FINAL = new Error(13, WARNING);
   public static Error CHANGED_TRANSIENT = new Error(14, WARNING);
   public static Error CHANGED_VOLATILE = new Error(15, WARNING);
   public static Error CHANGED_TYPE = new Error(16, WARNING);
@@ -147,6 +147,8 @@
   public static Error CHANGED_CLASS = new Error(23, WARNING);
   public static Error CHANGED_DEPRECATED = new Error(24, WARNING);
   public static Error CHANGED_SYNCHRONIZED = new Error(25, ERROR);
+  public static Error ADDED_FINAL_UNINSTANTIABLE = new Error(26, WARNING);
+  public static Error REMOVED_FINAL = new Error(27, WARNING);
 
   // Errors in javadoc generation
   public static final Error UNRESOLVED_LINK = new Error(101, WARNING);
@@ -175,10 +177,11 @@
           UNAVAILABLE_SYMBOL, HIDDEN_SUPERCLASS, DEPRECATED, DEPRECATION_MISMATCH, MISSING_COMMENT,
           IO_ERROR, NO_SINCE_DATA, NO_FEDERATION_DATA, PARSE_ERROR, ADDED_PACKAGE, ADDED_CLASS,
           ADDED_METHOD, ADDED_FIELD, ADDED_INTERFACE, REMOVED_PACKAGE, REMOVED_CLASS,
-          REMOVED_METHOD, REMOVED_FIELD, REMOVED_INTERFACE, CHANGED_STATIC, CHANGED_FINAL,
+          REMOVED_METHOD, REMOVED_FIELD, REMOVED_INTERFACE, CHANGED_STATIC, ADDED_FINAL,
           CHANGED_TRANSIENT, CHANGED_VOLATILE, CHANGED_TYPE, CHANGED_VALUE, CHANGED_SUPERCLASS,
           CHANGED_SCOPE, CHANGED_ABSTRACT, CHANGED_THROWS, CHANGED_NATIVE, CHANGED_CLASS,
-          CHANGED_DEPRECATED, CHANGED_SYNCHRONIZED, BROKEN_SINCE_FILE, INVALID_CONTENT_TYPE};
+          CHANGED_DEPRECATED, CHANGED_SYNCHRONIZED, ADDED_FINAL_UNINSTANTIABLE, REMOVED_FINAL,
+          BROKEN_SINCE_FILE, INVALID_CONTENT_TYPE};
 
   public static boolean setErrorLevel(int code, int level) {
     for (Error e : ERRORS) {
diff --git a/src/com/google/doclava/FieldInfo.java b/src/com/google/doclava/FieldInfo.java
index 0200b95..09391a6 100644
--- a/src/com/google/doclava/FieldInfo.java
+++ b/src/com/google/doclava/FieldInfo.java
@@ -438,9 +438,13 @@
       consistent = false;
     }
 
-    if (mIsFinal != fInfo.mIsFinal) {
-      Errors.error(Errors.CHANGED_FINAL, fInfo.position(), "Field " + fInfo.qualifiedName()
-          + " has changed 'final' qualifier");
+    if (!mIsFinal && fInfo.mIsFinal) {
+      Errors.error(Errors.ADDED_FINAL, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has added 'final' qualifier");
+      consistent = false;
+    } else if (mIsFinal && !fInfo.mIsFinal) {
+      Errors.error(Errors.REMOVED_FINAL, fInfo.position(), "Field " + fInfo.qualifiedName()
+          + " has removed 'final' qualifier");
       consistent = false;
     }
 
diff --git a/src/com/google/doclava/MethodInfo.java b/src/com/google/doclava/MethodInfo.java
index db5e0cf..fc8959f 100644
--- a/src/com/google/doclava/MethodInfo.java
+++ b/src/com/google/doclava/MethodInfo.java
@@ -624,6 +624,17 @@
     return mIsVarargs;
   }
 
+  public boolean isEffectivelyFinal() {
+      if (mIsFinal) {
+          return true;
+      }
+      ClassInfo containingClass = containingClass();
+      if (containingClass != null && containingClass.isEffectivelyFinal()) {
+          return true;
+      }
+      return false;
+  }
+
   @Override
   public String toString() {
     return this.name();
@@ -729,17 +740,19 @@
           + " has changed 'native' qualifier");
     }
 
-    if (mIsFinal != mInfo.mIsFinal) {
-      // Compiler-generated methods vary in their 'final' qual between versions of
+    if (!mIsStatic) {
+      // Compiler-generated methods vary in their 'final' qualifier between versions of
       // the compiler, so this check needs to be quite narrow. A change in 'final'
       // status of a method is only relevant if (a) the method is not declared 'static'
-      // and (b) the method's class is not itself 'final'.
-      if (!mIsStatic) {
-        if ((containingClass() == null) || (!containingClass().isFinal())) {
-          consistent = false;
-          Errors.error(Errors.CHANGED_FINAL, mInfo.position(), "Method " + mInfo.qualifiedName()
-              + " has changed 'final' qualifier");
-        }
+      // and (b) the method is not already inferred to be 'final' by virtue of its class.
+      if (!isEffectivelyFinal() && mInfo.isEffectivelyFinal()) {
+        consistent = false;
+        Errors.error(Errors.ADDED_FINAL, mInfo.position(), "Method " + mInfo.qualifiedName()
+            + " has added 'final' qualifier");
+      } else if (isEffectivelyFinal() && !mInfo.isEffectivelyFinal()) {
+        consistent = false;
+        Errors.error(Errors.REMOVED_FINAL, mInfo.position(), "Method " + mInfo.qualifiedName()
+            + " has removed 'final' qualifier");
       }
     }