diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/google/doclava/ClassInfo.java | 248 | ||||
-rw-r--r-- | src/com/google/doclava/Comment.java | 52 | ||||
-rw-r--r-- | src/com/google/doclava/Converter.java | 135 | ||||
-rw-r--r-- | src/com/google/doclava/DocInfo.java | 27 | ||||
-rw-r--r-- | src/com/google/doclava/Doclava.java | 88 | ||||
-rwxr-xr-x | src/com/google/doclava/Hierarchy.java | 2 | ||||
-rw-r--r-- | src/com/google/doclava/MemberInfo.java | 22 | ||||
-rw-r--r-- | src/com/google/doclava/NavTree.java | 2 | ||||
-rw-r--r-- | src/com/google/doclava/PackageInfo.java | 92 | ||||
-rw-r--r-- | src/com/google/doclava/Scoped.java | 2 | ||||
-rw-r--r-- | src/com/google/doclava/SinceTagger.java | 9 | ||||
-rw-r--r-- | src/com/google/doclava/Stubs.java | 186 | ||||
-rw-r--r-- | src/com/google/doclava/TodoFile.java | 2 | ||||
-rw-r--r-- | src/com/google/doclava/apicheck/ApiCheck.java | 12 |
14 files changed, 673 insertions, 206 deletions
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java index e60f4b8..3cda7ec 100644 --- a/src/com/google/doclava/ClassInfo.java +++ b/src/com/google/doclava/ClassInfo.java @@ -117,10 +117,18 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco mConstructors = new ArrayList<MethodInfo>(); for (MethodInfo m : mAllConstructors) { - if (!m.isHidden()) { + if (!m.isHiddenOrRemoved()) { mConstructors.add(m); } } @@ -462,13 +471,13 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco } 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 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco } for (FieldInfo f : mAllSelfFields) { - if (!f.isHidden()) { + if (!f.isHiddenOrRemoved()) { fields.put(f.name(), f); } } @@ -539,7 +548,7 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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,16 +1348,17 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco @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) { @@ -1223,6 +1377,42 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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()) { @@ -1481,7 +1671,11 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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>(); @@ -1505,8 +1699,9 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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; @@ -1520,6 +1715,13 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco // 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. @@ -1805,7 +2007,7 @@ public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Sco 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 class Comment { } 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 @@ public class Comment { private void initImpl() { isHidden(); + isRemoved(); isDocOnly(); isDeprecated(); @@ -539,9 +538,10 @@ public class Comment { } 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.ArrayList; 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 @@ public class Converter { 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 @@ public class Converter { 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 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 out.toArray(new MethodInfo[out.size()]); + + 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) { + 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 allFields; + } + + /** + * 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]); - // 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); - } + List<MethodInfo> allMethods = new ArrayList<MethodInfo>(); + for (ExecutableMemberDoc method : methods) { + MethodInfo methodInfo = Converter.obtainMethod(method); + allMethods.add(methodInfo); } - return out.toArray(new MethodInfo[out.size()]); + return allMethods; } - private static MethodInfo[] convertMethods(ConstructorDoc[] methods) { + /** + * 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; - 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> 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()]); - } - private static MethodInfo obtainMethod(MethodDoc o) { - return (MethodInfo) mMethods.obtain(o); + return ctors.toArray(new MethodInfo[ctors.size()]); } - private static MethodInfo obtainMethod(ConstructorDoc o) { + private static <E extends ExecutableMemberDoc> MethodInfo obtainMethod(E o) { return (MethodInfo) mMethods.obtain(o); } @@ -559,11 +582,11 @@ public class Converter { 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 @@ public class Converter { @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 @@ public abstract class DocInfo { * 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 abstract class DocInfo { public String getSince() { return mSince; } - + public void setDeprecatedSince(String since) { mDeprecatedSince = since; } @@ -100,11 +119,11 @@ public abstract class DocInfo { 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 b3e3eb3..c947d1e 100644 --- a/src/com/google/doclava/Doclava.java +++ b/src/com/google/doclava/Doclava.java @@ -114,7 +114,6 @@ public class Doclava { public static boolean checkLevel(boolean pub, boolean prot, boolean pkgp, boolean priv, boolean hidden) { - int level = 0; if (hidden && !checkLevel(SHOW_HIDDEN)) { return false; } @@ -148,6 +147,7 @@ public class Doclava { // 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>(); @@ -234,7 +234,10 @@ public class Doclava { 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; @@ -336,7 +339,7 @@ public class Doclava { } writeAssets(); - + // Navigation tree String refPrefix = new String(); if(gmsRef){ @@ -381,8 +384,8 @@ public class Doclava { } // 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(); @@ -609,6 +612,9 @@ public class Doclava { if (option.equals("-api")) { return 2; } + if (option.equals("-removedApi")) { + return 2; + } if (option.equals("-nodocs")) { return 1; } @@ -693,10 +699,10 @@ public class Doclava { 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 < 6) { @@ -724,17 +730,17 @@ public class Doclava { 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){ @@ -843,7 +849,7 @@ public class Doclava { SortedMap<String, Object> sorted = new TreeMap<String, Object>(); for (ClassInfo cl : classes) { - if (cl.isHidden()) { + if (cl.isHiddenOrRemoved()) { continue; } sorted.put(cl.qualifiedName(), cl); @@ -912,7 +918,8 @@ public class Doclava { // 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 @@ -1025,7 +1032,7 @@ public class Doclava { // 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); } } @@ -1069,10 +1076,11 @@ public class Doclava { 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 < 6) { @@ -1100,17 +1108,17 @@ public class Doclava { 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; } @@ -1177,7 +1185,8 @@ public class Doclava { 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; } @@ -1231,7 +1240,7 @@ public class Doclava { * 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); } * @@ -1250,7 +1259,7 @@ public class Doclava { ClassInfo[] classes = Converter.rootClasses(); ArrayList<ClassInfo> info = new ArrayList<ClassInfo>(); for (ClassInfo cl : classes) { - if (!cl.isHidden()) { + if (!cl.isHiddenOrRemoved()) { info.add(cl); } } @@ -1265,7 +1274,7 @@ public class Doclava { for (ClassInfo cl : classes) { Data data = makePackageHDF(); - if (!cl.isHidden()) { + if (!cl.isHiddenOrRemoved()) { writeClass(cl, data); } } @@ -1282,7 +1291,7 @@ public class Doclava { 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); } } @@ -1318,20 +1327,21 @@ public class Doclava { } /** - * 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. @@ -1339,7 +1349,7 @@ public class Doclava { ClassDoc classDoc = (ClassDoc) doc; // Check the containing package. - if (hasHideAnnotation(classDoc.containingPackage())) { + if (hasHideOrRemovedAnnotation(classDoc.containingPackage())) { return true; } @@ -1347,7 +1357,7 @@ public class Doclava { // nested class. ClassDoc current = classDoc; do { - if (hasHideAnnotation(current)) { + if (hasHideOrRemovedAnnotation(current)) { return true; } @@ -1359,9 +1369,9 @@ public class Doclava { } /** - * 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; } @@ -1376,10 +1386,10 @@ public class Doclava { 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 { @@ -1417,7 +1427,7 @@ public class Doclava { } try { - return filterHidden(method.invoke(target, args), method.getReturnType()); + return filterHiddenAndRemoved(method.invoke(target, args), method.getReturnType()); } catch (InvocationTargetException e) { throw e.getTargetException(); } @@ -1497,7 +1507,7 @@ public class Doclava { // 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()) { @@ -1765,5 +1775,5 @@ public class Doclava { return false; } } - + } 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 @@ public class Hierarchy { } 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 @@ public abstract class MemberInfo extends DocInfo implements Comparable, Scoped { 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 abstract class MemberInfo extends DocInfo implements Comparable, Scoped { public boolean isPrivate() { return mIsPrivate; } - + public String scope() { if (isPublic()) { return "public"; @@ -134,7 +151,8 @@ public abstract class MemberInfo extends DocInfo implements Comparable, Scoped { } 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 e36babe..cc4f43f 100644 --- a/src/com/google/doclava/NavTree.java +++ b/src/com/google/doclava/NavTree.java @@ -64,7 +64,7 @@ public class NavTree { SortedMap<String, Object> sorted = new TreeMap<String, Object>(); for (ClassInfo cl : classes) { - if (cl.isHidden()) { + if (cl.isHiddenOrRemoved()) { continue; } sorted.put(cl.qualifiedName(), cl); diff --git a/src/com/google/doclava/PackageInfo.java b/src/com/google/doclava/PackageInfo.java index 43b9800..e997b27 100644 --- a/src/com/google/doclava/PackageInfo.java +++ b/src/com/google/doclava/PackageInfo.java @@ -84,42 +84,82 @@ public class PackageInfo extends DocInfo implements ContainerInfo { @Override public boolean isHidden() { - if (mHidden == -1) { + 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() }; + ClassInfo[][] types = new ClassInfo[][] { annotations(), interfaces(), ordinaryClasses(), + enums(), exceptions() }; for (ClassInfo[] type : types) { if (type != null) { for (ClassInfo c : type) { if (c.hasShowAnnotation()) { - mHidden = 0; + mHidden = false; return false; } } } } - mHidden = 1; + mHidden = true; } else { - mHidden = 0; + mHidden = false; } } - return mHidden != 0; + 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 == -1) { - mHiddenByComment = comment().isHidden() ? 1 : 0; + if (mHiddenByComment == null) { + mHiddenByComment = comment().isHidden(); } - return mHiddenByComment != 0; + 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() { @@ -138,11 +178,15 @@ public class PackageInfo extends DocInfo implements ContainerInfo { 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); } } @@ -172,7 +216,8 @@ public class PackageInfo extends DocInfo implements ContainerInfo { public ClassInfo[] annotations() { if (mAnnotations == null) { mAnnotations = - ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.annotationTypes()))); + ClassInfo.sortByName(filterHiddenAndRemoved( + Converter.convertClasses(mPackage.annotationTypes()))); } return mAnnotations; } @@ -180,7 +225,8 @@ public class PackageInfo extends DocInfo implements ContainerInfo { public ClassInfo[] interfaces() { if (mInterfaces == null) { mInterfaces = - ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.interfaces()))); + ClassInfo.sortByName(filterHiddenAndRemoved( + Converter.convertClasses(mPackage.interfaces()))); } return mInterfaces; } @@ -188,14 +234,16 @@ public class PackageInfo extends DocInfo implements ContainerInfo { 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; } @@ -203,14 +251,16 @@ public class PackageInfo extends DocInfo implements ContainerInfo { 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; } @@ -229,8 +279,10 @@ public class PackageInfo extends DocInfo implements ContainerInfo { return mName.hashCode(); } - private int mHidden = -1; - private int mHiddenByComment = -1; + 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; 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 @@ public interface Scoped { 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 @@ import java.util.Map; /** * Applies version information to the Doclava class model from apicheck XML files. Sample usage: - * + * * <pre> * ClassInfo[] classInfos = ... * @@ -59,7 +59,7 @@ public class SinceTagger { 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 @@ public class SinceTagger { /** * 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 @@ public class SinceTagger { 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..3d4f7e2 100644 --- a/src/com/google/doclava/Stubs.java +++ b/src/com/google/doclava/Stubs.java @@ -32,12 +32,14 @@ import java.util.Set; 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 @@ public class Stubs { "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 @@ public class Stubs { // 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 @@ public class Stubs { } 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 @@ public class Stubs { 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 @@ public class Stubs { // 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 @@ public class Stubs { 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 @@ public class Stubs { } } + // 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 @@ public class Stubs { } } } - // write out the Api if (apiWriter != null) { writeApi(apiWriter, packages, notStrippable); @@ -161,6 +174,23 @@ public class Stubs { 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) { @@ -217,7 +247,7 @@ public class Stubs { // 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 @@ public class Stubs { 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 " @@ -445,8 +475,8 @@ public class Stubs { // 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 @@ public class Stubs { 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 @@ public class Stubs { 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); @@ -628,9 +662,9 @@ public class Stubs { // 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 @@ public class Stubs { 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")) { @@ -993,6 +1027,105 @@ public class Stubs { 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); @@ -1163,7 +1296,8 @@ public class Stubs { 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) { 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 @@ public class TodoFile { int classIndex = 0; for (ClassInfo cl : classes) { - if (cl.isHidden()) { + if (cl.isHiddenOrRemoved()){ continue; } 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 @@ public class ApiCheck { 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 @@ public class ApiCheck { oldApi.isConsistent(newApi); } + if (!Errors.hadError) { + oldRemovedApi.isConsistent(newRemovedApi); + } + return new Report(Errors.hadError ? 1 : 0, Errors.getErrors()); } |