From ed6aaf0f79b7b39b2d70684c902d2d689a3db841 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 30 Jan 2015 13:31:45 -0700 Subject: Track line numbers in lint script. Also create separate class to describe failures, which can be consumed by other tools. Still offers to render itself for console output by default. Change-Id: Ib0555cc289ae08a0e446489509cc964c866c564e --- tools/apilint/apilint.py | 149 +++++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 58 deletions(-) diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 393d2ec..1330c28 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -48,8 +48,9 @@ def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False): class Field(): - def __init__(self, clazz, raw, blame): + def __init__(self, clazz, line, raw, blame): self.clazz = clazz + self.line = line self.raw = raw.strip(" {;") self.blame = blame @@ -73,8 +74,9 @@ class Field(): class Method(): - def __init__(self, clazz, raw, blame): + def __init__(self, clazz, line, raw, blame): self.clazz = clazz + self.line = line self.raw = raw.strip(" {;") self.blame = blame @@ -110,8 +112,9 @@ class Method(): class Class(): - def __init__(self, pkg, raw, blame): + def __init__(self, pkg, line, raw, blame): self.pkg = pkg + self.line = line self.raw = raw.strip(" {;") self.blame = blame self.ctors = [] @@ -140,7 +143,8 @@ class Class(): class Package(): - def __init__(self, raw, blame): + def __init__(self, line, raw, blame): + self.line = line self.raw = raw.strip(" {;") self.blame = blame @@ -151,64 +155,92 @@ class Package(): return self.raw -def parse_api(fn): +def parse_api(f): + line = 0 api = {} pkg = None clazz = None blame = None re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$") + for raw in f.readlines(): + line += 1 + raw = raw.rstrip() + match = re_blame.match(raw) + if match is not None: + blame = match.groups()[0:2] + raw = match.groups()[2] + else: + blame = None + + if raw.startswith("package"): + pkg = Package(line, raw, blame) + elif raw.startswith(" ") and raw.endswith("{"): + clazz = Class(pkg, line, raw, blame) + api[clazz.fullname] = clazz + elif raw.startswith(" ctor"): + clazz.ctors.append(Method(clazz, line, raw, blame)) + elif raw.startswith(" method"): + clazz.methods.append(Method(clazz, line, raw, blame)) + elif raw.startswith(" field"): + clazz.fields.append(Field(clazz, line, raw, blame)) + + return api + +def parse_api_file(fn): with open(fn) as f: - for raw in f.readlines(): - raw = raw.rstrip() - match = re_blame.match(raw) - if match is not None: - blame = match.groups()[0:2] - raw = match.groups()[2] - else: - blame = None - - if raw.startswith("package"): - pkg = Package(raw, blame) - elif raw.startswith(" ") and raw.endswith("{"): - clazz = Class(pkg, raw, blame) - api[clazz.fullname] = clazz - elif raw.startswith(" ctor"): - clazz.ctors.append(Method(clazz, raw, blame)) - elif raw.startswith(" method"): - clazz.methods.append(Method(clazz, raw, blame)) - elif raw.startswith(" field"): - clazz.fields.append(Field(clazz, raw, blame)) + return parse_api(f) - return api + +class Failure(): + def __init__(self, sig, clazz, detail, error, msg): + self.sig = sig + self.clazz = clazz + self.detail = detail + self.error = error + self.msg = msg + + if error: + dump = "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg) + else: + dump = "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg) + + self.line = clazz.line + blame = clazz.blame + if detail is not None: + dump += "\n in " + repr(detail) + self.line = detail.line + blame = detail.blame + dump += "\n in " + repr(clazz) + dump += "\n in " + repr(clazz.pkg) + dump += "\n at line " + repr(self.line) + if blame is not None: + dump += "\n last modified by %s in %s" % (blame[1], blame[0]) + + self.dump = dump + + def __repr__(self): + return self.dump failures = {} -def _fail(clazz, detail, msg): +def _fail(clazz, detail, error, msg): """Records an API failure to be processed later.""" global failures sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg) sig = sig.replace(" deprecated ", " ") - res = msg - blame = clazz.blame - if detail is not None: - res += "\n in " + repr(detail) - blame = detail.blame - res += "\n in " + repr(clazz) - res += "\n in " + repr(clazz.pkg) - if blame is not None: - res += "\n last modified by %s in %s" % (blame[1], blame[0]) - failures[sig] = res + failures[sig] = Failure(sig, clazz, detail, error, msg) + def warn(clazz, detail, msg): - _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg)) + _fail(clazz, detail, False, msg) def error(clazz, detail, msg): - _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg)) + _fail(clazz, detail, True, msg) def verify_constants(clazz): @@ -770,28 +802,29 @@ def verify_compat(cur, prev): return failures -cur = parse_api(sys.argv[1]) -cur_fail = verify_style(cur) +if __name__ == "__main__": + cur = parse_api_file(sys.argv[1]) + cur_fail = verify_style(cur) -if len(sys.argv) > 2: - prev = parse_api(sys.argv[2]) - prev_fail = verify_style(prev) + if len(sys.argv) > 2: + prev = parse_api_file(sys.argv[2]) + prev_fail = verify_style(prev) - # ignore errors from previous API level - for p in prev_fail: - if p in cur_fail: - del cur_fail[p] + # ignore errors from previous API level + for p in prev_fail: + if p in cur_fail: + del cur_fail[p] - # look for compatibility issues - compat_fail = verify_compat(cur, prev) + # look for compatibility issues + compat_fail = verify_compat(cur, prev) - print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True))) - for f in sorted(compat_fail): - print compat_fail[f] - print + print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True))) + 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): - print cur_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): + print cur_fail[f] + print -- cgit v1.1