in tools/javac/ApiComparator.java [230:271]
public static Node compare(Api.Method a, Api.Method b) {
Node node = new Node(a, b);
if (node.diff == Diff.ADDED) {
if (b.parent.usage.inheritableByClient && b.modifiers.contains(ABSTRACT)) {
node.compatibility = Compatibility.MAJOR;
node.messages.add(Message.BREAKING_CHANGES);
} else {
// Adding a non-abstract method to a type inheritable by a client still may
// break compatibility in some cases, but we consider this risk low enough.
node.compatibility = Compatibility.MINOR;
if (b.extension == null && b.parent.usage.inheritableByBackend && b.modifiers.contains(ABSTRACT) &&
!b.modifiers.contains(STATIC) && !b.modifiers.contains(FINAL)) {
node.messages.add(Message.NON_EXTENSION_METHOD_ADDED);
}
}
} else if (node.diff == Diff.REMOVED) {
node.compatibility = Compatibility.MAJOR;
node.messages.add(Message.BREAKING_CHANGES);
} else {
// Breaking changes
node.check(!Objects.equals(a.returnType, b.returnType), "changed return type");
node.check(!Objects.equals(a.thrownTypes, b.thrownTypes), "changed thrown types");
node.check(!Arrays.equals(a.typeParameters, b.typeParameters), "changed type parameters");
if (node.diff != Diff.NONE) {
node.compatibility = Compatibility.MAJOR;
node.messages.add(Message.BREAKING_CHANGES);
return node;
}
if (compareModifiers(node, a.modifiers, b.modifiers)) return node;
// Compatible changes
node.check(a.deprecation != b.deprecation, "changed deprecation state");
node.check(!Objects.equals(a.extension, b.extension), "changed extension");
if (node.diff != Diff.NONE) {
node.compatibility = Compatibility.MINOR;
return node;
}
}
return node;
}