Add support to doclava for default / static interface methods

This change removes code that forces all interface methods to be
abstract. It also passes the new "is default" information to all
the places that require it.

Includes changes to the doclava template. Ordering of
method declaration modifiers changed slightly to reflect the ordering
given in:

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.3
http://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.4

This change *requires* the JDK 8 version of javadoc.

Bug: 26241119
Change-Id: Iccd3006ab52585cc7529e4924bbeea9aef36f046
diff --git a/res/assets/templates/class.cs b/res/assets/templates/class.cs
index e35e938..8854eaf 100644
--- a/res/assets/templates/class.cs
+++ b/res/assets/templates/class.cs
@@ -177,8 +177,9 @@
     <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:method.since ?>" >
         <td class="jd-typecol"><nobr>
             <?cs var:method.abstract ?>
-            <?cs var:method.final ?>
+            <?cs var:method.default ?>
             <?cs var:method.static ?>
+            <?cs var:method.final ?>
             <?cs call:type_link(method.generic) ?>
             <?cs call:type_link(method.returnType) ?></nobr>
         </td>
@@ -523,10 +524,11 @@
 <div class="jd-details api apilevel-<?cs var:method.since ?>"> 
     <h4 class="jd-details-title">
       <span class="normal">
-        <?cs var:method.scope ?> 
-        <?cs var:method.static ?> 
-        <?cs var:method.final ?> 
-        <?cs var:method.abstract ?> 
+        <?cs var:method.scope ?>
+        <?cs var:method.abstract ?>
+        <?cs var:method.default ?>
+        <?cs var:method.static ?>
+        <?cs var:method.final ?>
         <?cs call:type_link(method.returnType) ?>
       </span>
       <span class="sympad"><?cs var:method.name ?></span>
diff --git a/src/com/google/doclava/Converter.java b/src/com/google/doclava/Converter.java
index af3068e..1bc3563 100644
--- a/src/com/google/doclava/Converter.java
+++ b/src/com/google/doclava/Converter.java
@@ -404,8 +404,9 @@
                     m.name(), m.signature(), Converter.obtainClass(m.containingClass()),
                     Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
                     .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
-                    m.isAbstract(), m.isSynchronized(), m.isNative(), true, "annotationElement",
-                    m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()),
+                    m.isAbstract(), m.isSynchronized(), m.isNative(), m.isDefault(), true,
+                    "annotationElement", m.flatSignature(),
+                    Converter.obtainMethod(m.overriddenMethod()),
                     Converter.obtainType(m.returnType()),
                     new ArrayList<ParameterInfo>(Arrays.asList(
                             Converter.convertParameters(m.parameters(), m))),
@@ -425,8 +426,8 @@
                     Converter.obtainClass(m.containingClass()),
                     Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(),
                     m.isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
-                    m.isAbstract(), m.isSynchronized(), m.isNative(), false, "method",
-                    m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()),
+                    m.isAbstract(), m.isSynchronized(), m.isNative(), m.isDefault(), false,
+                    "method", m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()),
                     Converter.obtainType(m.returnType()),
                     new ArrayList<ParameterInfo>(Arrays.asList(
                             Converter.convertParameters(m.parameters(), m))),
@@ -459,7 +460,7 @@
                 name, m.signature(), Converter.obtainClass(m.containingClass()), Converter
                 .obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
                 .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
-                false, m.isSynchronized(), m.isNative(), false, "constructor", m.flatSignature(),
+                false, m.isSynchronized(), m.isNative(), false/*isDefault*/, false, "constructor", m.flatSignature(),
                 null, null, new ArrayList<ParameterInfo>(Arrays.asList(Converter.convertParameters(m.parameters(), m))),
                 new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(m.thrownExceptions()))), Converter.convertSourcePosition(m
                     .position()), new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter.convertAnnotationInstances(m.annotations()))));
diff --git a/src/com/google/doclava/InfoBuilder.java b/src/com/google/doclava/InfoBuilder.java
index 9f7e340..895f5b6 100644
--- a/src/com/google/doclava/InfoBuilder.java
+++ b/src/com/google/doclava/InfoBuilder.java
@@ -1070,7 +1070,7 @@
                 modifiers.isPrivate(), modifiers.isFinal(),
                 modifiers.isStatic(), modifiers.isSynthetic(),
                 modifiers.isAbstract(), modifiers.isSynchronized(),
-                false, isAnnotationElement, kind, flatSignature.toString(),
+                false, modifiers.isDefault(), isAnnotationElement, kind, flatSignature.toString(),
                 null, returnType, parameters, thrownExceptions,
                 commentAndPosition.getPosition(), modifiers.getAnnotations());
 
@@ -1854,6 +1854,7 @@
         private boolean mIsSynthetic = false;
         private boolean mIsSynchronized = false;
         private boolean mIsStrictfp = false;
+        private boolean mIsDefault = false;
         private InfoBuilder mBuilder;
         private ArrayList<AnnotationInstanceInfo> mAnnotations;
 
@@ -1895,6 +1896,8 @@
                     mIsSynchronized = true;
                 }  else if ("strictfp".equals(modifier)) {
                     mIsStrictfp = true;
+                }  else if ("default".equals(modifier)) {
+                    mIsDefault = true;
                 } else if ("annotation".equals(modifier)) {
                     mAnnotations.add(buildAnnotationInstance((ParseTree) child, mBuilder));
                 }
@@ -1950,6 +1953,10 @@
             return mIsStrictfp;
         }
 
+        public boolean isDefault() {
+            return mIsDefault;
+        }
+
         public ArrayList<AnnotationInstanceInfo> getAnnotations() {
             return mAnnotations;
         }
diff --git a/src/com/google/doclava/MethodInfo.java b/src/com/google/doclava/MethodInfo.java
index 2986027..02157aa 100644
--- a/src/com/google/doclava/MethodInfo.java
+++ b/src/com/google/doclava/MethodInfo.java
@@ -252,7 +252,7 @@
         new MethodInfo(getRawCommentText(), mTypeParameters, name(), signature(),
             newContainingClass, realContainingClass(), isPublic(), isProtected(),
             isPackagePrivate(), isPrivate(), isFinal(), isStatic(), isSynthetic(), mIsAbstract,
-            mIsSynchronized, mIsNative, mIsAnnotationElement, kind(), mFlatSignature,
+            mIsSynchronized, mIsNative, mIsDefault, mIsAnnotationElement, kind(), mFlatSignature,
             mOverriddenMethod, returnType, mParameters, mThrownExceptions, position(),
             annotations());
     result.init(mDefaultAnnotationElementValue);
@@ -263,10 +263,10 @@
       String signature, ClassInfo containingClass, ClassInfo realContainingClass, boolean isPublic,
       boolean isProtected, boolean isPackagePrivate, boolean isPrivate, boolean isFinal,
       boolean isStatic, boolean isSynthetic, boolean isAbstract, boolean isSynchronized,
-      boolean isNative, boolean isAnnotationElement, String kind, String flatSignature,
-      MethodInfo overriddenMethod, TypeInfo returnType, ArrayList<ParameterInfo> parameters,
-      ArrayList<ClassInfo> thrownExceptions, SourcePositionInfo position,
-      ArrayList<AnnotationInstanceInfo> annotations) {
+      boolean isNative, boolean isDefault, boolean isAnnotationElement, String kind,
+      String flatSignature, MethodInfo overriddenMethod, TypeInfo returnType,
+      ArrayList<ParameterInfo> parameters, ArrayList<ClassInfo> thrownExceptions,
+      SourcePositionInfo position, ArrayList<AnnotationInstanceInfo> annotations) {
     // Explicitly coerce 'final' state of Java6-compiled enum values() method, to match
     // the Java5-emitted base API description.
     super(rawCommentText, name, signature, containingClass, realContainingClass, isPublic,
@@ -274,19 +274,13 @@
         ((name.equals("values") && containingClass.isEnum()) ? true : isFinal),
         isStatic, isSynthetic, kind, position, annotations);
 
-    // The underlying MethodDoc for an interface's declared methods winds up being marked
-    // non-abstract. Correct that here by looking at the immediate-parent class, and marking
-    // this method abstract if it is an unimplemented interface method.
-    if (containingClass.isInterface()) {
-      isAbstract = true;
-    }
-
     mReasonOpened = "0:0";
     mIsAnnotationElement = isAnnotationElement;
     mTypeParameters = typeParameters;
     mIsAbstract = isAbstract;
     mIsSynchronized = isSynchronized;
     mIsNative = isNative;
+    mIsDefault = isDefault;
     mFlatSignature = flatSignature;
     mOverriddenMethod = overriddenMethod;
     mReturnType = returnType;
@@ -310,6 +304,10 @@
     return mIsNative;
   }
 
+  public boolean isDefault() {
+    return mIsDefault;
+  }
+
   public String flatSignature() {
     return mFlatSignature;
   }
@@ -576,6 +574,7 @@
       data.setValue(base + ".abstract", mIsAbstract ? "abstract" : "");
     }
 
+    data.setValue(base + ".default", mIsDefault ? "default" : "");
     data.setValue(base + ".synchronized", mIsSynchronized ? "synchronized" : "");
     data.setValue(base + ".final", isFinal() ? "final" : "");
     data.setValue(base + ".static", isStatic() ? "static" : "");
@@ -719,6 +718,7 @@
   private boolean mIsVarargs;
   private boolean mDeprecatedKnown;
   private boolean mIsDeprecated;
+  private boolean mIsDefault;
   private ArrayList<ParameterInfo> mParameters;
   private ArrayList<ClassInfo> mThrownExceptions;
   private String[] mParamStrings;
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 21d7d4b..7c94f9b 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -632,6 +632,9 @@
 
     writeAnnotations(stream, method.annotations(), method.isDeprecated());
 
+    if (method.isDefault()) {
+      stream.print("default ");
+    }
     stream.print(method.scope() + " ");
     if (method.isStatic()) {
       stream.print("static ");
@@ -684,7 +687,7 @@
         comma = ", ";
       }
     }
-    if (method.isAbstract() || method.isNative() || method.containingClass().isInterface()) {
+    if (method.isAbstract() || method.isNative() || (method.containingClass().isInterface() && (!method.isDefault() && !method.isStatic()))) {
       stream.println(";");
     } else {
       stream.print(" { ");
@@ -1355,6 +1358,9 @@
   static void writeMethodApi(PrintStream apiWriter, MethodInfo mi) {
     apiWriter.print("    method ");
     apiWriter.print(mi.scope());
+    if (mi.isDefault()) {
+      apiWriter.print(" default");
+    }
     if (mi.isStatic()) {
       apiWriter.print(" static");
     }
diff --git a/src/com/google/doclava/apicheck/ApiFile.java b/src/com/google/doclava/apicheck/ApiFile.java
index 81783fc..2d958d4 100644
--- a/src/com/google/doclava/apicheck/ApiFile.java
+++ b/src/com/google/doclava/apicheck/ApiFile.java
@@ -254,7 +254,7 @@
     method = new MethodInfo(""/*rawCommentText*/, new ArrayList<TypeInfo>()/*typeParameters*/,
         name, null/*signature*/, cl, cl, pub, prot, pkgpriv, false/*isPrivate*/, false/*isFinal*/,
         false/*isStatic*/, false/*isSynthetic*/, false/*isAbstract*/, false/*isSynthetic*/,
-        false/*isNative*/,
+        false/*isNative*/, false/* isDefault */,
         false /*isAnnotationElement*/, "constructor", null/*flatSignature*/,
         null/*overriddenMethod*/, cl.asTypeInfo(), new ArrayList<ParameterInfo>(),
         new ArrayList<ClassInfo>()/*thrownExceptions*/, tokenizer.pos(),
@@ -282,6 +282,7 @@
     boolean abs = false;
     boolean dep = false;
     boolean syn = false;
+    boolean def = false;
     String type;
     String name;
     String ext = null;
@@ -296,6 +297,10 @@
     } else {
       pkgpriv = true;
     }
+    if ("default".equals(token)) {
+      def = true;
+      token = tokenizer.requireToken();
+    }
     if ("static".equals(token)) {
       stat = true;
       token = tokenizer.requireToken();
@@ -323,7 +328,7 @@
     name = token;
     method = new MethodInfo(""/*rawCommentText*/, new ArrayList<TypeInfo>()/*typeParameters*/,
         name, null/*signature*/, cl, cl, pub, prot, pkgpriv, false/*isPrivate*/, fin,
-        stat, false/*isSynthetic*/, abs/*isAbstract*/, syn, false/*isNative*/,
+        stat, false/*isSynthetic*/, abs/*isAbstract*/, syn, false/*isNative*/, def/*isDefault*/,
         false /*isAnnotationElement*/, "method", null/*flatSignature*/, null/*overriddenMethod*/,
         Converter.obtainTypeFromString(type), new ArrayList<ParameterInfo>(),
         new ArrayList<ClassInfo>()/*thrownExceptions*/, tokenizer.pos(),
diff --git a/src/com/google/doclava/apicheck/XmlApiFile.java b/src/com/google/doclava/apicheck/XmlApiFile.java
index 562fcea..d36766b 100644
--- a/src/com/google/doclava/apicheck/XmlApiFile.java
+++ b/src/com/google/doclava/apicheck/XmlApiFile.java
@@ -139,6 +139,7 @@
       boolean isAbstract = Boolean.valueOf(attributes.getValue("abstract"));
       boolean isSynchronized = Boolean.valueOf(attributes.getValue("synchronized"));
       boolean isNative = Boolean.valueOf(attributes.getValue("native"));
+      boolean isDefault = Boolean.valueOf(attributes.getValue("default"));
       boolean isAnnotationElement = false; // TODO
       String kind = qName;
       String flatSignature = null; // TODO
@@ -152,9 +153,9 @@
       mCurrentMethod = 
           new MethodInfo(rawCommentText, typeParameters, name, signature, containingClass,
           realContainingClass, isPublic, isProtected, isPackagePrivate, isPrivate, isFinal,
-          isStatic, isSynthetic, isAbstract, isSynchronized, isNative, isAnnotationElement, kind,
-          flatSignature, overriddenMethod, returnType, parameters, thrownExceptions, position,
-          annotations);
+          isStatic, isSynthetic, isAbstract, isSynchronized, isNative, isDefault,
+          isAnnotationElement, kind, flatSignature, overriddenMethod, returnType, parameters,
+          thrownExceptions, position, annotations);
       
       mCurrentMethod.setDeprecated("deprecated".equals(attributes.getValue("deprecated")));
     } else if (qName.equals("constructor")) {
@@ -166,9 +167,9 @@
               attributes.getValue("name"), null/*signature*/, mCurrentClass, mCurrentClass,
               pub, prot, pkgpriv, false/*isPrivate*/, false/*isFinal*/, false/*isStatic*/,
               false/*isSynthetic*/, false/*isAbstract*/, false/*isSynthetic*/, false/*isNative*/,
-              false /*isAnnotationElement*/, "constructor", null/*flatSignature*/,
-              null/*overriddenMethod*/, mCurrentClass.asTypeInfo(), new ArrayList<ParameterInfo>(),
-              new ArrayList<ClassInfo>()/*thrownExceptions*/,
+              false/*isDefault*/, false/*isAnnotationElement*/, "constructor",
+              null/*flatSignature*/, null/*overriddenMethod*/, mCurrentClass.asTypeInfo(),
+              new ArrayList<ParameterInfo>(), new ArrayList<ClassInfo>()/*thrownExceptions*/,
               SourcePositionInfo.fromXml(attributes.getValue("source")),
               new ArrayList<AnnotationInstanceInfo>()/*annotations*/);
       mCurrentMethod.setDeprecated("deprecated".equals(attributes.getValue("deprecated")));