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

Commit 89ebdecf authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "API Lint: Add support for base current.txt"

parents 75665084 7690d0d4
Loading
Loading
Loading
Loading
+71 −16
Original line number Diff line number Diff line
@@ -183,6 +183,11 @@ class Class():

        self.name = self.fullname[self.fullname.rindex(".")+1:]

    def merge_from(self, other):
        self.ctors.extend(other.ctors)
        self.fields.extend(other.fields)
        self.methods.extend(other.methods)

    def __hash__(self):
        return hash((self.raw, tuple(self.ctors), tuple(self.fields), tuple(self.methods)))

@@ -204,9 +209,28 @@ class Package():
        return self.raw


def _parse_stream(f, clazz_cb=None):
    line = 0
def _parse_stream(f, clazz_cb=None, base_f=None):
    api = {}

    if base_f:
        base_classes = _parse_stream_to_generator(base_f)
    else:
        base_classes = []

    for clazz in _parse_stream_to_generator(f):
        base_class = _parse_to_matching_class(base_classes, clazz)
        if base_class:
            clazz.merge_from(base_class)

        if clazz_cb:
            clazz_cb(clazz)
        else: # In callback mode, don't keep track of the full API
            api[clazz.fullname] = clazz

    return api

def _parse_stream_to_generator(f):
    line = 0
    pkg = None
    clazz = None
    blame = None
@@ -225,26 +249,41 @@ def _parse_stream(f, clazz_cb=None):
        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)
            if not clazz_cb:
                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))
        elif raw.startswith("  }") and clazz:
            while True:
                retry = yield clazz
                if not retry:
                    break
                # send() was called, asking us to redeliver clazz on next(). Still need to yield
                # a dummy value to the send() first though.
                if (yield "Returning clazz on next()"):
                        raise TypeError("send() must be followed by next(), not send()")

    # Handle last trailing class
    if clazz and clazz_cb:
        clazz_cb(clazz)

    return api
def _parse_to_matching_class(classes, needle):
    """Takes a classes generator and parses it until it returns the class we're looking for

    This relies on classes being sorted by package and class name."""

    for clazz in classes:
        if clazz.pkg.name < needle.pkg.name:
            # We haven't reached the right package yet
            continue
        if clazz.name < needle.name:
            # We haven't reached the right class yet
            continue
        if clazz.fullname == needle.fullname:
            return clazz
        # We ran past the right class. Send it back into the generator, then report failure.
        classes.send(clazz)
        return None

class Failure():
    def __init__(self, sig, clazz, detail, error, rule, msg):
@@ -1504,12 +1543,12 @@ def examine_clazz(clazz):
    verify_singleton(clazz)


def examine_stream(stream):
def examine_stream(stream, base_stream=None):
    """Find all style issues in the given API stream."""
    global failures, noticed
    failures = {}
    noticed = {}
    _parse_stream(stream, examine_clazz)
    _parse_stream(stream, examine_clazz, base_f=base_stream)
    return (failures, noticed)


@@ -1650,6 +1689,12 @@ if __name__ == "__main__":
    parser.add_argument("current.txt", type=argparse.FileType('r'), help="current.txt")
    parser.add_argument("previous.txt", nargs='?', type=argparse.FileType('r'), default=None,
            help="previous.txt")
    parser.add_argument("--base-current", nargs='?', type=argparse.FileType('r'), default=None,
            help="The base current.txt to use when examining system-current.txt or"
                 " test-current.txt")
    parser.add_argument("--base-previous", nargs='?', type=argparse.FileType('r'), default=None,
            help="The base previous.txt to use when examining system-previous.txt or"
                 " test-previous.txt")
    parser.add_argument("--no-color", action='store_const', const=True,
            help="Disable terminal colors")
    parser.add_argument("--allow-google", action='store_const', const=True,
@@ -1669,7 +1714,9 @@ if __name__ == "__main__":
        ALLOW_GOOGLE = True

    current_file = args['current.txt']
    base_current_file = args['base_current']
    previous_file = args['previous.txt']
    base_previous_file = args['base_previous']

    if args['show_deprecations_at_birth']:
        with current_file as f:
@@ -1688,9 +1735,17 @@ if __name__ == "__main__":
        sys.exit()

    with current_file as f:
        if base_current_file:
            with base_current_file as base_f:
                cur_fail, cur_noticed = examine_stream(f, base_f)
        else:
            cur_fail, cur_noticed = examine_stream(f)
    if not previous_file is None:
        with previous_file as f:
            if base_previous_file:
                with base_previous_file as base_f:
                    prev_fail, prev_noticed = examine_stream(f, base_f)
            else:
                prev_fail, prev_noticed = examine_stream(f)

        # ignore errors from previous API level