summaryrefslogtreecommitdiffstats
path: root/tools/apicheck
diff options
context:
space:
mode:
Diffstat (limited to 'tools/apicheck')
-rw-r--r--tools/apicheck/src/com/android/apicheck/ApiCheck.java1
-rw-r--r--tools/apicheck/src/com/android/apicheck/ApiInfo.java3
-rw-r--r--tools/apicheck/src/com/android/apicheck/ClassInfo.java62
3 files changed, 38 insertions, 28 deletions
diff --git a/tools/apicheck/src/com/android/apicheck/ApiCheck.java b/tools/apicheck/src/com/android/apicheck/ApiCheck.java
index c8272dd..b2f2265 100644
--- a/tools/apicheck/src/com/android/apicheck/ApiCheck.java
+++ b/tools/apicheck/src/com/android/apicheck/ApiCheck.java
@@ -107,6 +107,7 @@ public class ApiCheck {
xmlreader.parse(new InputSource(fileReader));
ApiInfo apiInfo = handler.getApi();
apiInfo.resolveSuperclasses();
+ apiInfo.resolveInterfaces();
return apiInfo;
} catch (SAXParseException e) {
Errors.error(Errors.PARSE_ERROR,
diff --git a/tools/apicheck/src/com/android/apicheck/ApiInfo.java b/tools/apicheck/src/com/android/apicheck/ApiInfo.java
index c237814..47b9a15 100644
--- a/tools/apicheck/src/com/android/apicheck/ApiInfo.java
+++ b/tools/apicheck/src/com/android/apicheck/ApiInfo.java
@@ -31,14 +31,13 @@ public class ApiInfo {
return mAllClasses.get(name);
}
- private void resolveInterfaces() {
+ public void resolveInterfaces() {
for (ClassInfo c : mAllClasses.values()) {
c.resolveInterfaces(this);
}
}
public boolean isConsistent(ApiInfo otherApi) {
- resolveInterfaces();
boolean consistent = true;
for (PackageInfo pInfo : mPackages.values()) {
if (otherApi.getPackages().containsKey(pInfo.name())) {
diff --git a/tools/apicheck/src/com/android/apicheck/ClassInfo.java b/tools/apicheck/src/com/android/apicheck/ClassInfo.java
index e62a3d0..962a316 100644
--- a/tools/apicheck/src/com/android/apicheck/ClassInfo.java
+++ b/tools/apicheck/src/com/android/apicheck/ClassInfo.java
@@ -86,41 +86,35 @@ public class ClassInfo {
return mIsFinal;
}
- // Find a superclass implementation of the given method. Looking at our superclass
- // instead of at 'this' is unusual, but it fits the point-of-call demands well.
- public MethodInfo overriddenMethod(MethodInfo candidate) {
- if (mSuperClass == null) {
+ // Find a superclass implementation of the given method.
+ public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
+ if (newClassObj == null) {
return null;
}
-
- // does our immediate superclass have it?
- ClassInfo sup = mSuperClass;
- for (MethodInfo mi : sup.mMethods.values()) {
+ for (MethodInfo mi : newClassObj.mMethods.values()) {
if (mi.matches(candidate)) {
// found it
return mi;
}
}
- // no, so recurse
- if (sup.mSuperClass != null) {
- return mSuperClass.overriddenMethod(candidate);
- }
-
- // no parent, so we just don't have it
- return null;
+ // not found here. recursively search ancestors
+ return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperClass);
}
// Find a superinterface declaration of the given method.
- public MethodInfo interfaceMethod(MethodInfo candidate) {
- for (ClassInfo interfaceInfo : mInterfaces) {
+ public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
+ if (newClassObj == null) {
+ return null;
+ }
+ for (ClassInfo interfaceInfo : newClassObj.mInterfaces) {
for (MethodInfo mi : interfaceInfo.mMethods.values()) {
if (mi.matches(candidate)) {
return mi;
}
}
}
- return (mSuperClass != null) ? mSuperClass.interfaceMethod(candidate) : null;
+ return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperClass);
}
public boolean isConsistent(ClassInfo cl) {
@@ -135,11 +129,7 @@ public class ClassInfo {
consistent = false;
}
for (String iface : mInterfaceNames) {
- boolean found = false;
- for (ClassInfo c = cl; c != null && !found; c = c.mSuperClass) {
- found = c.mInterfaceNames.contains(iface);
- }
- if (!found) {
+ if (!implementsInterface(cl, iface)) {
Errors.error(Errors.REMOVED_INTERFACE, cl.position(),
"Class " + qualifiedName() + " no longer implements " + iface);
}
@@ -163,9 +153,9 @@ public class ClassInfo {
* Check our ancestry to see if there's an inherited version that still
* fulfills the API requirement.
*/
- MethodInfo mi = mInfo.containingClass().overriddenMethod(mInfo);
+ MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
if (mi == null) {
- mi = mInfo.containingClass().interfaceMethod(mInfo);
+ mi = ClassInfo.interfaceMethod(mInfo, cl);
}
if (mi == null) {
Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
@@ -179,7 +169,7 @@ public class ClassInfo {
/* Similarly to the above, do not fail if this "new" method is
* really an override of an existing superclass method.
*/
- MethodInfo mi = mInfo.containingClass().overriddenMethod(mInfo);
+ MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
if (mi == null) {
Errors.error(Errors.ADDED_METHOD, mInfo.position(),
"Added public method " + mInfo.qualifiedName());
@@ -274,6 +264,26 @@ public class ClassInfo {
return consistent;
}
+ /**
+ * 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.
+ */
+ private boolean implementsInterface(ClassInfo cl, String iface) {
+ if (cl.qualifiedName().equals(iface)) {
+ return true;
+ }
+ for (ClassInfo clImplements : cl.mInterfaces) {
+ if (implementsInterface(clImplements, iface)) {
+ return true;
+ }
+ }
+ if (cl.mSuperClass != null && implementsInterface(cl.mSuperClass, iface)) {
+ return true;
+ }
+ return false;
+ }
+
public void resolveInterfaces(ApiInfo apiInfo) {
for (String interfaceName : mInterfaceNames) {
mInterfaces.add(apiInfo.findClass(interfaceName));