Teach apicheck about interface methods.
If a method is declared by an interface implemented directly by a class, or indirectly by any of its superclasses, removing a duplicate declaration is not an API change. (This fixes the master build, which is currently broken because getOption and setOption were removed from DatagramSocketImpl because they were duplicate declarations of the same methods in the implemented interface SocketOptions.)
This commit is contained in:
parent
9dd765ff2c
commit
03ead3365d
2 changed files with 41 additions and 7 deletions
|
@ -26,8 +26,19 @@ public class ApiInfo {
|
|||
mPackages = new HashMap<String, PackageInfo>();
|
||||
mAllClasses = new HashMap<String, ClassInfo>();
|
||||
}
|
||||
|
||||
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())) {
|
||||
|
|
|
@ -26,7 +26,8 @@ public class ClassInfo {
|
|||
private boolean mIsFinal;
|
||||
private String mDeprecated;
|
||||
private String mScope;
|
||||
private List<String> mInterfaces;
|
||||
private List<String> mInterfaceNames;
|
||||
private List<ClassInfo> mInterfaces;
|
||||
private HashMap<String, MethodInfo> mMethods;
|
||||
private HashMap<String, FieldInfo> mFields;
|
||||
private HashMap<String, ConstructorInfo> mConstructors;
|
||||
|
@ -48,7 +49,8 @@ public class ClassInfo {
|
|||
mIsFinal = isFinal;
|
||||
mDeprecated = deprecated;
|
||||
mScope = visibility;
|
||||
mInterfaces = new ArrayList<String>();
|
||||
mInterfaceNames = new ArrayList<String>();
|
||||
mInterfaces = new ArrayList<ClassInfo>();
|
||||
mMethods = new HashMap<String, MethodInfo>();
|
||||
mFields = new HashMap<String, FieldInfo>();
|
||||
mConstructors = new HashMap<String, ConstructorInfo>();
|
||||
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue