Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
75 lines
2.4 KiB
Python
75 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Diff two javap dumps produced by dump_api.py and report changes to PUBLIC API only.
|
|
|
|
usage: apidiff.py <old-dump> <new-dump> [--vector-only]
|
|
|
|
A class is reported only if its declaration starts with 'public' in the old or the new dump, so
|
|
package-private implementation classes (which javap -public still lists) do not drown the signal.
|
|
"""
|
|
import collections
|
|
import re
|
|
import sys
|
|
|
|
|
|
def parse(path):
|
|
classes = collections.OrderedDict()
|
|
decl = {}
|
|
cur = None
|
|
for line in open(path):
|
|
line = line.rstrip("\n")
|
|
if line.startswith("#####") or line.startswith("Compiled from") or not line.strip():
|
|
continue
|
|
if not line.startswith(" "):
|
|
m = re.search(r"(?:class|interface|enum|@interface|record)\s+([\w.$]+)", line)
|
|
cur = m.group(1) if m else line
|
|
classes[cur] = set()
|
|
decl[cur] = line
|
|
elif cur is not None and line.strip() != "}":
|
|
classes[cur].add(line.strip())
|
|
return classes, decl
|
|
|
|
|
|
def is_public(decl_line):
|
|
return decl_line.startswith("public ") or decl_line.startswith("protected ")
|
|
|
|
|
|
def main():
|
|
old, old_decl = parse(sys.argv[1])
|
|
new, new_decl = parse(sys.argv[2])
|
|
vector_only = "--vector-only" in sys.argv
|
|
|
|
def keep(name):
|
|
if vector_only and not name.startswith("jdk.incubator.vector."):
|
|
return False
|
|
if name.startswith("file") or "Error: Access Flags" in old_decl.get(name, "") + new_decl.get(name, ""):
|
|
return False
|
|
return is_public(old_decl.get(name, "")) or is_public(new_decl.get(name, ""))
|
|
|
|
print("## public classes removed")
|
|
for c in sorted(set(old) - set(new)):
|
|
if keep(c):
|
|
print(" " + c)
|
|
print("## public classes added")
|
|
for c in sorted(set(new) - set(old)):
|
|
if keep(c):
|
|
print(" " + c)
|
|
print("## public class changes")
|
|
for c in sorted(set(old) & set(new)):
|
|
if not keep(c):
|
|
continue
|
|
removed = old[c] - new[c]
|
|
added = new[c] - old[c]
|
|
d_old, d_new = old_decl[c], new_decl[c]
|
|
if removed or added or d_old != d_new:
|
|
print(c)
|
|
if d_old != d_new:
|
|
print(" - " + d_old.strip())
|
|
print(" + " + d_new.strip())
|
|
for x in sorted(removed):
|
|
print(" - " + x)
|
|
for x in sorted(added):
|
|
print(" + " + x)
|
|
|
|
|
|
main()
|