Switch to incremental API parsing.
Incremental API parsing works on a single class at a time, which
greatly reduces memory pressure. For example, linting a typical
current.txt would use ~100MB before; now it only uses about ~15MB!
Change-Id: Id084b3dd2f6513d0e919790d5a5d629f80637ce8
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 54525ad..8af4f50 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -155,7 +155,7 @@
return self.raw
-def parse_api(f):
+def _parse_stream(f, clazz_cb=None):
line = 0
api = {}
pkg = None
@@ -163,7 +163,7 @@
blame = None
re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
- for raw in f.readlines():
+ for raw in f:
line += 1
raw = raw.rstrip()
match = re_blame.match(raw)
@@ -176,8 +176,13 @@
if raw.startswith("package"):
pkg = Package(line, raw, blame)
elif raw.startswith(" ") and raw.endswith("{"):
+ # When provided with class callback, we treat as incremental
+ # parse and don't build up entire API
+ if clazz and clazz_cb:
+ clazz_cb(clazz)
clazz = Class(pkg, line, raw, blame)
- api[clazz.fullname] = clazz
+ if not clazz_cb:
+ api[clazz.fullname] = clazz
elif raw.startswith(" ctor"):
clazz.ctors.append(Method(clazz, line, raw, blame))
elif raw.startswith(" method"):
@@ -185,19 +190,16 @@
elif raw.startswith(" field"):
clazz.fields.append(Field(clazz, line, raw, blame))
+ # Handle last trailing class
+ if clazz and clazz_cb:
+ clazz_cb(clazz)
+
return api
-def parse_api_file(fn):
- with open(fn) as f:
- return parse_api(f)
-
-
class Failure():
def __init__(self, sig, clazz, detail, error, rule, msg):
self.sig = sig
- self.clazz = clazz
- self.detail = detail
self.error = error
self.rule = rule
self.msg = msg
@@ -644,7 +646,7 @@
warn(clazz, m, "FW6", "Method argument type violates package layering")
-def verify_boolean(clazz, api):
+def verify_boolean(clazz):
"""Verifies that boolean accessors are named correctly.
For example, hasFoo() and setHasFoo()."""
@@ -809,7 +811,7 @@
if "deprecated" in m.split: continue
overloads[m.name].append(m)
- for name, methods in overloads.iteritems():
+ for name, methods in overloads.items():
if len(methods) <= 1: continue
# Look for arguments common across all overloads
@@ -945,56 +947,65 @@
error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
-def verify_style(api):
- """Find all style issues in the given API level."""
- global failures
+def examine_clazz(clazz):
+ """Find all style issues in the given class."""
+ if clazz.pkg.name.startswith("java"): return
+ if clazz.pkg.name.startswith("junit"): return
+ if clazz.pkg.name.startswith("org.apache"): return
+ if clazz.pkg.name.startswith("org.xml"): return
+ if clazz.pkg.name.startswith("org.json"): return
+ if clazz.pkg.name.startswith("org.w3c"): return
+ verify_constants(clazz)
+ verify_enums(clazz)
+ verify_class_names(clazz)
+ verify_method_names(clazz)
+ verify_callbacks(clazz)
+ verify_listeners(clazz)
+ verify_actions(clazz)
+ verify_extras(clazz)
+ verify_equals(clazz)
+ verify_parcelable(clazz)
+ verify_protected(clazz)
+ verify_fields(clazz)
+ verify_register(clazz)
+ verify_sync(clazz)
+ verify_intent_builder(clazz)
+ verify_helper_classes(clazz)
+ verify_builder(clazz)
+ verify_aidl(clazz)
+ verify_internal(clazz)
+ verify_layering(clazz)
+ verify_boolean(clazz)
+ verify_collections(clazz)
+ verify_flags(clazz)
+ verify_exception(clazz)
+ verify_google(clazz)
+ verify_bitset(clazz)
+ verify_manager(clazz)
+ verify_boxed(clazz)
+ verify_static_utils(clazz)
+ verify_overload_args(clazz)
+ verify_callback_handlers(clazz)
+ verify_context_first(clazz)
+ verify_listener_last(clazz)
+ verify_resource_names(clazz)
+
+
+def examine_stream(stream):
+ """Find all style issues in the given API stream."""
+ global failures
+ failures = {}
+ _parse_stream(stream, examine_clazz)
+ return failures
+
+
+def examine_api(api):
+ """Find all style issues in the given parsed API."""
+ global failures
failures = {}
for key in sorted(api.keys()):
- clazz = api[key]
-
- if clazz.pkg.name.startswith("java"): continue
- if clazz.pkg.name.startswith("junit"): continue
- if clazz.pkg.name.startswith("org.apache"): continue
- if clazz.pkg.name.startswith("org.xml"): continue
- if clazz.pkg.name.startswith("org.json"): continue
- if clazz.pkg.name.startswith("org.w3c"): continue
-
- verify_constants(clazz)
- verify_enums(clazz)
- verify_class_names(clazz)
- verify_method_names(clazz)
- verify_callbacks(clazz)
- verify_listeners(clazz)
- verify_actions(clazz)
- verify_extras(clazz)
- verify_equals(clazz)
- verify_parcelable(clazz)
- verify_protected(clazz)
- verify_fields(clazz)
- verify_register(clazz)
- verify_sync(clazz)
- verify_intent_builder(clazz)
- verify_helper_classes(clazz)
- verify_builder(clazz)
- verify_aidl(clazz)
- verify_internal(clazz)
- verify_layering(clazz)
- verify_boolean(clazz, api)
- verify_collections(clazz)
- verify_flags(clazz)
- verify_exception(clazz)
- verify_google(clazz)
- verify_bitset(clazz)
- verify_manager(clazz)
- verify_boxed(clazz)
- verify_static_utils(clazz)
- verify_overload_args(clazz)
- verify_callback_handlers(clazz)
- verify_context_first(clazz)
- verify_listener_last(clazz)
- verify_resource_names(clazz)
-
+ examine_clazz(api[key])
return failures
@@ -1054,18 +1065,20 @@
if __name__ == "__main__":
- cur = parse_api_file(sys.argv[1])
- cur_fail = verify_style(cur)
+ with open(sys.argv[1]) as f:
+ cur_fail = examine_stream(f)
if len(sys.argv) > 2:
- prev = parse_api_file(sys.argv[2])
- prev_fail = verify_style(prev)
+ with open(sys.argv[2]) as f:
+ prev_fail = examine_stream(f)
# ignore errors from previous API level
for p in prev_fail:
if p in cur_fail:
del cur_fail[p]
+ """
+ # NOTE: disabled because of memory pressure
# look for compatibility issues
compat_fail = verify_compat(cur, prev)
@@ -1073,7 +1086,7 @@
for f in sorted(compat_fail):
print compat_fail[f]
print
-
+ """
print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
for f in sorted(cur_fail):