Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed6aaf0f authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

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
parent 0f5e1975
Loading
Loading
Loading
Loading
+91 −58
Original line number Diff line number Diff line
@@ -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,16 +155,16 @@ 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,}) \(<([^>]+)>.+?\) (.+?)$")

    with open(fn) as f:
    for raw in f.readlines():
        line += 1
        raw = raw.rstrip()
        match = re_blame.match(raw)
        if match is not None:
@@ -170,45 +174,73 @@ def parse_api(fn):
            blame = None

        if raw.startswith("package"):
                pkg = Package(raw, blame)
            pkg = Package(line, raw, blame)
        elif raw.startswith("  ") and raw.endswith("{"):
                clazz = Class(pkg, raw, blame)
            clazz = Class(pkg, line, raw, blame)
            api[clazz.fullname] = clazz
        elif raw.startswith("    ctor"):
                clazz.ctors.append(Method(clazz, raw, blame))
            clazz.ctors.append(Method(clazz, line, raw, blame))
        elif raw.startswith("    method"):
                clazz.methods.append(Method(clazz, raw, blame))
            clazz.methods.append(Method(clazz, line, raw, blame))
        elif raw.startswith("    field"):
                clazz.fields.append(Field(clazz, raw, blame))
            clazz.fields.append(Field(clazz, line, raw, blame))

    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, 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,11 +802,12 @@ def verify_compat(cur, prev):
    return failures


cur = parse_api(sys.argv[1])
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 = parse_api_file(sys.argv[2])
        prev_fail = verify_style(prev)

        # ignore errors from previous API level