summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandroid-build-prod (mdb) <android-build-team-robot@google.com>2020-09-08 22:20:41 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2020-09-08 22:20:41 +0000
commitd08742d64d7e2b84eb348ab599ee49f74715f54c (patch)
tree4097c6984c74d6f1d777ba9631814ec54743e92f
parent08bc827b428b81ce79c3592a9bd8cd1edc36e78b (diff)
parent04d430d38de94b978e85b2d13b9d7ff0ead9900f (diff)
downloadplatform_external_doclava-androidx-mediarouter-release.tar.gz
platform_external_doclava-androidx-mediarouter-release.tar.bz2
platform_external_doclava-androidx-mediarouter-release.zip
Merge "Snap for 6820526 from 0dd0bcb5eefdcb7cd75fc30db2d75467fdfacef0 to androidx-mediarouter-release" into androidx-mediarouter-releaseandroidx-mediarouter-release
-rw-r--r--METADATA3
-rw-r--r--OWNERS3
-rw-r--r--build.gradle17
-rw-r--r--res/assets/templates-sdk/assets/css/default.css17
-rw-r--r--res/assets/templates-sdk/class.cs25
-rw-r--r--res/assets/templates-sdk/compatchanges.cs47
-rw-r--r--res/assets/templates-sdk/macros_override.cs12
-rw-r--r--res/assets/templates-sdk/page_info.cs7
-rw-r--r--res/assets/templates/macros.cs15
-rw-r--r--src/com/google/doclava/AndroidAuxSource.java40
-rw-r--r--src/com/google/doclava/ClassInfo.java1
-rw-r--r--src/com/google/doclava/Comment.java52
-rw-r--r--src/com/google/doclava/CompatInfo.java255
-rw-r--r--src/com/google/doclava/Converter.java16
-rw-r--r--src/com/google/doclava/DocInfo.java15
-rw-r--r--src/com/google/doclava/Doclava.java91
-rw-r--r--src/com/google/doclava/Errors.java1
-rw-r--r--src/com/google/doclava/NavTree.java1
-rw-r--r--src/com/google/doclava/SeeTagInfo.java12
-rw-r--r--src/com/google/doclava/Stubs.java49
20 files changed, 555 insertions, 124 deletions
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+ license_type: NOTICE
+}
diff --git a/OWNERS b/OWNERS
index 080f8f8..dd69424 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,3 +2,6 @@
# Please update this list if you find better candidates.
jsharkey@android.com
smain@google.com # for files under res/
+ddougherty@google.com
+tiem@google.com
+tnorbye@google.com
diff --git a/build.gradle b/build.gradle
index cf0c9d4..bb0ff5f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -78,7 +78,17 @@ dependencies {
testCompile 'junit:junit:4.12'
// tools.jar required for com.sun.javadoc
- compile files(((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs())
+ def currentJvmVersion = org.gradle.api.JavaVersion.current()
+ def toolsJar;
+ if (currentJvmVersion.getMajorVersion() == "8") {
+ toolsJar = ((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs()
+ } else if (System.env.JAVA_TOOLS_JAR != null) {
+ toolsJar = System.env.JAVA_TOOLS_JAR
+ } else {
+ throw new Exception("If you are not using Java 8, JAVA_TOOLS_JAR env variable " +
+ "needs to be set to build Doclava")
+ }
+ compile files(toolsJar)
}
sourceSets {
@@ -111,3 +121,8 @@ task dist(type: Zip, dependsOn: uploadArchives) {
logger.lifecycle "Compressed maven artifacts to ${archivePath}"
}
}
+
+tasks.withType(JavaCompile) {
+ // Suppress build warnings that we're not interested in: b/154755010
+ options.warnings = false
+}
diff --git a/res/assets/templates-sdk/assets/css/default.css b/res/assets/templates-sdk/assets/css/default.css
index 65d7fde..2abfe73 100644
--- a/res/assets/templates-sdk/assets/css/default.css
+++ b/res/assets/templates-sdk/assets/css/default.css
@@ -2552,25 +2552,10 @@ div.design-announce p {
}
.expandable {
- height:34px;
+ height:auto;
padding-left:20px;
position:relative;
}
-.expandable:before {
- content: '';
- background-image: url(../images/styles/disclosure_down.png);
- background-repeat:no-repeat;
- background-position: -12px -9px;
- width: 20px;
- height: 20px;
- display: inline-block;
- position: absolute;
- top: 0;
- left: 0; }
-}
-.expandable.expanded:before {
- background-image: url(../images/styles/disclosure_up.png);
-}
/* notice box for cross links between Design/Develop docs */
a.notice-developers-video,
diff --git a/res/assets/templates-sdk/class.cs b/res/assets/templates-sdk/class.cs
index 9b5a370..5fb2a9d 100644
--- a/res/assets/templates-sdk/class.cs
+++ b/res/assets/templates-sdk/class.cs
@@ -685,31 +685,6 @@ if:subcount(class.subclasses.direct) && !class.subclasses.hidden ?>
</div><!-- end jd-content -->
-<?cs if:devsite ?>
-
-<div class="data-reference-resources-wrapper">
- <?cs if:subcount(class.package) ?>
- <ul data-reference-resources>
- <?cs call:list("Annotations", class.package.annotations) ?>
- <?cs call:list("Interfaces", class.package.interfaces) ?>
- <?cs call:list("Classes", class.package.classes) ?>
- <?cs call:list("Enums", class.package.enums) ?>
- <?cs call:list("Exceptions", class.package.exceptions) ?>
- <?cs call:list("Errors", class.package.errors) ?>
- </ul>
- <?cs elif:subcount(package) ?>
- <ul data-reference-resources>
- <?cs call:class_link_list("Annotations", package.annotations) ?>
- <?cs call:class_link_list("Interfaces", package.interfaces) ?>
- <?cs call:class_link_list("Classes", package.classes) ?>
- <?cs call:class_link_list("Enums", package.enums) ?>
- <?cs call:class_link_list("Exceptions", package.exceptions) ?>
- <?cs call:class_link_list("Errors", package.errors) ?>
- </ul>
- <?cs /if ?>
-</div>
-<?cs /if ?>
-
<?cs if:!devsite ?>
<?cs include:"footer.cs" ?>
<?cs include:"trailer.cs" ?>
diff --git a/res/assets/templates-sdk/compatchanges.cs b/res/assets/templates-sdk/compatchanges.cs
new file mode 100644
index 0000000..001b937
--- /dev/null
+++ b/res/assets/templates-sdk/compatchanges.cs
@@ -0,0 +1,47 @@
+<?cs # THIS CREATES THE COMPAT CONFIG DOCS FROM compatconfig.xml ?>
+<?cs include:"macros.cs" ?>
+<?cs include:"macros_override.cs" ?>
+
+<?cs include:"doctype.cs" ?>
+<html<?cs if:devsite ?> devsite<?cs /if ?>>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"body_tag.cs" ?>
+<div itemscope itemtype="http://developers.google.com/ReferenceObject">
+<?cs include:"header.cs" ?>
+<?cs # Includes api-info-block DIV at top of page. Standard Devsite uses right nav. ?>
+<?cs if:dac ?><?cs include:"page_info.cs" ?><?cs /if ?>
+<?cs # This DIV spans the entire document to provide scope for some scripts ?>
+<div id="jd-content" >
+
+<?cs each:change=change ?>
+ <h3 class="api-name" id="<?cs var:change.name ?>"><?cs var:change.name ?></h3>
+ <div>Value: <?cs var:change.id ?></div>
+ <div>
+ <?cs if:change.loggingOnly ?>
+ Used for logging only.
+ <?cs else ?>
+ <?cs if:change.disabled ?>
+ Disabled for all apps.
+ <?cs else ?>
+ Enabled for
+ <?cs if:change.enableAfterTargetSdk ?>
+ apps with a <code>targetSdkVersion</code> of greater than
+ <?cs var:change.enableAfterTargetSdk ?>.
+ <?cs else ?>
+ all apps.
+ <?cs /if ?>
+ <?cs /if ?>
+ <?cs /if ?>
+ </div>
+
+ <?cs call:description(change) ?>
+<?cs /each ?>
+
+</div>
+<?cs if:!devsite ?>
+<?cs include:"footer.cs" ?>
+<?cs include:"trailer.cs" ?>
+<?cs /if ?>
+</div><!-- end devsite ReferenceObject -->
+</body>
+</html>
diff --git a/res/assets/templates-sdk/macros_override.cs b/res/assets/templates-sdk/macros_override.cs
index 8ef81cf..5c0c482 100644
--- a/res/assets/templates-sdk/macros_override.cs
+++ b/res/assets/templates-sdk/macros_override.cs
@@ -68,6 +68,7 @@ def:aux_tag_list(tags) ?><?cs
elif:tag.kind == "@permission" ?><?cs call:dump_permission(tag) ?><?cs
elif:tag.kind == "@service" ?><?cs call:dump_service(tag) ?><?cs
elif:tag.kind == "@feature" ?><?cs call:dump_feature(tag) ?><?cs
+ elif:tag.kind == "@column" ?><?cs call:dump_column(tag) ?><?cs
/if ?><?cs
/each ?></p><?cs
/def ?><?cs
@@ -143,3 +144,14 @@ def:dump_feature(tag) ?>Requires the <?cs
call:tag_list(tag.values[0].commentTags) ?> feature which can be detected using <?cs
call:tag_list(tag.values[1].commentTags) ?>.<?cs
/def ?>
+
+# Print output for @column tags ?><?cs
+def:dump_column(tag) ?>This constant represents a column name that can be used with a <?cs
+ call:tag_list(tag.values[0].commentTags) ?> through a <?cs
+ call:tag_list(tag.values[1].commentTags) ?> or <?cs
+ call:tag_list(tag.values[2].commentTags) ?> object. The values stored in this column are <?cs
+ call:tag_list(tag.values[3].commentTags) ?><?cs
+ if tag.readOnly ?>, and are read-only and cannot be mutated<?cs
+ else ?><?cs
+ /if ?>.<?cs
+/def ?>
diff --git a/res/assets/templates-sdk/page_info.cs b/res/assets/templates-sdk/page_info.cs
index 8585ee1..5fe6f7b 100644
--- a/res/assets/templates-sdk/page_info.cs
+++ b/res/assets/templates-sdk/page_info.cs
@@ -27,13 +27,6 @@ elif:subcount(class)
<?cs if:class.artifact ?>
<br><?cs call:artifact_tags(class) ?>
<?cs /if ?>
- <?cs if:class.deprecatedsince ?><?cs
- if:class.artifact ?><br>Deprecated since version <?cs var:class.deprecatedsince ?><?cs
- else ?><br>Deprecated since
- <a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level
- <?cs var:class.deprecatedsince ?></a><?cs
- /if ?>
- <?cs /if ?>
<?cs call:federated_refs(class) ?>
</div>
diff --git a/res/assets/templates/macros.cs b/res/assets/templates/macros.cs
index 13a884f..db502bb 100644
--- a/res/assets/templates/macros.cs
+++ b/res/assets/templates/macros.cs
@@ -267,17 +267,24 @@ def:see_also_tags(also) ?><?cs
def:since_tags(obj) ?><?cs
if:reference.apilevels && obj.since ?><?cs
if:string.slice(obj.since,0,1) > 0 ?>
- added in <?cs
+ Added in <?cs
if:string.find(obj.since,'.') > -1
?><a href="<?cs var:toroot ?>topic/libraries/support-library/revisions.html">version<?cs
else
?><a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level<?cs
/if ?> <?cs
var:obj.since ?></a><?cs
- else ?>
- <b><a href="<?cs var:toroot ?>preview/">Android <?cs var:obj.since ?> Developer Preview</a></b><?cs
+ else ?><a data-version-added="<?cs var:obj.since ?>" href="<?cs var:toroot ?>preview/"><b>Added in Android <?cs
+ var:obj.since ?></b></a><?cs
/if?><?cs
-/if ?><?cs
+/if ?>
+ <?cs if:obj.deprecatedsince ?><?cs
+ if:class.artifact ?><br>Deprecated in version <?cs var:obj.deprecatedsince ?><?cs
+ else ?><br>Deprecated in
+ <a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level
+ <?cs var:obj.deprecatedsince ?></a><?cs
+ /if ?>
+ <?cs /if ?><?cs
/def ?><?cs
# print the artifact ?><?cs
diff --git a/src/com/google/doclava/AndroidAuxSource.java b/src/com/google/doclava/AndroidAuxSource.java
index 1c97b18..ca1fbd0 100644
--- a/src/com/google/doclava/AndroidAuxSource.java
+++ b/src/com/google/doclava/AndroidAuxSource.java
@@ -219,6 +219,46 @@ public class AndroidAuxSource implements AuxSource {
valueTags.toArray(TagInfo.getArray(valueTags.size()))));
}
+ // Document provider columns
+ if ((type == TYPE_FIELD) && annotation.type().qualifiedNameMatches("android", "Column")) {
+ String value = null;
+ boolean readOnly = false;
+ for (AnnotationValueInfo val : annotation.elementValues()) {
+ switch (val.element().name()) {
+ case "value":
+ value = String.valueOf(val.value());
+ break;
+ case "readOnly":
+ readOnly = Boolean.parseBoolean(String.valueOf(val.value()));
+ break;
+ }
+ }
+
+ ArrayList<TagInfo> valueTags = new ArrayList<>();
+ valueTags.add(new ParsedTagInfo("", "",
+ "{@link android.content.ContentProvider}", null, SourcePositionInfo.UNKNOWN));
+ valueTags.add(new ParsedTagInfo("", "",
+ "{@link android.content.ContentValues}", null, SourcePositionInfo.UNKNOWN));
+ valueTags.add(new ParsedTagInfo("", "",
+ "{@link android.database.Cursor}", null, SourcePositionInfo.UNKNOWN));
+
+ ClassInfo cursorClass = annotation.type().findClass("android.database.Cursor");
+ for (FieldInfo field : cursorClass.fields()) {
+ if (field.isHiddenOrRemoved()) continue;
+ if (String.valueOf(field.constantValue()).equals(value)) {
+ valueTags.add(new ParsedTagInfo("", "",
+ "{@link android.database.Cursor#" + field.name() + "}",
+ null, SourcePositionInfo.UNKNOWN));
+ }
+ }
+ if (valueTags.size() < 4) continue;
+
+ Map<String, String> args = new HashMap<>();
+ if (readOnly) args.put("readOnly", "true");
+ tags.add(new AuxTagInfo("@column", "@column", SourcePositionInfo.UNKNOWN, args,
+ valueTags.toArray(TagInfo.getArray(valueTags.size()))));
+ }
+
// The remaining annotations below always appear on return docs, and
// should not be included in the method body
if (type == TYPE_METHOD) continue;
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
index dbe7783..2a5db75 100644
--- a/src/com/google/doclava/ClassInfo.java
+++ b/src/com/google/doclava/ClassInfo.java
@@ -39,7 +39,6 @@ import java.util.TreeMap;
import java.util.function.Predicate;
public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped, Resolvable {
-
/**
* Contains a ClassInfo and a TypeInfo.
* <p>
diff --git a/src/com/google/doclava/Comment.java b/src/com/google/doclava/Comment.java
index 63ace55..29154c2 100644
--- a/src/com/google/doclava/Comment.java
+++ b/src/com/google/doclava/Comment.java
@@ -30,9 +30,14 @@ public class Comment {
private static final Set<String> KNOWN_TAGS = new HashSet<String>(Arrays.asList(new String[] {
"@apiNote",
"@author",
- "@since",
"@version",
+ //not used by metalava for Android docs (see @apiSince)
+ "@since",
+ //value is an Android API level (set automatically by metalava)
+ "@apiSince",
"@deprecated",
+ //value is an Android API level (set automatically by metalava)
+ "@deprecatedSince",
"@undeprecate",
"@docRoot",
"@sdkCurrent",
@@ -45,8 +50,6 @@ public class Comment {
"@implNote",
"@implSpec",
"@usesMathJax",
- "@deprecatedSince",
- "@apiSince",
}));
public Comment(String text, ContainerInfo base, SourcePositionInfo sp) {
@@ -287,8 +290,6 @@ public class Comment {
for (char c = text.charAt(index);
index < endOfBlock && !isWhitespaceChar(c); c = text.charAt(index++)) {}
-
- //
if (index == startOfBlock+1) {
return;
}
@@ -330,6 +331,10 @@ public class Comment {
mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
} else if (name.equals("@param")) {
mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
+ } else if (name.equals("@apiSince")) {
+ setApiSince(text);
+ } else if (name.equals("@deprecatedSince")) {
+ setDeprecatedSince(text);
} else if (name.equals("@see")) {
mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
} else if (name.equals("@link")) {
@@ -387,8 +392,16 @@ public class Comment {
known = Doclava.knownTags.contains(name);
}
if (!known) {
- Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
- "Unknown tag: " + name);
+ if (name.length() >= 2 && Character.isUpperCase(name.charAt(1))) {
+ // This is a workaround for b/135928616 where parsing of comments fails when there is
+ // a Java annotation and not a tag.
+ Errors.error(Errors.JAVA_TAG_IN_COMMENT,
+ pos == null ? null : new SourcePositionInfo(pos),
+ "Invalid tag: " + name);
+ } else {
+ Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
+ "Unknown tag: " + name);
+ }
}
TagInfo t = new TextTagInfo(name, name, text, pos);
if (isInline) {
@@ -526,6 +539,29 @@ public class Comment {
return mRemoved;
}
+ public void setDeprecatedSince(String since) {
+ if (since != null) {
+ since = since.trim();
+ }
+ mDeprecatedSince = since;
+ }
+
+ public String getDeprecatedSince() {
+ return mDeprecatedSince;
+ }
+
+ public void setApiSince(String since) {
+ if (since != null) {
+ since = since.trim();
+ }
+ mApiSince = since;
+ }
+
+ public String getApiSince() {
+ //return the value of @apiSince, an API level in Android
+ return mApiSince;
+ }
+
public boolean isDocOnly() {
if (mDocOnly == null) {
mDocOnly = (mText != null) && (mText.indexOf("@doconly") >= 0);
@@ -601,6 +637,8 @@ public class Comment {
Boolean mRemoved = null;
Boolean mDocOnly = null;
Boolean mDeprecated = null;
+ String mDeprecatedSince;
+ String mApiSince;
String mText;
ContainerInfo mBase;
SourcePositionInfo mPosition;
diff --git a/src/com/google/doclava/CompatInfo.java b/src/com/google/doclava/CompatInfo.java
new file mode 100644
index 0000000..167f6ab
--- /dev/null
+++ b/src/com/google/doclava/CompatInfo.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.doclava;
+
+import com.google.clearsilver.jsilver.data.Data;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+public class CompatInfo {
+
+ public static class CompatChange {
+ public final String name;
+ public final long id;
+ public final String description;
+ public final String definedInClass;
+ public final String sourceFile;
+ public final int sourceLine;
+ public final boolean disabled;
+ public final boolean loggingOnly;
+ public final int enableAfterTargetSdk;
+
+
+ CompatChange(String name, long id, String description, String definedInClass,
+ String sourceFile, int sourceLine, boolean disabled, boolean loggingOnly,
+ int enableAfterTargetSdk) {
+ this.name = name;
+ this.id = id;
+ this.description = description;
+ this.definedInClass = definedInClass;
+ this.sourceFile = sourceFile;
+ this.sourceLine = sourceLine;
+ this.disabled = disabled;
+ this.loggingOnly = loggingOnly;
+ this.enableAfterTargetSdk = enableAfterTargetSdk;
+ }
+
+ static class Builder {
+ private String mName;
+ private long mId;
+ private String mDescription;
+ private String mDefinedInClass;
+ private String mSourceFile;
+ private int mSourceLine;
+ private boolean mDisabled;
+ private boolean mLoggingOnly;
+ private int mEnableAfterTargetSdk;
+
+ CompatChange build() {
+ return new CompatChange(
+ mName, mId, mDescription, mDefinedInClass, mSourceFile, mSourceLine,
+ mDisabled, mLoggingOnly, mEnableAfterTargetSdk);
+ }
+
+ Builder name(String name) {
+ mName = name;
+ return this;
+ }
+
+ Builder id(long id) {
+ mId = id;
+ return this;
+ }
+
+ Builder description(String description) {
+ mDescription = description;
+ return this;
+ }
+
+ Builder definedInClass(String definedInClass) {
+ mDefinedInClass = definedInClass;
+ return this;
+ }
+
+ Builder sourcePosition(String sourcePosition) throws SAXException {
+ if (sourcePosition != null) {
+ int colonPos = sourcePosition.indexOf(":");
+ if (colonPos == -1) {
+ throw new SAXException("Invalid source position: " + sourcePosition);
+ }
+ mSourceFile = sourcePosition.substring(0, colonPos);
+ try {
+ mSourceLine = Integer.parseInt(sourcePosition.substring(colonPos + 1));
+ } catch (NumberFormatException nfe) {
+ throw new SAXException("Invalid source position: " + sourcePosition, nfe);
+ }
+ }
+ return this;
+ }
+
+ boolean parseBool(String value) {
+ if (value == null) {
+ return false;
+ }
+ boolean result = Boolean.parseBoolean(value);
+ return result;
+ }
+
+ Builder disabled(String disabled) {
+ mDisabled = parseBool(disabled);
+ return this;
+ }
+
+ Builder loggingOnly(String loggingOnly) {
+ mLoggingOnly = parseBool(loggingOnly);
+ return this;
+ }
+
+ Builder enableAfterTargetSdk(String enableAfter) throws SAXException {
+ if (enableAfter == null) {
+ mEnableAfterTargetSdk = 0;
+ } else {
+ try {
+ mEnableAfterTargetSdk = Integer.parseInt(enableAfter);
+ } catch (NumberFormatException nfe) {
+ throw new SAXException("Invalid SDK version int: " + enableAfter, nfe);
+ }
+ }
+ return this;
+ }
+ }
+
+ }
+
+ private class CompatConfigXmlParser extends DefaultHandler {
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ if (qName.equals("compat-change")) {
+ mCurrentChange = new CompatChange.Builder();
+ String idStr = attributes.getValue("id");
+ if (idStr == null) {
+ throw new SAXException("<compat-change> element has no id");
+ }
+ try {
+ mCurrentChange.id(Long.parseLong(idStr));
+ } catch (NumberFormatException nfe) {
+ throw new SAXException("<compat-change> id is not a valid long", nfe);
+ }
+ mCurrentChange.name(attributes.getValue("name"))
+ .description(attributes.getValue("description"))
+ .enableAfterTargetSdk(attributes.getValue("enableAfterTargetSdk"))
+ .disabled(attributes.getValue("disabled"))
+ .loggingOnly(attributes.getValue("loggingOnly"));
+
+ } else if (qName.equals("meta-data")) {
+ if (mCurrentChange == null) {
+ throw new SAXException("<meta-data> tag with no enclosing <compat-change>");
+ }
+ mCurrentChange.definedInClass(attributes.getValue("definedIn"))
+ .sourcePosition(attributes.getValue("sourcePosition"));
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) {
+ if (qName.equals("compat-change")) {
+ mChanges.add(mCurrentChange.build());
+ mCurrentChange = null;
+ }
+ }
+ }
+
+ public static CompatInfo readCompatConfig(String source) {
+ CompatInfo config = new CompatInfo();
+ try {
+ InputStream in = new FileInputStream(new File(source));
+
+ XMLReader xmlreader = XMLReaderFactory.createXMLReader();
+ xmlreader.setContentHandler(config.mXmlParser);
+ xmlreader.setErrorHandler(config.mXmlParser);
+ xmlreader.parse(new InputSource(in));
+ in.close();
+ return config;
+ } catch (SAXException e) {
+ throw new RuntimeException("Failed to parse " + source, e);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to read " + source, e);
+ }
+ }
+
+ private final CompatConfigXmlParser mXmlParser = new CompatConfigXmlParser();
+ private CompatChange.Builder mCurrentChange;
+ private List<CompatChange> mChanges = new ArrayList<>();
+
+ public List<CompatChange> getChanges() {
+ return mChanges;
+ }
+
+ public void makeHDF(Data hdf) {
+ // We construct a Comment for each compat change to re-use the default docs generation support
+ // for comments.
+ mChanges.sort(Comparator.comparing(a -> a.name));
+ for (int i = 0; i < mChanges.size(); ++i) {
+ CompatInfo.CompatChange change = mChanges.get(i);
+ // we will get null ClassInfo here if the defining class is not in the SDK.
+ ContainerInfo definedInContainer = Converter.obtainClass(change.definedInClass);
+ if (definedInContainer == null) {
+ // This happens when the class defining the @ChangeId constant is not included in
+ // the sources that the SDK docs are generated from. Using package "android" as the
+ // container works, but means we lose the context of the original javadoc comment.
+ // This means that if the javadoc comment refers to classes imported by it's
+ // containing source file, we cannot resolve those imports here.
+ // TODO see if we could somehow plumb the import list from the original source file,
+ // via compat_config.xml, so we can resolve links properly here?
+ definedInContainer = Converter.obtainPackage("android");
+ }
+ if (change.description == null) {
+ throw new RuntimeException("No desriprion found for @ChangeId " + change.name);
+ }
+ Comment comment = new Comment(change.description, definedInContainer, new SourcePositionInfo(
+ change.sourceFile, change.sourceLine, 1));
+ String path = "change." + i;
+ hdf.setValue(path + ".id", Long.toString(change.id));
+ hdf.setValue(path + ".name", change.name);
+ if (change.enableAfterTargetSdk != 0) {
+ hdf.setValue(path + ".enableAfterTargetSdk",
+ Integer.toString(change.enableAfterTargetSdk));
+ }
+ if (change.loggingOnly) {
+ hdf.setValue(path + ".loggingOnly", Boolean.toString(true));
+ }
+ if (change.disabled) {
+ hdf.setValue(path + ".disabled", Boolean.toString(true));
+ }
+ TagInfo.makeHDF(hdf, path + ".descr", comment.tags());
+ }
+ }
+}
diff --git a/src/com/google/doclava/Converter.java b/src/com/google/doclava/Converter.java
index a6f803b..cf14237 100644
--- a/src/com/google/doclava/Converter.java
+++ b/src/com/google/doclava/Converter.java
@@ -501,23 +501,9 @@ public class Converter {
return result;
} else {
ConstructorDoc m = (ConstructorDoc) o;
- // Workaround for a JavaDoc behavior change introduced in OpenJDK 8 that breaks
- // links in documentation and the content of API files like current.txt.
- // http://b/18051133.
- String name = m.name();
- ClassDoc containingClass = m.containingClass();
- if (containingClass.containingClass() != null) {
- // This should detect the new behavior and be bypassed otherwise.
- if (!name.contains(".")) {
- // Constructors of inner classes do not contain the name of the enclosing class
- // with OpenJDK 8. This simulates the old behavior:
- name = containingClass.name();
- }
- }
- // End of workaround.
MethodInfo result =
new MethodInfo(m.getRawCommentText(), new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(m.typeParameters()))),
- name, m.signature(), Converter.obtainClass(m.containingClass()), Converter
+ 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(),
false, m.isSynchronized(), m.isNative(), false/*isDefault*/, false, "constructor", m.flatSignature(),
diff --git a/src/com/google/doclava/DocInfo.java b/src/com/google/doclava/DocInfo.java
index 650ce0d..fae225f 100644
--- a/src/com/google/doclava/DocInfo.java
+++ b/src/com/google/doclava/DocInfo.java
@@ -101,6 +101,9 @@ public abstract class DocInfo {
}
public String getSince() {
+ if (Doclava.METALAVA_API_SINCE) {
+ mSince = comment().getApiSince();
+ }
return mSince;
}
@@ -129,11 +132,19 @@ public abstract class DocInfo {
}
public String getDeprecatedSince() {
- return mDeprecatedSince;
+ if (Doclava.METALAVA_API_SINCE) {
+ return comment().getDeprecatedSince();
+ } else {
+ return mDeprecatedSince;
+ }
}
public boolean isDeprecated() {
- return mDeprecatedSince != null ? true : false;
+ if (Doclava.METALAVA_API_SINCE) {
+ return comment().isDeprecated();
+ } else {
+ return mDeprecatedSince != null ? true : false;
+ }
}
public final void addFederatedReference(FederatedSite source) {
diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java
index 53afe55..049e93e 100644
--- a/src/com/google/doclava/Doclava.java
+++ b/src/com/google/doclava/Doclava.java
@@ -82,6 +82,7 @@ public class Doclava {
public static boolean NAVTREE_ONLY = false;
/* Generate reference navtree.js with all inherited members */
public static boolean AT_LINKS_NAVTREE = false;
+ public static boolean METALAVA_API_SINCE = false;
public static String outputPathBase = "/";
public static ArrayList<String> inputPathHtmlDirs = new ArrayList<String>();
public static ArrayList<String> inputPathHtmlDir2 = new ArrayList<String>();
@@ -121,10 +122,12 @@ public class Doclava {
public static boolean referenceOnly = false;
public static boolean staticOnly = false;
public static boolean yamlV2 = false; /* whether to build the new version of the yaml file */
+ public static boolean devsite = false; /* whether to build docs for devsite */
public static AuxSource auxSource = new EmptyAuxSource();
public static Linter linter = new EmptyLinter();
public static boolean android = false;
public static String manifestFile = null;
+ public static String compatConfig = null;
public static Map<String, String> manifestPermissions = new HashMap<>();
public static JSilver jSilver = null;
@@ -193,6 +196,7 @@ public class Doclava {
HashSet<String> stubPackages = null;
HashSet<String> stubImportPackages = null;
boolean stubSourceOnly = false;
+ boolean keepStubComments = false;
ArrayList<String> knownTagsFiles = new ArrayList<String>();
root = r;
@@ -301,6 +305,8 @@ public class Doclava {
}
} else if (a[0].equals("-stubsourceonly")) {
stubSourceOnly = true;
+ } else if (a[0].equals("-keepstubcomments")) {
+ keepStubComments = true;
} else if (a[0].equals("-sdkvalues")) {
sdkValuePath = a[1];
} else if (a[0].equals("-api")) {
@@ -327,6 +333,8 @@ public class Doclava {
includeDefaultAssets = false;
} else if (a[0].equals("-parsecomments")) {
parseComments = true;
+ } else if (a[0].equals("-metalavaApiSince")) {
+ METALAVA_API_SINCE = true;
} else if (a[0].equals("-since")) {
sinceTagger.addVersion(a[1], a[2]);
} else if (a[0].equals("-artifact")) {
@@ -377,6 +385,7 @@ public class Doclava {
} else if (a[0].equals("-yamlV2")) {
yamlV2 = true;
} else if (a[0].equals("-devsite")) {
+ devsite = true;
// Don't copy any assets to devsite output
includeAssets = false;
USE_DEVSITE_LOCALE_OUTPUT_PATHS = true;
@@ -386,7 +395,8 @@ public class Doclava {
System.out.println(" ... Generating static html only for devsite");
}
if (yamlNavFile == null) {
- yamlNavFile = "_book.yaml";
+ // Use _toc.yaml as default to avoid clobbering possible manual _book.yaml files
+ yamlNavFile = "_toc.yaml";
}
} else if (a[0].equals("-android")) {
auxSource = new AndroidAuxSource();
@@ -394,6 +404,8 @@ public class Doclava {
android = true;
} else if (a[0].equals("-manifest")) {
manifestFile = a[1];
+ } else if (a[0].equals("-compatconfig")) {
+ compatConfig = a[1];
}
}
@@ -424,9 +436,8 @@ public class Doclava {
}
// If no custom template path is provided, and this is a devsite build,
// then use the bundled templates-sdk/ files by default
- if (templates.isEmpty() && USE_DEVSITE_LOCALE_OUTPUT_PATHS) {
+ if (templates.isEmpty() && devsite) {
resourceLoaders.add(new ClassResourceLoader(Doclava.class, "/assets/templates-sdk"));
- System.out.println("\n######### OK, Using templates-sdk ############\n");
}
templates = ClearPage.getBundledTemplateDirs();
@@ -447,7 +458,11 @@ public class Doclava {
if (NAVTREE_ONLY) {
if (AT_LINKS_NAVTREE) {
AtLinksNavTree.writeAtLinksNavTree(javadocDir);
+ } else if (yamlV2) {
+ // Generate DAC-formatted left-nav for devsite
+ NavTree.writeYamlTree2(javadocDir, yamlNavFile);
} else {
+ // This shouldn't happen; this is the legacy DAC left nav file
NavTree.writeNavTree(javadocDir, "");
}
return true;
@@ -518,18 +533,6 @@ public class Doclava {
} else if(gcmRef){
refPrefix = "gcm-";
}
- NavTree.writeNavTree(javadocDir, refPrefix);
-
- // Write yaml tree.
- if (yamlNavFile != null){
- NavTree.writeYamlTree(javadocDir, yamlNavFile);
- if (yamlV2) {
- // Generate both for good measure, to make transitions easier, but change the filename
- // for the new one so there's yet another explicit opt-in required by fixing the name.
- yamlNavFile = "_NEW" + yamlNavFile;
- NavTree.writeYamlTree2(javadocDir, yamlNavFile);
- }
- }
// Packages Pages
writePackages(refPrefix + "packages" + htmlExtension);
@@ -538,8 +541,23 @@ public class Doclava {
writeClassLists();
writeClasses();
writeHierarchy();
+ writeCompatConfig();
// writeKeywords();
+ // Write yaml tree.
+ if (yamlNavFile != null) {
+ if (yamlV2) {
+ // Generate DAC-formatted left-nav for devsite
+ NavTree.writeYamlTree2(javadocDir, yamlNavFile);
+ } else {
+ // Generate legacy devsite left-nav (shows sub-classes nested under parent class)
+ NavTree.writeYamlTree(javadocDir, yamlNavFile);
+ }
+ } else {
+ // This shouldn't happen; this is the legacy DAC left nav file
+ NavTree.writeNavTree(javadocDir, refPrefix);
+ }
+
// Lists for JavaScript
writeLists();
if (keepListFile != null) {
@@ -556,7 +574,7 @@ public class Doclava {
if (!sTaglist.isEmpty()) {
PageMetadata.WriteListByLang(sTaglist);
// For devsite (ds) reference only, write samples_metadata to out dir
- if ((USE_DEVSITE_LOCALE_OUTPUT_PATHS) && (!DEVSITE_STATIC_ONLY)) {
+ if ((devsite) && (!DEVSITE_STATIC_ONLY)) {
PageMetadata.WriteSamplesListByLang(sTaglist);
}
}
@@ -568,7 +586,7 @@ public class Doclava {
|| privateApiFile != null || privateDexApiFile != null || apiMappingFile != null) {
Stubs.writeStubsAndApi(stubsDir, apiFile, dexApiFile, proguardFile, removedApiFile,
removedDexApiFile, exactApiFile, privateApiFile, privateDexApiFile, apiMappingFile,
- stubPackages, stubImportPackages, stubSourceOnly);
+ stubPackages, stubImportPackages, stubSourceOnly, keepStubComments);
}
Errors.printErrors();
@@ -853,6 +871,9 @@ public class Doclava {
if (option.equals("-stubsourceonly")) {
return 1;
}
+ if (option.equals("-keepstubcomments")) {
+ return 1;
+ }
if (option.equals("-sdkvalues")) {
return 2;
}
@@ -889,6 +910,9 @@ public class Doclava {
if (option.equals("-parsecomments")) {
return 1;
}
+ if (option.equals("-metalavaApiSince")) {
+ return 1;
+ }
if (option.equals("-since")) {
return 3;
}
@@ -942,6 +966,9 @@ public class Doclava {
if (option.equals("-manifest")) {
return 2;
}
+ if (option.equals("-compatconfig")) {
+ return 2;
+ }
return 0;
}
public static boolean validOptions(String[][] options, DocErrorReporter r) {
@@ -1040,7 +1067,11 @@ public class Doclava {
data.setValue("reference.gcm", "true");
}
data.setValue("reference", "1");
- data.setValue("reference.apilevels", sinceTagger.hasVersions() ? "1" : "0");
+ if (METALAVA_API_SINCE) {
+ data.setValue("reference.apilevels", (pkg.getSince() != null) ? "1" : "0");
+ } else {
+ data.setValue("reference.apilevels", sinceTagger.hasVersions() ? "1" : "0");
+ }
data.setValue("reference.artifacts", artifactTagger.hasArtifacts() ? "1" : "0");
data.setValue("docs.packages." + i + ".name", s);
data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
@@ -1201,7 +1232,7 @@ public class Doclava {
// Write the lists for JD documents (if there are HTML directories to process)
// Skip this for devsite builds
- if ((inputPathHtmlDirs.size() > 0) && (!USE_DEVSITE_LOCALE_OUTPUT_PATHS)) {
+ if ((inputPathHtmlDirs.size() > 0) && (!devsite)) {
Data jddata = makeHDF();
Iterator counter = new Iterator();
for (String htmlDir : inputPathHtmlDirs) {
@@ -1563,8 +1594,11 @@ public class Doclava {
setPageTitle(data, "Class Index");
ClearPage.write(data, "classes.cs", packageDir + "classes" + htmlExtension);
- // Index page redirects to the classes.html page, so use the same directory
- writeIndex(packageDir);
+ if (!devsite) {
+ // Index page redirects to the classes.html page, so use the same directory
+ // This page is not needed for devsite builds, which should instead use _redirects.yaml
+ writeIndex(packageDir);
+ }
}
// we use the word keywords because "index" means something else in html land
@@ -2144,8 +2178,8 @@ public class Doclava {
public static String getDocumentationStringForAnnotation(String annotationName) {
if (!documentAnnotations) return null;
if (annotationDocumentationMap == null) {
- // parse the file for map
annotationDocumentationMap = new HashMap<String, String>();
+ // parse the file for map
try {
BufferedReader in = new BufferedReader(
new FileReader(documentAnnotationsPath));
@@ -2168,4 +2202,17 @@ public class Doclava {
return annotationDocumentationMap.get(annotationName);
}
+ public static void writeCompatConfig() {
+ if (compatConfig == null) {
+ return;
+ }
+ CompatInfo config = CompatInfo.readCompatConfig(compatConfig);
+ Data data = makeHDF();
+ config.makeHDF(data);
+ setPageTitle(data, "Compatibility changes");
+ // TODO - should we write the output to some other path?
+ String outfile = "compatchanges.html";
+ ClearPage.write(data, "compatchanges.cs", outfile);
+ }
+
}
diff --git a/src/com/google/doclava/Errors.java b/src/com/google/doclava/Errors.java
index 6b0eee0..a7a3bdf 100644
--- a/src/com/google/doclava/Errors.java
+++ b/src/com/google/doclava/Errors.java
@@ -314,6 +314,7 @@ public class Errors {
public static final Error TODO = new Error(128, LINT);
public static final Error NO_ARTIFACT_DATA = new Error(129, HIDDEN);
public static final Error BROKEN_ARTIFACT_FILE = new Error(130, ERROR);
+ public static final Error JAVA_TAG_IN_COMMENT = new Error(131, LINT);
public static boolean setErrorLevel(int code, int level) {
for (Error e : sErrors) {
diff --git a/src/com/google/doclava/NavTree.java b/src/com/google/doclava/NavTree.java
index b4861c8..3375df5 100644
--- a/src/com/google/doclava/NavTree.java
+++ b/src/com/google/doclava/NavTree.java
@@ -26,6 +26,7 @@ import java.util.TreeMap;
public class NavTree {
+ /* @deprecated This method was used for an older version of DAC, circa 2012, retired May 2018 */
public static void writeNavTree(String dir, String refPrefix) {
List<Node> children = new ArrayList<Node>();
for (PackageInfo pkg : Doclava.choosePackages()) {
diff --git a/src/com/google/doclava/SeeTagInfo.java b/src/com/google/doclava/SeeTagInfo.java
index eddc595..fee8ce2 100644
--- a/src/com/google/doclava/SeeTagInfo.java
+++ b/src/com/google/doclava/SeeTagInfo.java
@@ -35,16 +35,8 @@ public class SeeTagInfo extends TagInfo {
protected LinkReference linkReference() {
if (mLink == null) {
- // If this is a @see reference in frameworks/base, suppress errors about broken references.
- // Outside of frameworks/base, and the generated android/R file, all such
- // errors have been fixed, see b/80570421.
- boolean suppressableSeeReference =
- "@see".equals(name()) &&
- (position().file.contains("frameworks/base/")
- || position().file.endsWith("android/R.java"));
- mLink =
- LinkReference.parse(text(), mBase, position(), !suppressableSeeReference
- && (mBase != null ? mBase.checkLevel() : true));
+ mLink = LinkReference.parse(text(), mBase, position(),
+ mBase != null ? mBase.checkLevel() : true);
}
return mLink;
}
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 0ef3749..930d52c 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -49,7 +49,8 @@ public class Stubs {
public static void writeStubsAndApi(String stubsDir, String apiFile, String dexApiFile,
String keepListFile, String removedApiFile, String removedDexApiFile, String exactApiFile,
String privateApiFile, String privateDexApiFile, String apiMappingFile,
- HashSet<String> stubPackages, HashSet<String> stubImportPackages, boolean stubSourceOnly) {
+ HashSet<String> stubPackages, HashSet<String> stubImportPackages, boolean stubSourceOnly,
+ boolean keepStubComments) {
// figure out which classes we need
final HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
Collection<ClassInfo> all = Converter.allClasses();
@@ -259,7 +260,7 @@ public class Stubs {
if (shouldWriteStub(cl.containingPackage().name(), stubPackages, stubPackageWildcards)) {
// write out the stubs
if (stubsDir != null) {
- writeClassFile(stubsDir, notStrippable, cl);
+ writeClassFile(stubsDir, notStrippable, cl, keepStubComments);
}
// build class list for api file or keep list file
if (apiWriter != null || dexApiWriter != null || keepListWriter != null) {
@@ -588,7 +589,7 @@ public class Stubs {
return dir + cl.name() + ".java";
}
- static void writeClassFile(String stubsDir, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
+ static void writeClassFile(String stubsDir, HashSet<ClassInfo> notStrippable, ClassInfo cl, boolean keepStubComments) {
// inner classes are written by their containing class
if (cl.containingClass() != null) {
return;
@@ -608,7 +609,7 @@ public class Stubs {
PrintStream stream = null;
try {
stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
- writeClassFile(stream, notStrippable, cl);
+ writeClassFile(stream, notStrippable, cl, keepStubComments);
} catch (FileNotFoundException e) {
System.err.println("error writing file: " + filename);
} finally {
@@ -618,7 +619,7 @@ public class Stubs {
}
}
- static void writeClassFile(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
+ static void writeClassFile(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl, boolean keepStubComments) {
PackageInfo pkg = cl.containingPackage();
if (cl.containingClass() == null) {
stream.print(parseLicenseHeader(cl.position()));
@@ -626,7 +627,7 @@ public class Stubs {
if (pkg != null) {
stream.println("package " + pkg.name() + ";");
}
- writeClass(stream, notStrippable, cl);
+ writeClass(stream, notStrippable, cl, keepStubComments);
}
private static String parseLicenseHeader(/* @Nonnull */ SourcePositionInfo positionInfo) {
@@ -677,7 +678,11 @@ public class Stubs {
return builder.toString();
}
- static void writeClass(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
+ static void writeClass(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl, boolean keepStubComments) {
+ if (keepStubComments) {
+ writeComment(stream, cl);
+ }
+
writeAnnotations(stream, cl.annotations(), cl.isDeprecated());
stream.print(cl.scope() + " ");
@@ -752,14 +757,14 @@ public class Stubs {
for (ClassInfo inner : cl.getRealInnerClasses()) {
if (notStrippable.contains(inner) && !inner.isDocOnly()) {
- writeClass(stream, notStrippable, inner);
+ writeClass(stream, notStrippable, inner, keepStubComments);
}
}
for (MethodInfo method : cl.constructors()) {
if (!method.isDocOnly()) {
- writeMethod(stream, method, true);
+ writeMethod(stream, method, true, keepStubComments);
}
}
@@ -806,7 +811,7 @@ public class Stubs {
}
}
if (!method.isDocOnly()) {
- writeMethod(stream, method, false);
+ writeMethod(stream, method, false, keepStubComments);
}
}
// Write all methods that are hidden or removed, but override abstract methods or interface methods.
@@ -823,7 +828,7 @@ public class Stubs {
(overriddenMethod.isAbstract() || overriddenMethod.containingClass().isInterface())) {
method.setReason("1:" + classContainingMethod.qualifiedName());
cl.addMethod(method);
- writeMethod(stream, method, false);
+ writeMethod(stream, method, false, keepStubComments);
}
}
@@ -835,7 +840,7 @@ public class Stubs {
for (FieldInfo field : cl.selfFields()) {
if (!field.isDocOnly()) {
- writeField(stream, field);
+ writeField(stream, field, keepStubComments);
}
}
@@ -853,7 +858,10 @@ public class Stubs {
stream.println("}");
}
- static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor) {
+ static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor, boolean keepStubComments) {
+ if (keepStubComments) {
+ writeComment(stream, method);
+ }
String comma;
writeAnnotations(stream, method.annotations(), method.isDeprecated());
@@ -924,7 +932,10 @@ public class Stubs {
}
}
- static void writeField(PrintStream stream, FieldInfo field) {
+ static void writeField(PrintStream stream, FieldInfo field, boolean keepStubComments) {
+ if (keepStubComments) {
+ writeComment(stream, field);
+ }
writeAnnotations(stream, field.annotations(), field.isDeprecated());
stream.print(field.scope() + " ");
@@ -1090,6 +1101,16 @@ public class Stubs {
stream.println(";");
}
+ static void writeComment(PrintStream stream, DocInfo doc) {
+ if (!doc.isHiddenOrRemoved() && !doc.comment().isDocOnly() && !"".equals(doc.getRawCommentText())) {
+ String newLineSeparator = System.getProperty("line.separator");
+ stream.println("/**");
+ stream.print(" * ");
+ stream.println(doc.getRawCommentText().replace(newLineSeparator, newLineSeparator + " *"));
+ stream.println(" */");
+ }
+ }
+
public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs, boolean strip) {
if (strip) {
Stubs.writeXml(xmlWriter, pkgs);