am 164bbd75: (-s ours) am b9d279d8: Merge "Support marking packages as hidden via command-line."
* commit '164bbd75087fcd3d6ab2a774dfb06c469be399e3':
Support marking packages as hidden via command-line.
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
index a750b11..3cda7ec 100644
--- a/src/com/google/doclava/ClassInfo.java
+++ b/src/com/google/doclava/ClassInfo.java
@@ -117,10 +117,18 @@
mRealInterfaces = new ArrayList<ClassInfo>(interfaces);
mRealInterfaceTypes = interfaceTypes;
mInnerClasses = innerClasses;
+ // mAllConstructors will not contain *all* constructors. Only the constructors that pass
+ // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
mAllConstructors = constructors;
+ // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
+ // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
mAllSelfMethods = methods;
mAnnotationElements = annotationElements;
+ // mAllSelfFields will not contain *all* self fields. Only the fields that pass
+ // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
mAllSelfFields = fields;
+ // mEnumConstants will not contain *all* enum constants. Only the enums that pass
+ // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
mEnumConstants = enumConstants;
mContainingPackage = containingPackage;
mContainingClass = containingClass;
@@ -162,16 +170,17 @@
return mTypeParameters;
}
+ /**
+ * @return true if this class needs to be shown in api txt, based on the
+ * hidden/removed status of the class and the show level setting in doclava.
+ */
public boolean checkLevel() {
- int val = mCheckLevel;
- if (val >= 0) {
- return val != 0;
- } else {
- boolean v =
- Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, isHidden());
- mCheckLevel = v ? 1 : 0;
- return v;
+ if (mCheckLevel == null) {
+ mCheckLevel = Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate,
+ isHiddenOrRemoved());
}
+
+ return mCheckLevel;
}
public int compareTo(Object that) {
@@ -350,7 +359,7 @@
mConstructors = new ArrayList<MethodInfo>();
for (MethodInfo m : mAllConstructors) {
- if (!m.isHidden()) {
+ if (!m.isHiddenOrRemoved()) {
mConstructors.add(m);
}
}
@@ -462,13 +471,13 @@
}
for (FieldInfo field : selfFields()) {
- if (!field.isHidden()) {
+ if (!field.isHiddenOrRemoved()) {
all.put(field.name(), field);
}
}
for (FieldInfo enumConst : mEnumConstants) {
- if (!enumConst.isHidden()) {
+ if (!enumConst.isHiddenOrRemoved()) {
all.put(enumConst.name(), enumConst);
}
}
@@ -500,7 +509,7 @@
}
for (FieldInfo f : mAllSelfFields) {
- if (!f.isHidden()) {
+ if (!f.isHiddenOrRemoved()) {
fields.put(f.name(), f);
}
}
@@ -539,7 +548,7 @@
if (mAllSelfMethods != null) {
for (MethodInfo m : mAllSelfMethods) {
if (m.checkLevel()) {
- methods.put(m.name() + m.signature(), m);
+ methods.put(m.name() + m.signature(), m);
}
}
}
@@ -555,6 +564,150 @@
return mAllSelfMethods;
}
+ /**
+ * @param removedMethods the removed methods regardless of access levels.
+ */
+ public void setRemovedMethods(List<MethodInfo> removedMethods) {
+ Collections.sort(removedMethods, MethodInfo.comparator);
+ mRemovedMethods = Collections.unmodifiableList(removedMethods);
+ }
+
+ /**
+ * @param allMethods all methods regardless of access levels. Selects the
+ * removed, public/protected ones and store them. If a class is removed, all its members
+ * are removed, even if the member may not have a @removed tag.
+ */
+ public void setRemovedSelfMethods(List<MethodInfo> allMethods) {
+ List<MethodInfo> removedSelfMethods = new ArrayList<MethodInfo>();
+ for (MethodInfo method : allMethods) {
+ if ((this.isRemoved() || method.isRemoved()) && (method.isPublic() || method.isProtected()) &&
+ (this.isPublic() || this.isProtected()) &&
+ (method.findOverriddenMethod(method.name(), method.signature()) == null)) {
+ removedSelfMethods.add(method);
+ }
+ }
+
+ Collections.sort(removedSelfMethods, MethodInfo.comparator);
+ mRemovedSelfMethods = Collections.unmodifiableList(removedSelfMethods);
+ }
+
+ /**
+ * @param allCtors all constructors regardless of access levels.
+ * But only the public/protected removed constructors will be stored by the method.
+ * Removed constructors should never be deleted from source code because
+ * they were once public API.
+ */
+ public void setRemovedConstructors(List<MethodInfo> allCtors) {
+ List<MethodInfo> ctors = new ArrayList<MethodInfo>();
+ for (MethodInfo ctor : allCtors) {
+ if ((this.isRemoved() || ctor.isRemoved()) && (ctor.isPublic() || ctor.isProtected()) &&
+ (this.isPublic() || this.isProtected())) {
+ ctors.add(ctor);
+ }
+ }
+
+ Collections.sort(ctors, MethodInfo.comparator);
+ mRemovedConstructors = Collections.unmodifiableList(ctors);
+ }
+
+ /**
+ * @param allFields all fields regardless of access levels. Selects the
+ * removed, public/protected ones and store them. If a class is removed, all its members
+ * are removed, even if the member may not have a @removed tag.
+ */
+ public void setRemovedSelfFields(List<FieldInfo> allFields) {
+ List<FieldInfo> fields = new ArrayList<FieldInfo>();
+ for (FieldInfo field : allFields) {
+ if ((this.isRemoved() || field.isRemoved()) && (field.isPublic() || field.isProtected()) &&
+ (this.isPublic() || this.isProtected())) {
+ fields.add(field);
+ }
+ }
+
+ Collections.sort(fields, FieldInfo.comparator);
+ mRemovedSelfFields = Collections.unmodifiableList(fields);
+ }
+
+ /**
+ * @param allEnumConstants all enum constants regardless of access levels. Selects the
+ * removed, public/protected ones and store them. If a class is removed, all its members
+ * are removed, even if the member may not have a @removed tag.
+ */
+ public void setRemovedEnumConstants(List<FieldInfo> allEnumConstants) {
+ List<FieldInfo> enums = new ArrayList<FieldInfo>();
+ for (FieldInfo field : allEnumConstants) {
+ if ((this.isRemoved() || field.isRemoved()) && (field.isPublic() || field.isProtected()) &&
+ (this.isPublic() || this.isProtected())) {
+ enums.add(field);
+ }
+ }
+
+ Collections.sort(enums, FieldInfo.comparator);
+ mRemovedEnumConstants = Collections.unmodifiableList(enums);
+ }
+
+ /**
+ * @return all methods that are marked as removed, regardless of access levels.
+ * The returned list is sorted and unmodifiable.
+ */
+ public List<MethodInfo> getRemovedMethods() {
+ return mRemovedMethods;
+ }
+
+ /**
+ * @return all public/protected methods that are removed. @removed methods should never be
+ * deleted from source code because they were once public API. Methods that override
+ * a parent method will not be included, because deleting them does not break the API.
+ */
+ public List<MethodInfo> getRemovedSelfMethods() {
+ return mRemovedSelfMethods;
+ }
+
+ /**
+ * @return all public constructors that are removed.
+ * removed constructors should never be deleted from source code because they
+ * were once public API.
+ * The returned list is sorted and unmodifiable.
+ */
+ public List<MethodInfo> getRemovedConstructors() {
+ return mRemovedConstructors;
+ }
+
+ /**
+ * @return all public/protected fields that are removed.
+ * removed members should never be deleted from source code because they were once public API.
+ * The returned list is sorted and unmodifiable.
+ */
+ public List<FieldInfo> getRemovedSelfFields() {
+ return mRemovedSelfFields;
+ }
+
+ /**
+ * @return all public/protected enumConstants that are removed.
+ * removed members should never be deleted from source code
+ * because they were once public API.
+ * The returned list is sorted and unmodifiable.
+ */
+ public List<FieldInfo> getRemovedSelfEnumConstants() {
+ return mRemovedEnumConstants;
+ }
+
+ /**
+ * @return true if this class contains any self members that are removed
+ */
+ public boolean hasRemovedSelfMembers() {
+ List<FieldInfo> removedSelfFields = getRemovedSelfFields();
+ List<FieldInfo> removedSelfEnumConstants = getRemovedSelfEnumConstants();
+ List<MethodInfo> removedSelfMethods = getRemovedSelfMethods();
+ List<MethodInfo> removedConstructors = getRemovedConstructors();
+ if (removedSelfFields.size() + removedSelfEnumConstants.size()
+ + removedSelfMethods.size() + removedConstructors.size() == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
public void addMethod(MethodInfo method) {
mApiCheckMethods.put(method.getHashableName(), method);
@@ -1195,29 +1348,26 @@
@Override
public boolean isHidden() {
- int val = mHidden;
- if (val >= 0) {
- return val != 0;
- } else {
- boolean v = isHiddenImpl();
- mHidden = v ? 1 : 0;
- return v;
+ if (mHidden == null) {
+ mHidden = isHiddenImpl();
}
+
+ return mHidden;
}
+ /**
+ * @return true if the containing package has @hide comment, or an ancestor
+ * class of this class is hidden, or this class has @hide comment.
+ */
public boolean isHiddenImpl() {
ClassInfo cl = this;
while (cl != null) {
- PackageInfo pkg = cl.containingPackage();
- if (pkg != null && pkg.isHidden()) {
- return true;
+ if (cl.hasShowAnnotation()) {
+ return false;
}
- if (cl.annotations() != null) {
- for (AnnotationInstanceInfo info : cl.annotations()) {
- if (Doclava.showAnnotations.contains(info.type().qualifiedName())) {
- return false;
- }
- }
+ PackageInfo pkg = cl.containingPackage();
+ if (pkg != null && pkg.hasHideComment()) {
+ return true;
}
if (cl.comment().isHidden()) {
return true;
@@ -1227,6 +1377,53 @@
return false;
}
+ @Override
+ public boolean isRemoved() {
+ if (mRemoved == null) {
+ mRemoved = isRemovedImpl();
+ }
+
+ return mRemoved;
+ }
+
+ /**
+ * @return true if the containing package has @removed comment, or an ancestor
+ * class of this class is removed, or this class has @removed comment.
+ */
+ public boolean isRemovedImpl() {
+ ClassInfo cl = this;
+ while (cl != null) {
+ if (cl.hasShowAnnotation()) {
+ return false;
+ }
+ PackageInfo pkg = cl.containingPackage();
+ if (pkg != null && pkg.hasRemovedComment()) {
+ return true;
+ }
+ if (cl.comment().isRemoved()) {
+ return true;
+ }
+ cl = cl.containingClass();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isHiddenOrRemoved() {
+ return isHidden() || isRemoved();
+ }
+
+ public boolean hasShowAnnotation() {
+ if (annotations() != null) {
+ for (AnnotationInstanceInfo info : annotations()) {
+ if (Doclava.showAnnotations.contains(info.type().qualifiedName())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params,
String[] dimensions, boolean varargs) {
for (MethodInfo method : methods) {
@@ -1474,7 +1671,11 @@
private ArrayList<ClassInfo> mInterfaces;
private ArrayList<TypeInfo> mRealInterfaceTypes;
private ArrayList<ClassInfo> mInnerClasses;
+ // mAllConstructors will not contain *all* constructors. Only the constructors that pass
+ // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>();
+ // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
+ // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>();
private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation
private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>();
@@ -1498,8 +1699,9 @@
private ArrayList<FieldInfo> mFields;
private ArrayList<TypeInfo> mTypeParameters;
private ArrayList<MethodInfo> mHiddenMethods;
- private int mHidden = -1;
- private int mCheckLevel = -1;
+ private Boolean mHidden = null;
+ private Boolean mRemoved = null;
+ private Boolean mCheckLevel = null;
private String mReasonIncluded;
private ArrayList<MethodInfo> mNonWrittenConstructors;
private boolean mIsDeprecated;
@@ -1513,6 +1715,13 @@
// Resolutions
private ArrayList<Resolution> mResolutions;
+ private List<MethodInfo> mRemovedConstructors; // immutable after you set its value.
+ // @removed self methods that do not override any parent methods
+ private List<MethodInfo> mRemovedSelfMethods; // immutable after you set its value.
+ private List<MethodInfo> mRemovedMethods; // immutable after you set its value.
+ private List<FieldInfo> mRemovedSelfFields; // immutable after you set its value.
+ private List<FieldInfo> mRemovedEnumConstants; // immutable after you set its value.
+
/**
* Returns true if {@code cl} implements the interface {@code iface} either by either being that
* interface, implementing that interface or extending a type that implements the interface.
@@ -1798,7 +2007,7 @@
return consistent;
}
- // Find a superclass implementation of the given method.
+ // Find a superclass implementation of the given method based on the methods in mApiCheckMethods.
public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
if (newClassObj == null) {
return null;
diff --git a/src/com/google/doclava/Comment.java b/src/com/google/doclava/Comment.java
index 70f4f30..c93cda7 100644
--- a/src/com/google/doclava/Comment.java
+++ b/src/com/google/doclava/Comment.java
@@ -458,37 +458,35 @@
}
public boolean isHidden() {
- if (mHidden != -1) {
- return mHidden != 0;
- } else {
- if (Doclava.checkLevel(Doclava.SHOW_HIDDEN)) {
- mHidden = 0;
- return false;
- }
- boolean b = mText.indexOf("@hide") >= 0 || mText.indexOf("@pending") >= 0;
- mHidden = b ? 1 : 0;
- return b;
+ if (mHidden == null) {
+ mHidden = !Doclava.checkLevel(Doclava.SHOW_HIDDEN) &&
+ (mText != null) && (mText.indexOf("@hide") >= 0 || mText.indexOf("@pending") >= 0);
}
+ return mHidden;
+ }
+
+ public boolean isRemoved() {
+ if (mRemoved == null) {
+ mRemoved = !Doclava.checkLevel(Doclava.SHOW_HIDDEN) &&
+ (mText != null) && (mText.indexOf("@removed") >= 0);
+ }
+
+ return mRemoved;
}
public boolean isDocOnly() {
- if (mDocOnly != -1) {
- return mDocOnly != 0;
- } else {
- boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
- mDocOnly = b ? 1 : 0;
- return b;
+ if (mDocOnly == null) {
+ mDocOnly = (mText != null) && (mText.indexOf("@doconly") >= 0);
}
+ return mDocOnly;
}
-
+
public boolean isDeprecated() {
- if (mDeprecated != -1) {
- return mDeprecated != 0;
- } else {
- boolean b = (mText != null) && (mText.indexOf("@deprecated") >= 0);
- mDeprecated = b ? 1 : 0;
- return b;
+ if (mDeprecated == null) {
+ mDeprecated = (mText != null) && (mText.indexOf("@deprecated") >= 0);
}
+
+ return mDeprecated;
}
private void init() {
@@ -499,6 +497,7 @@
private void initImpl() {
isHidden();
+ isRemoved();
isDocOnly();
isDeprecated();
@@ -539,9 +538,10 @@
}
boolean mInitialized;
- int mHidden = -1;
- int mDocOnly = -1;
- int mDeprecated = -1;
+ Boolean mHidden = null;
+ Boolean mRemoved = null;
+ Boolean mDocOnly = null;
+ Boolean mDeprecated = null;
String mText;
ContainerInfo mBase;
SourcePositionInfo mPosition;
diff --git a/src/com/google/doclava/Converter.java b/src/com/google/doclava/Converter.java
index bdf6af5..e620bf3 100644
--- a/src/com/google/doclava/Converter.java
+++ b/src/com/google/doclava/Converter.java
@@ -41,6 +41,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
public class Converter {
private static RootDoc root;
@@ -131,6 +132,18 @@
cl.setHiddenMethods(
new ArrayList<MethodInfo>(Arrays.asList(Converter.getHiddenMethods(c.methods(false)))));
+ cl.setRemovedMethods(
+ new ArrayList<MethodInfo>(Arrays.asList(Converter.getRemovedMethods(c.methods(false)))));
+
+ cl.setRemovedSelfMethods(
+ new ArrayList<MethodInfo>(Converter.convertAllMethods(c.methods(false))));
+ cl.setRemovedConstructors(
+ new ArrayList<MethodInfo>(Converter.convertAllMethods(c.constructors(false))));
+ cl.setRemovedSelfFields(
+ new ArrayList<FieldInfo>(Converter.convertAllFields(c.fields(false))));
+ cl.setRemovedEnumConstants(
+ new ArrayList<FieldInfo>(Converter.convertAllFields(c.enumConstants())));
+
cl.setNonWrittenConstructors(
new ArrayList<MethodInfo>(Arrays.asList(Converter.convertNonWrittenConstructors(
c.constructors(false)))));
@@ -288,81 +301,91 @@
private static MethodInfo[] getHiddenMethods(MethodDoc[] methods) {
if (methods == null) return null;
- ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
- int N = methods.length;
- for (int i = 0; i < N; i++) {
- MethodInfo m = Converter.obtainMethod(methods[i]);
- // System.out.println(m.toString() + ": ");
- // for (TypeInfo ti : m.getTypeParameters()){
- // if (ti.asClassInfo() != null){
- // System.out.println(" " +ti.asClassInfo().toString());
- // } else {
- // System.out.println(" null");
- // }
- // }
- if (m.isHidden()) {
- out.add(m);
+ ArrayList<MethodInfo> hiddenMethods = new ArrayList<MethodInfo>();
+ for (MethodDoc method : methods) {
+ MethodInfo methodInfo = Converter.obtainMethod(method);
+ if (methodInfo.isHidden()) {
+ hiddenMethods.add(methodInfo);
}
}
- return out.toArray(new MethodInfo[out.size()]);
+
+ return hiddenMethods.toArray(new MethodInfo[hiddenMethods.size()]);
+ }
+
+ // Gets the removed methods regardless of access levels
+ private static MethodInfo[] getRemovedMethods(MethodDoc[] methods) {
+ if (methods == null) return null;
+ ArrayList<MethodInfo> removedMethods = new ArrayList<MethodInfo>();
+ for (MethodDoc method : methods) {
+ MethodInfo methodInfo = Converter.obtainMethod(method);
+ if (methodInfo.isRemoved()) {
+ removedMethods.add(methodInfo);
+ }
+ }
+
+ return removedMethods.toArray(new MethodInfo[removedMethods.size()]);
}
/**
- * Convert MethodDoc[] into MethodInfo[]. Also filters according to the -private, -public option,
- * because the filtering doesn't seem to be working in the ClassDoc.constructors(boolean) call.
+ * Converts FieldDoc[] into List<FieldInfo>. No filtering is done.
*/
- private static MethodInfo[] convertMethods(MethodDoc[] methods) {
- if (methods == null) return null;
- ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
- int N = methods.length;
- for (int i = 0; i < N; i++) {
- MethodInfo m = Converter.obtainMethod(methods[i]);
- // System.out.println(m.toString() + ": ");
- // for (TypeInfo ti : m.getTypeParameters()){
- // if (ti.asClassInfo() != null){
- // System.out.println(" " +ti.asClassInfo().toString());
- // } else {
- // System.out.println(" null");
- // }
- // }
- if (m.checkLevel()) {
- out.add(m);
- }
+ private static List<FieldInfo> convertAllFields(FieldDoc[] fields) {
+ if (fields == null) return null;
+ List<FieldInfo> allFields = new ArrayList<FieldInfo>();
+
+ for (FieldDoc field : fields) {
+ FieldInfo fieldInfo = Converter.obtainField(field);
+ allFields.add(fieldInfo);
}
- return out.toArray(new MethodInfo[out.size()]);
+
+ return allFields;
}
- private static MethodInfo[] convertMethods(ConstructorDoc[] methods) {
+ /**
+ * Converts ExecutableMemberDoc[] into List<MethodInfo>. No filtering is done.
+ */
+ private static List<MethodInfo> convertAllMethods(ExecutableMemberDoc[] methods) {
if (methods == null) return null;
- ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
- int N = methods.length;
- for (int i = 0; i < N; i++) {
- MethodInfo m = Converter.obtainMethod(methods[i]);
- if (m.checkLevel()) {
- out.add(m);
+ List<MethodInfo> allMethods = new ArrayList<MethodInfo>();
+ for (ExecutableMemberDoc method : methods) {
+ MethodInfo methodInfo = Converter.obtainMethod(method);
+ allMethods.add(methodInfo);
+ }
+ return allMethods;
+ }
+
+ /**
+ * Convert MethodDoc[] or ConstructorDoc[] into MethodInfo[].
+ * Also filters according to the -private, -public option,
+ * because the filtering doesn't seem to be working in the ClassDoc.constructors(boolean) call.
+ */
+ private static MethodInfo[] convertMethods(ExecutableMemberDoc[] methods) {
+ if (methods == null) return null;
+ List<MethodInfo> filteredMethods = new ArrayList<MethodInfo>();
+ for (ExecutableMemberDoc method : methods) {
+ MethodInfo methodInfo = Converter.obtainMethod(method);
+ if (methodInfo.checkLevel()) {
+ filteredMethods.add(methodInfo);
}
}
- return out.toArray(new MethodInfo[out.size()]);
+
+ return filteredMethods.toArray(new MethodInfo[filteredMethods.size()]);
}
private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods) {
if (methods == null) return null;
- ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
- int N = methods.length;
- for (int i = 0; i < N; i++) {
- MethodInfo m = Converter.obtainMethod(methods[i]);
- if (!m.checkLevel()) {
- out.add(m);
+ ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
+ for (ConstructorDoc method : methods) {
+ MethodInfo methodInfo = Converter.obtainMethod(method);
+ if (!methodInfo.checkLevel()) {
+ ctors.add(methodInfo);
}
}
- return out.toArray(new MethodInfo[out.size()]);
+
+ return ctors.toArray(new MethodInfo[ctors.size()]);
}
- private static MethodInfo obtainMethod(MethodDoc o) {
- return (MethodInfo) mMethods.obtain(o);
- }
-
- private static MethodInfo obtainMethod(ConstructorDoc o) {
+ private static <E extends ExecutableMemberDoc> MethodInfo obtainMethod(E o) {
return (MethodInfo) mMethods.obtain(o);
}
@@ -559,11 +582,11 @@
return keyString;
}
};
-
+
public static TypeInfo obtainTypeFromString(String type) {
return (TypeInfo) mTypesFromString.obtain(type);
}
-
+
private static final Cache mTypesFromString = new Cache() {
@Override
protected Object make(Object o) {
@@ -573,7 +596,7 @@
@Override
protected void made(Object o, Object r) {
-
+
}
@Override
diff --git a/src/com/google/doclava/DocInfo.java b/src/com/google/doclava/DocInfo.java
index 714beb8..d8a1961 100644
--- a/src/com/google/doclava/DocInfo.java
+++ b/src/com/google/doclava/DocInfo.java
@@ -32,11 +32,30 @@
* The relative path to a web page representing this item.
*/
public abstract String htmlPage();
-
+
+ /**
+ * @return true if the element has never been a part of public API
+ */
public boolean isHidden() {
return comment().isHidden();
}
+ /**
+ * @return true if the element was once a part of public API, now removed.
+ */
+ public boolean isRemoved() {
+ return comment().isRemoved();
+ }
+
+ /**
+ * Hidden and removed elements should not be appear in api.txt files, nor
+ * should they appear in the java doc.
+ * @return true if the element is either hidden or removed.
+ */
+ public boolean isHiddenOrRemoved() {
+ return isHidden() || isRemoved();
+ }
+
public boolean isDocOnly() {
return comment().isDocOnly();
}
@@ -84,7 +103,7 @@
public String getSince() {
return mSince;
}
-
+
public void setDeprecatedSince(String since) {
mDeprecatedSince = since;
}
@@ -100,11 +119,11 @@
public final void addFederatedReference(FederatedSite source) {
mFederatedReferences.add(source);
}
-
+
public final Set<FederatedSite> getFederatedReferences() {
return mFederatedReferences;
}
-
+
public final void setFederatedReferences(Data data, String base) {
int pos = 0;
for (FederatedSite source : getFederatedReferences()) {
diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java
index 848d467..79295fd 100644
--- a/src/com/google/doclava/Doclava.java
+++ b/src/com/google/doclava/Doclava.java
@@ -90,7 +90,6 @@
public static HashSet<String> knownTags = new HashSet<String>();
public static FederationTagger federationTagger = new FederationTagger();
public static Set<String> showAnnotations = new HashSet<String>();
- public static Set<String> hiddenPackages = new HashSet<String>();
public static boolean includeDefaultAssets = true;
private static boolean generateDocs = true;
private static boolean parseComments = false;
@@ -117,7 +116,6 @@
public static boolean checkLevel(boolean pub, boolean prot, boolean pkgp, boolean priv,
boolean hidden) {
- int level = 0;
if (hidden && !checkLevel(SHOW_HIDDEN)) {
return false;
}
@@ -151,6 +149,7 @@
// Create the dependency graph for the stubs directory
boolean offlineMode = false;
String apiFile = null;
+ String removedApiFile = null;
String debugStubsFile = "";
HashSet<String> stubPackages = null;
ArrayList<String> knownTagsFiles = new ArrayList<String>();
@@ -210,8 +209,6 @@
keepListFile = a[1];
} else if (a[0].equals("-showAnnotation")) {
showAnnotations.add(a[1]);
- } else if (a[0].equals("-hidePackage")) {
- hiddenPackages.add(a[1]);
} else if (a[0].equals("-proguard")) {
proguardFile = a[1];
} else if (a[0].equals("-proofread")) {
@@ -239,7 +236,10 @@
sdkValuePath = a[1];
} else if (a[0].equals("-api")) {
apiFile = a[1];
- } else if (a[0].equals("-nodocs")) {
+ } else if (a[0].equals("-removedApi")) {
+ removedApiFile = a[1];
+ }
+ else if (a[0].equals("-nodocs")) {
generateDocs = false;
} else if (a[0].equals("-nodefaultassets")) {
includeDefaultAssets = false;
@@ -343,7 +343,7 @@
}
writeAssets();
-
+
// Navigation tree
String refPrefix = new String();
if(gmsRef){
@@ -388,8 +388,8 @@
}
// Stubs
- if (stubsDir != null || apiFile != null || proguardFile != null) {
- Stubs.writeStubsAndApi(stubsDir, apiFile, proguardFile, stubPackages);
+ if (stubsDir != null || apiFile != null || proguardFile != null || removedApiFile != null) {
+ Stubs.writeStubsAndApi(stubsDir, apiFile, proguardFile, removedApiFile, stubPackages);
}
Errors.printErrors();
@@ -580,9 +580,6 @@
if (option.equals("-showAnnotation")) {
return 2;
}
- if (option.equals("-hidePackage")) {
- return 2;
- }
if (option.equals("-proguard")) {
return 2;
}
@@ -619,6 +616,9 @@
if (option.equals("-api")) {
return 2;
}
+ if (option.equals("-removedApi")) {
+ return 2;
+ }
if (option.equals("-nodocs")) {
return 1;
}
@@ -706,13 +706,13 @@
for (String s : sorted.keySet()) {
PackageInfo pkg = sorted.get(s);
- if (pkg.isHidden()) {
+ if (pkg.isHiddenOrRemoved()) {
continue;
}
- Boolean allHidden = true;
+ boolean allHiddenOrRemoved = true;
int pass = 0;
ClassInfo[] classesToCheck = null;
- while (pass < 5) {
+ while (pass < 6) {
switch (pass) {
case 0:
classesToCheck = pkg.ordinaryClasses();
@@ -729,22 +729,25 @@
case 4:
classesToCheck = pkg.interfaces();
break;
+ case 5:
+ classesToCheck = pkg.annotations();
+ break;
default:
System.err.println("Error reading package: " + pkg.name());
break;
}
for (ClassInfo cl : classesToCheck) {
- if (!cl.isHidden()) {
- allHidden = false;
+ if (!cl.isHiddenOrRemoved()) {
+ allHiddenOrRemoved = false;
break;
}
}
- if (!allHidden) {
+ if (!allHiddenOrRemoved) {
break;
}
pass++;
}
- if (allHidden) {
+ if (allHiddenOrRemoved) {
continue;
}
if(gmsRef){
@@ -848,7 +851,7 @@
SortedMap<String, Object> sorted = new TreeMap<String, Object>();
for (ClassInfo cl : classes) {
- if (cl.isHidden()) {
+ if (cl.isHiddenOrRemoved()) {
continue;
}
sorted.put(cl.qualifiedName(), cl);
@@ -917,7 +920,8 @@
// If it's a .jd file we want to process
if (len > 3 && ".jd".equals(templ.substring(len - 3))) {
// remove the directories below the site root
- String webPath = filePath.substring(filePath.indexOf("docs/html/") + 10, filePath.length());
+ String webPath = filePath.substring(filePath.indexOf("docs/html/") + 10,
+ filePath.length());
// replace .jd with .html
webPath = webPath.substring(0, webPath.length() - 3) + htmlExtension;
// Parse the .jd file for properties data at top of page
@@ -1030,7 +1034,7 @@
// If a class is public and not hidden, then it and everything it derives
// from cannot be stripped. Otherwise we can strip it.
for (ClassInfo cl : all) {
- if (cl.isPublic() && !cl.isHidden()) {
+ if (cl.isPublic() && !cl.isHiddenOrRemoved()) {
cantStripThis(cl, notStrippable);
}
}
@@ -1074,13 +1078,14 @@
for (String s : sorted.keySet()) {
PackageInfo pkg = sorted.get(s);
- if (pkg.isHidden()) {
+ if (pkg.isHiddenOrRemoved()) {
continue;
}
- Boolean allHidden = true;
+
+ boolean allHiddenOrRemoved = true;
int pass = 0;
ClassInfo[] classesToCheck = null;
- while (pass < 5) {
+ while (pass < 6) {
switch (pass) {
case 0:
classesToCheck = pkg.ordinaryClasses();
@@ -1097,22 +1102,25 @@
case 4:
classesToCheck = pkg.interfaces();
break;
+ case 5:
+ classesToCheck = pkg.annotations();
+ break;
default:
System.err.println("Error reading package: " + pkg.name());
break;
}
for (ClassInfo cl : classesToCheck) {
- if (!cl.isHidden()) {
- allHidden = false;
+ if (!cl.isHiddenOrRemoved()) {
+ allHiddenOrRemoved = false;
break;
}
}
- if (!allHidden) {
+ if (!allHiddenOrRemoved) {
break;
}
pass++;
}
- if (allHidden) {
+ if (allHiddenOrRemoved) {
continue;
}
@@ -1159,6 +1167,7 @@
data.setValue("package.descr", "...description...");
pkg.setFederatedReferences(data, "package");
+ makeClassListHDF(data, "package.annotations", ClassInfo.sortByName(pkg.annotations()));
makeClassListHDF(data, "package.interfaces", ClassInfo.sortByName(pkg.interfaces()));
makeClassListHDF(data, "package.classes", ClassInfo.sortByName(pkg.ordinaryClasses()));
makeClassListHDF(data, "package.enums", ClassInfo.sortByName(pkg.enums()));
@@ -1178,7 +1187,8 @@
int i;
Data data = makePackageHDF();
- ClassInfo[] classes = PackageInfo.filterHidden(Converter.convertClasses(root.classes()));
+ ClassInfo[] classes = PackageInfo.filterHiddenAndRemoved(
+ Converter.convertClasses(root.classes()));
if (classes.length == 0) {
return;
}
@@ -1232,7 +1242,7 @@
* public static void writeKeywords() { ArrayList<KeywordEntry> keywords = new
* ArrayList<KeywordEntry>();
*
- * ClassInfo[] classes = PackageInfo.filterHidden(Converter.convertClasses(root.classes()));
+ * ClassInfo[] classes = PackageInfo.filterHiddenAndRemoved(Converter.convertClasses(root.classes()));
*
* for (ClassInfo cl: classes) { cl.makeKeywordEntries(keywords); }
*
@@ -1251,7 +1261,7 @@
ClassInfo[] classes = Converter.rootClasses();
ArrayList<ClassInfo> info = new ArrayList<ClassInfo>();
for (ClassInfo cl : classes) {
- if (!cl.isHidden()) {
+ if (!cl.isHiddenOrRemoved()) {
info.add(cl);
}
}
@@ -1266,7 +1276,7 @@
for (ClassInfo cl : classes) {
Data data = makePackageHDF();
- if (!cl.isHidden()) {
+ if (!cl.isHiddenOrRemoved()) {
writeClass(cl, data);
}
}
@@ -1283,7 +1293,7 @@
public static void makeClassListHDF(Data data, String base, ClassInfo[] classes) {
for (int i = 0; i < classes.length; i++) {
ClassInfo cl = classes[i];
- if (!cl.isHidden()) {
+ if (!cl.isHiddenOrRemoved()) {
cl.makeShortDescrHDF(data, base + "." + i);
}
}
@@ -1319,20 +1329,21 @@
}
/**
- * Returns true if the given element has an @hide or @pending annotation.
+ * Returns true if the given element has an @hide, @removed or @pending annotation.
*/
- private static boolean hasHideAnnotation(Doc doc) {
+ private static boolean hasHideOrRemovedAnnotation(Doc doc) {
String comment = doc.getRawCommentText();
- return comment.indexOf("@hide") != -1 || comment.indexOf("@pending") != -1;
+ return comment.indexOf("@hide") != -1 || comment.indexOf("@pending") != -1 ||
+ comment.indexOf("@removed") != -1;
}
/**
* Returns true if the given element is hidden.
*/
- private static boolean isHidden(Doc doc) {
+ private static boolean isHiddenOrRemoved(Doc doc) {
// Methods, fields, constructors.
if (doc instanceof MemberDoc) {
- return hasHideAnnotation(doc);
+ return hasHideOrRemovedAnnotation(doc);
}
// Classes, interfaces, enums, annotation types.
@@ -1340,7 +1351,7 @@
ClassDoc classDoc = (ClassDoc) doc;
// Check the containing package.
- if (hasHideAnnotation(classDoc.containingPackage())) {
+ if (hasHideOrRemovedAnnotation(classDoc.containingPackage())) {
return true;
}
@@ -1348,7 +1359,7 @@
// nested class.
ClassDoc current = classDoc;
do {
- if (hasHideAnnotation(current)) {
+ if (hasHideOrRemovedAnnotation(current)) {
return true;
}
@@ -1360,9 +1371,9 @@
}
/**
- * Filters out hidden elements.
+ * Filters out hidden and removed elements.
*/
- private static Object filterHidden(Object o, Class<?> expected) {
+ private static Object filterHiddenAndRemoved(Object o, Class<?> expected) {
if (o == null) {
return null;
}
@@ -1377,10 +1388,10 @@
Object[] array = (Object[]) o;
List<Object> list = new ArrayList<Object>(array.length);
for (Object entry : array) {
- if ((entry instanceof Doc) && isHidden((Doc) entry)) {
+ if ((entry instanceof Doc) && isHiddenOrRemoved((Doc) entry)) {
continue;
}
- list.add(filterHidden(entry, componentType));
+ list.add(filterHiddenAndRemoved(entry, componentType));
}
return list.toArray((Object[]) Array.newInstance(componentType, list.size()));
} else {
@@ -1418,7 +1429,7 @@
}
try {
- return filterHidden(method.invoke(target, args), method.getReturnType());
+ return filterHiddenAndRemoved(method.invoke(target, args), method.getReturnType());
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
@@ -1498,7 +1509,7 @@
// Now check the class for @Widget or if its in the android.widget package
// (unless the class is hidden or abstract, or non public)
- if (clazz.isHidden() == false && clazz.isPublic() && clazz.isAbstract() == false) {
+ if (clazz.isHiddenOrRemoved() == false && clazz.isPublic() && clazz.isAbstract() == false) {
boolean annotated = false;
ArrayList<AnnotationInstanceInfo> annotations = clazz.annotations();
if (!annotations.isEmpty()) {
@@ -1766,5 +1777,5 @@
return false;
}
}
-
-}
\ No newline at end of file
+
+}
diff --git a/src/com/google/doclava/Hierarchy.java b/src/com/google/doclava/Hierarchy.java
index 0887b63..0fddf9a 100755
--- a/src/com/google/doclava/Hierarchy.java
+++ b/src/com/google/doclava/Hierarchy.java
@@ -88,7 +88,7 @@
}
private static boolean exists(ClassInfo cl) {
- return cl != null && !cl.isHidden() && cl.isIncluded();
+ return cl != null && !cl.isHiddenOrRemoved() && cl.isIncluded();
}
private static void recurse(HashMap<String, TreeSet<String>> nodes, String name, Data hdf,
diff --git a/src/com/google/doclava/MemberInfo.java b/src/com/google/doclava/MemberInfo.java
index e5cc7a2..800edba 100644
--- a/src/com/google/doclava/MemberInfo.java
+++ b/src/com/google/doclava/MemberInfo.java
@@ -54,6 +54,23 @@
return super.isHidden();
}
+ @Override
+ public boolean isRemoved() {
+ if (mAnnotations != null) {
+ for (AnnotationInstanceInfo info : mAnnotations) {
+ if (Doclava.showAnnotations.contains(info.type().qualifiedName())) {
+ return false;
+ }
+ }
+ }
+ return super.isRemoved();
+ }
+
+ @Override
+ public boolean isHiddenOrRemoved() {
+ return isHidden() || isRemoved();
+ }
+
public String anchor() {
if (mSignature != null) {
return mName + mSignature;
@@ -101,7 +118,7 @@
public boolean isPrivate() {
return mIsPrivate;
}
-
+
public String scope() {
if (isPublic()) {
return "public";
@@ -134,7 +151,8 @@
}
public boolean checkLevel() {
- return Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, isHidden());
+ return Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate,
+ isHiddenOrRemoved());
}
public String kind() {
diff --git a/src/com/google/doclava/NavTree.java b/src/com/google/doclava/NavTree.java
index aa02d7c..cc4f43f 100644
--- a/src/com/google/doclava/NavTree.java
+++ b/src/com/google/doclava/NavTree.java
@@ -64,7 +64,7 @@
SortedMap<String, Object> sorted = new TreeMap<String, Object>();
for (ClassInfo cl : classes) {
- if (cl.isHidden()) {
+ if (cl.isHiddenOrRemoved()) {
continue;
}
sorted.put(cl.qualifiedName(), cl);
@@ -133,6 +133,7 @@
private static Node makePackageNode(PackageInfo pkg) {
List<Node> children = new ArrayList<Node>();
+ addClassNodes(children, "Annotations", pkg.annotations());
addClassNodes(children, "Interfaces", pkg.interfaces());
addClassNodes(children, "Classes", pkg.ordinaryClasses());
addClassNodes(children, "Enums", pkg.enums());
diff --git a/src/com/google/doclava/PackageInfo.java b/src/com/google/doclava/PackageInfo.java
index a3ecfe1..e997b27 100644
--- a/src/com/google/doclava/PackageInfo.java
+++ b/src/com/google/doclava/PackageInfo.java
@@ -61,6 +61,7 @@
}
private void initializeMaps() {
+ mAnnotationsMap = new HashMap<String, ClassInfo>();
mInterfacesMap = new HashMap<String, ClassInfo>();
mOrdinaryClassesMap = new HashMap<String, ClassInfo>();
mEnumsMap = new HashMap<String, ClassInfo>();
@@ -83,16 +84,82 @@
@Override
public boolean isHidden() {
- if (Doclava.hiddenPackages.contains(mName)) {
- return true;
+ if (mHidden == null) {
+ if (hasHideComment()) {
+ // We change the hidden value of the package if a class wants to be not hidden.
+ ClassInfo[][] types = new ClassInfo[][] { annotations(), interfaces(), ordinaryClasses(),
+ enums(), exceptions() };
+ for (ClassInfo[] type : types) {
+ if (type != null) {
+ for (ClassInfo c : type) {
+ if (c.hasShowAnnotation()) {
+ mHidden = false;
+ return false;
+ }
+ }
+ }
+ }
+ mHidden = true;
+ } else {
+ mHidden = false;
+ }
}
- return comment().isHidden();
+ return mHidden;
+ }
+
+ @Override
+ public boolean isRemoved() {
+ if (mRemoved == null) {
+ if (hasRemovedComment()) {
+ // We change the removed value of the package if a class wants to be not hidden.
+ ClassInfo[][] types = new ClassInfo[][] { annotations(), interfaces(), ordinaryClasses(),
+ enums(), exceptions() };
+ for (ClassInfo[] type : types) {
+ if (type != null) {
+ for (ClassInfo c : type) {
+ if (c.hasShowAnnotation()) {
+ mRemoved = false;
+ return false;
+ }
+ }
+ }
+ }
+ mRemoved = true;
+ } else {
+ mRemoved = false;
+ }
+ }
+
+ return mRemoved;
+ }
+
+ @Override
+ public boolean isHiddenOrRemoved() {
+ return isHidden() || isRemoved();
+ }
+
+ /**
+ * Used by ClassInfo to determine packages default visability before annoations.
+ */
+ public boolean hasHideComment() {
+ if (mHiddenByComment == null) {
+ mHiddenByComment = comment().isHidden();
+ }
+ return mHiddenByComment;
+ }
+
+ public boolean hasRemovedComment() {
+ if (mRemovedByComment == null) {
+ mRemovedByComment = comment().isRemoved();
+ }
+
+ return mRemovedByComment;
}
public boolean checkLevel() {
// TODO should return false if all classes are hidden but the package isn't.
// We don't have this so I'm not doing it now.
- return !isHidden();
+ return !isHiddenOrRemoved();
}
public String name() {
@@ -111,11 +178,15 @@
return comment().briefTags();
}
- public static ClassInfo[] filterHidden(ClassInfo[] classes) {
+ /**
+ * @param classes the Array of ClassInfo to be filtered
+ * @return an Array of ClassInfo without any hidden or removed classes
+ */
+ public static ClassInfo[] filterHiddenAndRemoved(ClassInfo[] classes) {
ArrayList<ClassInfo> out = new ArrayList<ClassInfo>();
for (ClassInfo cl : classes) {
- if (!cl.isHidden()) {
+ if (!cl.isHiddenOrRemoved()) {
out.add(cl);
}
}
@@ -133,6 +204,7 @@
public void makeClassLinkListHDF(Data data, String base) {
makeLink(data, base);
+ ClassInfo.makeLinkListHDF(data, base + ".annotations", annotations());
ClassInfo.makeLinkListHDF(data, base + ".interfaces", interfaces());
ClassInfo.makeLinkListHDF(data, base + ".classes", ordinaryClasses());
ClassInfo.makeLinkListHDF(data, base + ".enums", enums());
@@ -141,10 +213,20 @@
data.setValue(base + ".since", getSince());
}
+ public ClassInfo[] annotations() {
+ if (mAnnotations == null) {
+ mAnnotations =
+ ClassInfo.sortByName(filterHiddenAndRemoved(
+ Converter.convertClasses(mPackage.annotationTypes())));
+ }
+ return mAnnotations;
+ }
+
public ClassInfo[] interfaces() {
if (mInterfaces == null) {
mInterfaces =
- ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.interfaces())));
+ ClassInfo.sortByName(filterHiddenAndRemoved(
+ Converter.convertClasses(mPackage.interfaces())));
}
return mInterfaces;
}
@@ -152,14 +234,16 @@
public ClassInfo[] ordinaryClasses() {
if (mOrdinaryClasses == null) {
mOrdinaryClasses =
- ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.ordinaryClasses())));
+ ClassInfo.sortByName(filterHiddenAndRemoved(
+ Converter.convertClasses(mPackage.ordinaryClasses())));
}
return mOrdinaryClasses;
}
public ClassInfo[] enums() {
if (mEnums == null) {
- mEnums = ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.enums())));
+ mEnums = ClassInfo.sortByName(filterHiddenAndRemoved(
+ Converter.convertClasses(mPackage.enums())));
}
return mEnums;
}
@@ -167,14 +251,16 @@
public ClassInfo[] exceptions() {
if (mExceptions == null) {
mExceptions =
- ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.exceptions())));
+ ClassInfo.sortByName(filterHiddenAndRemoved(
+ Converter.convertClasses(mPackage.exceptions())));
}
return mExceptions;
}
public ClassInfo[] errors() {
if (mErrors == null) {
- mErrors = ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.errors())));
+ mErrors = ClassInfo.sortByName(filterHiddenAndRemoved(
+ Converter.convertClasses(mPackage.errors())));
}
return mErrors;
}
@@ -193,15 +279,21 @@
return mName.hashCode();
}
+ private Boolean mHidden = null;
+ private Boolean mHiddenByComment = null;
+ private Boolean mRemoved = null;
+ private Boolean mRemovedByComment = null;
private String mName;
private PackageDoc mPackage;
private ApiInfo mContainingApi;
+ private ClassInfo[] mAnnotations;
private ClassInfo[] mInterfaces;
private ClassInfo[] mOrdinaryClasses;
private ClassInfo[] mEnums;
private ClassInfo[] mExceptions;
private ClassInfo[] mErrors;
+ private HashMap<String, ClassInfo> mAnnotationsMap;
private HashMap<String, ClassInfo> mInterfacesMap;
private HashMap<String, ClassInfo> mOrdinaryClassesMap;
private HashMap<String, ClassInfo> mEnumsMap;
@@ -233,10 +325,24 @@
if (cls != null) {
return cls;
}
+ cls = mAnnotationsMap.get(className);
+
+ if (cls != null) {
+ return cls;
+ }
return mErrorsMap.get(className);
}
+ public void addAnnotation(ClassInfo cls) {
+ cls.setPackage(this);
+ mAnnotationsMap.put(cls.name(), cls);
+ }
+
+ public ClassInfo getAnnotation(String annotationName) {
+ return mAnnotationsMap.get(annotationName);
+ }
+
public void addInterface(ClassInfo cls) {
cls.setPackage(this);
mInterfacesMap.put(cls.name(), cls);
diff --git a/src/com/google/doclava/Scoped.java b/src/com/google/doclava/Scoped.java
index 03e42f9..931f299 100644
--- a/src/com/google/doclava/Scoped.java
+++ b/src/com/google/doclava/Scoped.java
@@ -24,6 +24,4 @@
boolean isPackagePrivate();
boolean isPrivate();
-
- boolean isHidden();
}
diff --git a/src/com/google/doclava/SinceTagger.java b/src/com/google/doclava/SinceTagger.java
index 858d98f..b8ad418 100644
--- a/src/com/google/doclava/SinceTagger.java
+++ b/src/com/google/doclava/SinceTagger.java
@@ -31,7 +31,7 @@
/**
* Applies version information to the Doclava class model from apicheck XML files. Sample usage:
- *
+ *
* <pre>
* ClassInfo[] classInfos = ...
*
@@ -59,7 +59,7 @@
for (Map.Entry<String, String> versionSpec : xmlToName.entrySet()) {
String xmlFile = versionSpec.getKey();
String versionName = versionSpec.getValue();
-
+
ApiInfo specApi;
try {
specApi = new ApiCheck().parseApi(xmlFile);
@@ -96,7 +96,7 @@
/**
* Applies the version information to {@code classDocs} where not already present.
- *
+ *
* @param versionName the version name
* @param specApi the spec for this version. If a symbol is in this spec, it was present in the
* named version
@@ -266,7 +266,8 @@
List<T> result = Collections.emptyList();
for (T t : all) {
// if this member has version info or isn't documented, skip it
- if (t.getSince() != null || t.isHidden() || !checkLevelRecursive(t.realContainingClass())) {
+ if (t.getSince() != null || t.isHiddenOrRemoved() ||
+ !checkLevelRecursive(t.realContainingClass())) {
continue;
}
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 9b9fc6e..560acef 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -32,12 +32,14 @@
public class Stubs {
public static void writeStubsAndApi(String stubsDir, String apiFile, String keepListFile,
- HashSet<String> stubPackages) {
+ String removedApiFile, HashSet<String> stubPackages) {
// figure out which classes we need
final HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
ClassInfo[] all = Converter.allClasses();
PrintStream apiWriter = null;
PrintStream keepListWriter = null;
+ PrintStream removedApiWriter = null;
+
if (apiFile != null) {
try {
File xml = new File(apiFile);
@@ -58,6 +60,17 @@
"Cannot open file for write.");
}
}
+ if (removedApiFile != null) {
+ try {
+ File removedApi = new File(removedApiFile);
+ removedApi.getParentFile().mkdirs();
+ removedApiWriter = new PrintStream(
+ new BufferedOutputStream(new FileOutputStream(removedApi)));
+ } catch (FileNotFoundException e) {
+ Errors.error(Errors.IO_ERROR, new SourcePositionInfo(removedApiFile, 0, 0),
+ "Cannot open file for write");
+ }
+ }
// If a class is public or protected, not hidden, and marked as included,
// then we can't strip it
for (ClassInfo cl : all) {
@@ -69,10 +82,10 @@
// complain about anything that looks includeable but is not supposed to
// be written, e.g. hidden things
for (ClassInfo cl : notStrippable) {
- if (!cl.isHidden()) {
+ if (!cl.isHiddenOrRemoved()) {
for (MethodInfo m : cl.selfMethods()) {
- if (m.isHidden()) {
- Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to hidden method "
+ if (m.isHiddenOrRemoved()) {
+ Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to unavailable method "
+ m.name());
} else if (m.isDeprecated()) {
// don't bother reporting deprecated methods
@@ -82,7 +95,7 @@
}
ClassInfo returnClass = m.returnType().asClassInfo();
- if (returnClass != null && returnClass.isHidden()) {
+ if (returnClass != null && returnClass.isHiddenOrRemoved()) {
Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
+ "." + m.name() + " returns unavailable type " + returnClass.name());
}
@@ -90,8 +103,8 @@
for (ParameterInfo p : m.parameters()) {
TypeInfo t = p.type();
if (!t.isPrimitive()) {
- if (t.asClassInfo().isHidden()) {
- Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Parameter of hidden type "
+ if (t.asClassInfo().isHiddenOrRemoved()) {
+ Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Parameter of unavailable type "
+ t.fullName() + " in " + cl.qualifiedName() + "." + m.name() + "()");
}
}
@@ -100,13 +113,13 @@
// annotations are handled like methods
for (MethodInfo m : cl.annotationElements()) {
- if (m.isHidden()) {
- Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to hidden annotation "
+ if (m.isHiddenOrRemoved()) {
+ Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to unavailable annotation "
+ m.name());
}
ClassInfo returnClass = m.returnType().asClassInfo();
- if (returnClass != null && returnClass.isHidden()) {
+ if (returnClass != null && returnClass.isHiddenOrRemoved()) {
Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Annotation '" + m.name()
+ "' returns unavailable type " + returnClass.name());
}
@@ -114,7 +127,7 @@
for (ParameterInfo p : m.parameters()) {
TypeInfo t = p.type();
if (!t.isPrimitive()) {
- if (t.asClassInfo().isHidden()) {
+ if (t.asClassInfo().isHiddenOrRemoved()) {
Errors.error(Errors.UNAVAILABLE_SYMBOL, p.position(),
"Reference to unavailable annotation class " + t.fullName());
}
@@ -128,6 +141,7 @@
}
}
+ // packages contains all the notStrippable classes mapped by their containing packages
HashMap<PackageInfo, List<ClassInfo>> packages = new HashMap<PackageInfo, List<ClassInfo>>();
for (ClassInfo cl : notStrippable) {
if (!cl.isDocOnly()) {
@@ -149,7 +163,6 @@
}
}
}
-
// write out the Api
if (apiWriter != null) {
writeApi(apiWriter, packages, notStrippable);
@@ -161,6 +174,23 @@
writeKeepList(keepListWriter, packages, notStrippable);
keepListWriter.close();
}
+
+ HashMap<PackageInfo, List<ClassInfo>> allPackageClassMap =
+ new HashMap<PackageInfo, List<ClassInfo>>();
+ for (ClassInfo cl : Converter.allClasses()) {
+ if (allPackageClassMap.containsKey(cl.containingPackage())) {
+ allPackageClassMap.get(cl.containingPackage()).add(cl);
+ } else {
+ ArrayList<ClassInfo> classes = new ArrayList<ClassInfo>();
+ classes.add(cl);
+ allPackageClassMap.put(cl.containingPackage(), classes);
+ }
+ }
+ // write out the removed Api
+ if (removedApiWriter != null) {
+ writeRemovedApi(removedApiWriter, allPackageClassMap, notStrippable);
+ removedApiWriter.close();
+ }
}
public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why) {
@@ -179,8 +209,8 @@
* }
*/
// cant strip any public fields or their generics
- if (cl.allSelfFields() != null) {
- for (FieldInfo fInfo : cl.allSelfFields()) {
+ if (cl.selfFields() != null) {
+ for (FieldInfo fInfo : cl.selfFields()) {
if (fInfo.type() != null) {
if (fInfo.type().asClassInfo() != null) {
cantStripThis(fInfo.type().asClassInfo(), notStrippable, "2:" + cl.qualifiedName());
@@ -217,7 +247,7 @@
// blow open super class and interfaces
ClassInfo supr = cl.realSuperclass();
if (supr != null) {
- if (supr.isHidden()) {
+ if (supr.isHiddenOrRemoved()) {
// cl is a public class declared as extending a hidden superclass.
// this is not a desired practice but it's happened, so we deal
// with it by finding the first super class which passes checklevel for purposes of
@@ -256,7 +286,7 @@
for (TypeInfo tInfoType : pInfo.type().typeArguments()) {
if (tInfoType.asClassInfo() != null) {
ClassInfo tcl = tInfoType.asClassInfo();
- if (tcl.isHidden()) {
+ if (tcl.isHiddenOrRemoved()) {
Errors
.error(Errors.UNAVAILABLE_SYMBOL, mInfo.position(),
"Parameter of hidden type " + tInfoType.fullName() + " in "
@@ -427,7 +457,7 @@
boolean fieldNeedsInitialization = false;
boolean staticFieldNeedsInitialization = false;
- for (FieldInfo field : cl.allSelfFields()) {
+ for (FieldInfo field : cl.selfFields()) {
if (!field.isDocOnly()) {
if (!field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
fieldNeedsInitialization = true;
@@ -445,8 +475,8 @@
// and the super class doesn't have a default constructor, write in a private constructor
// that works. TODO -- we generate this as protected, but we really should generate
// it as private unless it also exists in the real code.
- if ((cl.constructors().isEmpty() && (!cl.getNonWrittenConstructors().isEmpty() || fieldNeedsInitialization))
- && !cl.isAnnotation() && !cl.isInterface() && !cl.isEnum()) {
+ if ((cl.constructors().isEmpty() && (!cl.getNonWrittenConstructors().isEmpty() ||
+ fieldNeedsInitialization)) && !cl.isAnnotation() && !cl.isInterface() && !cl.isEnum()) {
// Errors.error(Errors.HIDDEN_CONSTRUCTOR,
// cl.position(), "No constructors " +
// "found and superclass has no parameterless constructor. A constructor " +
@@ -458,8 +488,9 @@
for (MethodInfo method : cl.allSelfMethods()) {
if (cl.isEnum()) {
- if (("values".equals(method.name()) && "()".equals(method.signature()))
- || ("valueOf".equals(method.name()) && "(java.lang.String)".equals(method.signature()))) {
+ if (("values".equals(method.name()) && "()".equals(method.signature())) ||
+ ("valueOf".equals(method.name()) &&
+ "(java.lang.String)".equals(method.signature()))) {
// skip these two methods on enums, because they're synthetic,
// although for some reason javadoc doesn't mark them as synthetic,
// maybe because they still want them documented
@@ -470,15 +501,18 @@
writeMethod(stream, method, false);
}
}
- // Write all methods that are hidden, but override abstract methods or interface methods.
+ // Write all methods that are hidden or removed, but override abstract methods or interface methods.
// These can't be hidden.
- for (MethodInfo method : cl.getHiddenMethods()) {
+ List<MethodInfo> hiddenAndRemovedMethods = cl.getHiddenMethods();
+ hiddenAndRemovedMethods.addAll(cl.getRemovedMethods());
+ for (MethodInfo method : hiddenAndRemovedMethods) {
MethodInfo overriddenMethod =
method.findRealOverriddenMethod(method.name(), method.signature(), notStrippable);
ClassInfo classContainingMethod =
method.findRealOverriddenClass(method.name(), method.signature());
- if (overriddenMethod != null && !overriddenMethod.isHidden() && !overriddenMethod.isDocOnly()
- && (overriddenMethod.isAbstract() || overriddenMethod.containingClass().isInterface())) {
+ if (overriddenMethod != null && !overriddenMethod.isHiddenOrRemoved() &&
+ !overriddenMethod.isDocOnly() &&
+ (overriddenMethod.isAbstract() || overriddenMethod.containingClass().isInterface())) {
method.setReason("1:" + classContainingMethod.qualifiedName());
cl.addMethod(method);
writeMethod(stream, method, false);
@@ -491,7 +525,7 @@
}
}
- for (FieldInfo field : cl.allSelfFields()) {
+ for (FieldInfo field : cl.selfFields()) {
if (!field.isDocOnly()) {
writeField(stream, field);
}
@@ -499,7 +533,7 @@
if (staticFieldNeedsInitialization) {
stream.print("static { ");
- for (FieldInfo field : cl.allSelfFields()) {
+ for (FieldInfo field : cl.selfFields()) {
if (!field.isDocOnly() && field.isStatic() && field.isFinal() && !fieldIsInitialized(field)
&& field.constantValue() == null) {
stream.print(field.name() + " = " + field.type().defaultValue() + "; ");
@@ -628,9 +662,9 @@
// Look only for overrides of an ancestor class implementation,
// not of e.g. an abstract or interface method declaration
if (!om.isAbstract()) {
- // If the parent is hidden, we can't rely on it to provide
+ // If the parent is hidden or removed, we can't rely on it to provide
// the API
- if (!om.isHidden()) {
+ if (!om.isHiddenOrRemoved()) {
// If the only "override" turns out to be in our own class
// (which sometimes happens in concrete subclasses of
// abstract base classes), it's not really an override
@@ -751,7 +785,7 @@
if (ann.type() != null && ann.type().qualifiedName().equals("java.lang.Override")) {
continue;
}
- if (!ann.type().isHidden()) {
+ if (!ann.type().isHiddenOrRemoved()) {
stream.println(ann.toString());
if (isDeprecated && ann.type() != null
&& ann.type().qualifiedName().equals("java.lang.Deprecated")) {
@@ -872,7 +906,7 @@
}
}
- ArrayList<FieldInfo> fields = cl.allSelfFields();
+ ArrayList<FieldInfo> fields = cl.selfFields();
Collections.sort(fields, FieldInfo.comparator);
for (FieldInfo fi : fields) {
writeFieldXML(xmlWriter, fi);
@@ -993,6 +1027,105 @@
return returnString;
}
+ static void writeRemovedApi(PrintStream apiWriter, HashMap<PackageInfo,
+ List<ClassInfo>> allPackageClassMap, Set<ClassInfo> notStrippable) {
+ final PackageInfo[] packages = allPackageClassMap.keySet().toArray(new PackageInfo[0]);
+ Arrays.sort(packages, PackageInfo.comparator);
+ for (PackageInfo pkg : packages) {
+ // beware that pkg.allClasses() has no class in it at the moment
+ final List<ClassInfo> classes = allPackageClassMap.get(pkg);
+ Collections.sort(classes, ClassInfo.comparator);
+ boolean hasWrittenPackageHead = false;
+ for (ClassInfo cl : classes) {
+ if (cl.hasRemovedSelfMembers()) {
+ if (!hasWrittenPackageHead) {
+ hasWrittenPackageHead = true;
+ apiWriter.print("package ");
+ apiWriter.print(pkg.qualifiedName());
+ apiWriter.print(" {\n\n");
+ }
+ writeClassRemovedSelfMembers(apiWriter, cl, notStrippable);
+ }
+ }
+
+ // the package contains some classes with some removed members
+ if (hasWrittenPackageHead) {
+ apiWriter.print("}\n\n");
+ }
+ }
+ }
+
+ /**
+ * Write the removed members of the class to removed.txt
+ */
+ private static void writeClassRemovedSelfMembers(PrintStream apiWriter, ClassInfo cl,
+ Set<ClassInfo> notStrippable) {
+ apiWriter.print(" ");
+ apiWriter.print(cl.scope());
+ if (cl.isStatic()) {
+ apiWriter.print(" static");
+ }
+ if (cl.isFinal()) {
+ apiWriter.print(" final");
+ }
+ if (cl.isAbstract()) {
+ apiWriter.print(" abstract");
+ }
+ if (cl.isDeprecated()) {
+ apiWriter.print(" deprecated");
+ }
+ apiWriter.print(" ");
+ apiWriter.print(cl.isInterface() ? "interface" : "class");
+ apiWriter.print(" ");
+ apiWriter.print(cl.name());
+
+ if (!cl.isInterface()
+ && !"java.lang.Object".equals(cl.qualifiedName())
+ && cl.realSuperclass() != null
+ && !"java.lang.Object".equals(cl.realSuperclass().qualifiedName())) {
+ apiWriter.print(" extends ");
+ apiWriter.print(cl.realSuperclass().qualifiedName());
+ }
+
+ ArrayList<ClassInfo> interfaces = cl.realInterfaces();
+ Collections.sort(interfaces, ClassInfo.comparator);
+ boolean first = true;
+ for (ClassInfo iface : interfaces) {
+ if (notStrippable.contains(iface)) {
+ if (first) {
+ apiWriter.print(" implements");
+ first = false;
+ }
+ apiWriter.print(" ");
+ apiWriter.print(iface.qualifiedName());
+ }
+ }
+
+ apiWriter.print(" {\n");
+
+ List<MethodInfo> constructors = cl.getRemovedConstructors();
+ for (MethodInfo mi : constructors) {
+ writeConstructorApi(apiWriter, mi);
+ }
+
+ List<MethodInfo> methods = cl.getRemovedSelfMethods();
+ for (MethodInfo mi : methods) {
+ writeMethodApi(apiWriter, mi);
+ }
+
+ List<FieldInfo> enums = cl.getRemovedSelfEnumConstants();
+ for (FieldInfo fi : enums) {
+ writeFieldApi(apiWriter, fi, "enum_constant");
+ }
+
+ List<FieldInfo> fields = cl.getRemovedSelfFields();
+ for (FieldInfo fi : fields) {
+ writeFieldApi(apiWriter, fi, "field");
+ }
+
+ apiWriter.print(" }\n\n");
+ }
+
public static void writeApi(PrintStream apiWriter, Collection<PackageInfo> pkgs) {
final PackageInfo[] packages = pkgs.toArray(new PackageInfo[pkgs.size()]);
Arrays.sort(packages, PackageInfo.comparator);
@@ -1107,7 +1240,7 @@
writeFieldApi(apiWriter, fi, "enum_constant");
}
- ArrayList<FieldInfo> fields = cl.allSelfFields();
+ ArrayList<FieldInfo> fields = cl.selfFields();
Collections.sort(fields, FieldInfo.comparator);
for (FieldInfo fi : fields) {
writeFieldApi(apiWriter, fi, "field");
@@ -1163,7 +1296,8 @@
apiWriter.print(";\n");
}
- static void writeParametersApi(PrintStream apiWriter, MethodInfo method, ArrayList<ParameterInfo> params) {
+ static void writeParametersApi(PrintStream apiWriter, MethodInfo method,
+ ArrayList<ParameterInfo> params) {
apiWriter.print("(");
for (ParameterInfo pi : params) {
@@ -1297,9 +1431,8 @@
ArrayList<MethodInfo> methods = cl.allSelfMethods();
Collections.sort(methods, MethodInfo.comparator);
for (MethodInfo mi : methods) {
- if (!methodIsOverride(notStrippable, mi)) {
- writeMethodKeepList(keepListWriter, mi);
- }
+ // allSelfMethods is the non-hidden and visible methods. See Doclava.checkLevel.
+ writeMethodKeepList(keepListWriter, mi);
}
keepListWriter.print("\n");
@@ -1312,7 +1445,7 @@
keepListWriter.print("\n");
- ArrayList<FieldInfo> fields = cl.allSelfFields();
+ ArrayList<FieldInfo> fields = cl.selfFields();
Collections.sort(fields, FieldInfo.comparator);
for (FieldInfo fi : fields) {
writeFieldKeepList(keepListWriter, fi);
diff --git a/src/com/google/doclava/TodoFile.java b/src/com/google/doclava/TodoFile.java
index 5cf4f1e..36df2c7 100644
--- a/src/com/google/doclava/TodoFile.java
+++ b/src/com/google/doclava/TodoFile.java
@@ -74,7 +74,7 @@
int classIndex = 0;
for (ClassInfo cl : classes) {
- if (cl.isHidden()) {
+ if (cl.isHiddenOrRemoved()){
continue;
}
diff --git a/src/com/google/doclava/TypeInfo.java b/src/com/google/doclava/TypeInfo.java
index 048d0ea..36d9634 100644
--- a/src/com/google/doclava/TypeInfo.java
+++ b/src/com/google/doclava/TypeInfo.java
@@ -150,38 +150,61 @@
return mFullName;
}
- public String fullNameNoDimension(HashSet<String> typeVars) {
- String fullName = null;
+ public String fullNameNoBounds(HashSet<String> typeVars) {
+ return fullNameNoDimensionNoBounds(typeVars) + mDimension;
+ }
+
+ // don't recurse forever with the parameters. This handles
+ // Enum<K extends Enum<K>>
+ private boolean checkRecurringTypeVar(HashSet<String> typeVars) {
if (mIsTypeVariable) {
if (typeVars.contains(mQualifiedTypeName)) {
- // don't recurse forever with the parameters. This handles
- // Enum<K extends Enum<K>>
- return mQualifiedTypeName;
+ return true;
}
typeVars.add(mQualifiedTypeName);
}
+ return false;
+ }
+
+ private String fullNameNoDimensionNoBounds(HashSet<String> typeVars) {
+ String fullName = null;
+ if (checkRecurringTypeVar(typeVars)) {
+ return mQualifiedTypeName;
+ }
/*
* if (fullName != null) { return fullName; }
*/
fullName = mQualifiedTypeName;
if (mTypeArguments != null && !mTypeArguments.isEmpty()) {
fullName += typeArgumentsName(mTypeArguments, typeVars);
- } else if (mSuperBounds != null && !mSuperBounds.isEmpty()) {
+ }
+ return fullName;
+ }
+
+ public String fullNameNoDimension(HashSet<String> typeVars) {
+ String fullName = null;
+ if (checkRecurringTypeVar(typeVars)) {
+ return mQualifiedTypeName;
+ }
+ fullName = fullNameNoDimensionNoBounds(typeVars);
+ if (mTypeArguments == null || mTypeArguments.isEmpty()) {
+ if (mSuperBounds != null && !mSuperBounds.isEmpty()) {
for (TypeInfo superBound : mSuperBounds) {
if (superBound == mSuperBounds.get(0)) {
- fullName += " super " + superBound.fullName(typeVars);
+ fullName += " super " + superBound.fullNameNoBounds(typeVars);
} else {
- fullName += " & " + superBound.fullName(typeVars);
+ fullName += " & " + superBound.fullNameNoBounds(typeVars);
}
}
- } else if (mExtendsBounds != null && !mExtendsBounds.isEmpty()) {
+ } else if (mExtendsBounds != null && !mExtendsBounds.isEmpty()) {
for (TypeInfo extendsBound : mExtendsBounds) {
if (extendsBound == mExtendsBounds.get(0)) {
- fullName += " extends " + extendsBound.fullName(typeVars);
+ fullName += " extends " + extendsBound.fullNameNoBounds(typeVars);
} else {
- fullName += " & " + extendsBound.fullName(typeVars);
+ fullName += " & " + extendsBound.fullNameNoBounds(typeVars);
}
}
+ }
}
return fullName;
}
diff --git a/src/com/google/doclava/apicheck/ApiCheck.java b/src/com/google/doclava/apicheck/ApiCheck.java
index fb5b011..28d7ce0 100644
--- a/src/com/google/doclava/apicheck/ApiCheck.java
+++ b/src/com/google/doclava/apicheck/ApiCheck.java
@@ -103,10 +103,16 @@
ApiInfo oldApi;
ApiInfo newApi;
-
+ ApiInfo oldRemovedApi;
+ ApiInfo newRemovedApi;
+
+ // commandline options look like:
+ // [other optoins] old_api.txt new_api.txt old_removed_api.txt new_removed_api.txt
try {
oldApi = parseApi(args.get(0));
newApi = parseApi(args.get(1));
+ oldRemovedApi = parseApi(args.get(2));
+ newRemovedApi = parseApi(args.get(3));
} catch (ApiParseException e) {
e.printStackTrace();
System.err.println("Error parsing API");
@@ -118,6 +124,10 @@
oldApi.isConsistent(newApi);
}
+ if (!Errors.hadError) {
+ oldRemovedApi.isConsistent(newRemovedApi);
+ }
+
return new Report(Errors.hadError ? 1 : 0, Errors.getErrors());
}