diff --git a/tools/apicheck/src/com/android/apicheck/ApiInfo.java b/tools/apicheck/src/com/android/apicheck/ApiInfo.java index 01d8f9e76d..c237814552 100644 --- a/tools/apicheck/src/com/android/apicheck/ApiInfo.java +++ b/tools/apicheck/src/com/android/apicheck/ApiInfo.java @@ -26,8 +26,19 @@ public class ApiInfo { mPackages = new HashMap(); mAllClasses = new HashMap(); } + + public ClassInfo findClass(String name) { + return mAllClasses.get(name); + } + + private 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 d4416f4aa6..e62a3d0d64 100644 --- a/tools/apicheck/src/com/android/apicheck/ClassInfo.java +++ b/tools/apicheck/src/com/android/apicheck/ClassInfo.java @@ -26,7 +26,8 @@ public class ClassInfo { private boolean mIsFinal; private String mDeprecated; private String mScope; - private List mInterfaces; + private List mInterfaceNames; + private List mInterfaces; private HashMap mMethods; private HashMap mFields; private HashMap mConstructors; @@ -48,7 +49,8 @@ public class ClassInfo { mIsFinal = isFinal; mDeprecated = deprecated; mScope = visibility; - mInterfaces = new ArrayList(); + mInterfaceNames = new ArrayList(); + mInterfaces = new ArrayList(); mMethods = new HashMap(); mFields = new HashMap(); mConstructors = new HashMap(); @@ -109,6 +111,18 @@ public class ClassInfo { return null; } + // Find a superinterface declaration of the given method. + public MethodInfo interfaceMethod(MethodInfo candidate) { + for (ClassInfo interfaceInfo : mInterfaces) { + for (MethodInfo mi : interfaceInfo.mMethods.values()) { + if (mi.matches(candidate)) { + return mi; + } + } + } + return (mSuperClass != null) ? mSuperClass.interfaceMethod(candidate) : null; + } + public boolean isConsistent(ClassInfo cl) { cl.mExistsInBoth = true; mExistsInBoth = true; @@ -120,18 +134,18 @@ public class ClassInfo { + " changed class/interface declaration"); consistent = false; } - for (String iface : mInterfaces) { + for (String iface : mInterfaceNames) { boolean found = false; for (ClassInfo c = cl; c != null && !found; c = c.mSuperClass) { - found = c.mInterfaces.contains(iface); + found = c.mInterfaceNames.contains(iface); } if (!found) { Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName() + " no longer implements " + iface); } } - for (String iface : cl.mInterfaces) { - if (!mInterfaces.contains(iface)) { + for (String iface : cl.mInterfaceNames) { + if (!mInterfaceNames.contains(iface)) { Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface + " to class " + qualifiedName()); @@ -150,6 +164,9 @@ public class ClassInfo { * fulfills the API requirement. */ MethodInfo mi = mInfo.containingClass().overriddenMethod(mInfo); + if (mi == null) { + mi = mInfo.containingClass().interfaceMethod(mInfo); + } if (mi == null) { Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public method " + mInfo.qualifiedName()); @@ -256,9 +273,15 @@ public class ClassInfo { return consistent; } + + public void resolveInterfaces(ApiInfo apiInfo) { + for (String interfaceName : mInterfaceNames) { + mInterfaces.add(apiInfo.findClass(interfaceName)); + } + } public void addInterface(String name) { - mInterfaces.add(name); + mInterfaceNames.add(name); } public void addMethod(MethodInfo mInfo) {