Extend lint script to emit API statistics.
Bug: 77588754
Test: manual
Change-Id: I240dba5fae1a8635a4265a1af903517f00dec54c
(cherry picked from commit daa7cf3a365c24e3a81d0df178c188b12e6d3a91)
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 70a47cf..9db3f02 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -1334,18 +1334,25 @@
error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()")
+def is_interesting(clazz):
+ """Test if given class is interesting from an Android PoV."""
+
+ if clazz.pkg.name.startswith("java"): return False
+ if clazz.pkg.name.startswith("junit"): return False
+ if clazz.pkg.name.startswith("org.apache"): return False
+ if clazz.pkg.name.startswith("org.xml"): return False
+ if clazz.pkg.name.startswith("org.json"): return False
+ if clazz.pkg.name.startswith("org.w3c"): return False
+ if clazz.pkg.name.startswith("android.icu."): return False
+ return True
+
+
def examine_clazz(clazz):
"""Find all style issues in the given class."""
notice(clazz)
- 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
- if clazz.pkg.name.startswith("android.icu."): return
+ if not is_interesting(clazz): return
verify_constants(clazz)
verify_enums(clazz)
@@ -1479,6 +1486,7 @@
# Remove all existing things so we're left with new
for prev_clazz in prev.values():
cur_clazz = cur[prev_clazz.fullname]
+ if not is_interesting(cur_clazz): continue
sigs = { i.ident: i for i in prev_clazz.ctors }
cur_clazz.ctors = [ i for i in cur_clazz.ctors if i.ident not in sigs ]
@@ -1506,6 +1514,38 @@
print
+def show_stats(cur, prev):
+ """Show API stats."""
+
+ stats = collections.defaultdict(int)
+ for cur_clazz in cur.values():
+ if not is_interesting(cur_clazz): continue
+
+ if cur_clazz.fullname not in prev:
+ stats['new_classes'] += 1
+ stats['new_ctors'] += len(cur_clazz.ctors)
+ stats['new_methods'] += len(cur_clazz.methods)
+ stats['new_fields'] += len(cur_clazz.fields)
+ else:
+ prev_clazz = prev[cur_clazz.fullname]
+
+ sigs = { i.ident: i for i in prev_clazz.ctors }
+ ctors = len([ i for i in cur_clazz.ctors if i.ident not in sigs ])
+ sigs = { i.ident: i for i in prev_clazz.methods }
+ methods = len([ i for i in cur_clazz.methods if i.ident not in sigs ])
+ sigs = { i.ident: i for i in prev_clazz.fields }
+ fields = len([ i for i in cur_clazz.fields if i.ident not in sigs ])
+
+ if ctors + methods + fields > 0:
+ stats['extend_classes'] += 1
+ stats['extend_ctors'] += ctors
+ stats['extend_methods'] += methods
+ stats['extend_fields'] += fields
+
+ print "#", "".join([ k.ljust(20) for k in sorted(stats.keys()) ])
+ print " ", "".join([ str(stats[k]).ljust(20) for k in sorted(stats.keys()) ])
+
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Enforces common Android public API design \
patterns. It ignores lint messages from a previous API level, if provided.")
@@ -1520,6 +1560,8 @@
help="Show API changes noticed")
parser.add_argument("--show-deprecations-at-birth", action='store_const', const=True,
help="Show API deprecations at birth")
+ parser.add_argument("--show-stats", action='store_const', const=True,
+ help="Show API stats")
args = vars(parser.parse_args())
if args['no_color']:
@@ -1539,6 +1581,14 @@
show_deprecations_at_birth(cur, prev)
sys.exit()
+ if args['show_stats']:
+ with current_file as f:
+ cur = _parse_stream(f)
+ with previous_file as f:
+ prev = _parse_stream(f)
+ show_stats(cur, prev)
+ sys.exit()
+
with current_file as f:
cur_fail, cur_noticed = examine_stream(f)
if not previous_file is None:
diff --git a/tools/apilint/apilint_stats.sh b/tools/apilint/apilint_stats.sh
new file mode 100755
index 0000000..052d9a5
--- /dev/null
+++ b/tools/apilint/apilint_stats.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+API=28
+while [ $API -gt 14 ]; do
+ echo "# Changes in API $((API))"
+ python tools/apilint/apilint.py --show-stats ../../prebuilts/sdk/$((API))/public/api/android.txt ../../prebuilts/sdk/$((API-1))/public/api/android.txt
+ let API=API-1
+done