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

Commit 5cdfb694 authored by Adrian Roos's avatar Adrian Roos
Browse files

ApiLint: Add Kotlin-style type support

Test: tools/apilint/apilint_sha.sh HEAD && python tools/apilint/apilint_test.py
Change-Id: Iac1fdabcbeffe57c8288d73b2359e8ce0b2bc3eb
(cherry picked from commit 7884d6b9)
parent 1f1b6a84
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
@@ -223,7 +223,7 @@ class Package():
class V2Tokenizer(object):
    __slots__ = ["raw"]

    DELIMITER = re.compile(r'\s+|[()@<>;,={}/"]|\[\]')
    DELIMITER = re.compile(r'\s+|[()@<>;,={}/"!?]|\[\]|\.\.\.')
    STRING_SPECIAL = re.compile(r'["\\]')

    def __init__(self, raw):
@@ -435,19 +435,32 @@ class V2LineParser(object):
            ret.append(self.parse_token())
        return ret

    def parse_kotlin_nullability(self):
        t = self.lookahead()
        if t == "?" or t == "!":
            return self.parse_token()
        return None

    def parse_type(self):
        type = self.parse_token()
        if type in V2LineParser.JAVA_LANG_TYPES:
            type = "java.lang." + type
        self.parse_matching_paren("<", ">")
        while self.parse_if("[]"):
            type += "[]"
        while True:
            t = self.lookahead()
            if t == "[]":
                type += self.parse_token()
            elif self.parse_kotlin_nullability() is not None:
                pass  # discard nullability for now
            else:
                break
        return type

    def parse_arg_type(self):
        type = self.parse_type()
        if self.parse_if("..."):
            type += "..."
        self.parse_kotlin_nullability() # discard nullability for now
        return type

    def parse_name(self):
@@ -466,7 +479,15 @@ class V2LineParser(object):

    def parse_arg(self):
        self.parse_annotations()
        return self.parse_arg_type()
        type = self.parse_arg_type()
        l = self.lookahead()
        if l != "," and l != ")":
            self.parse_token()  # kotlin argument name
            if self.parse_if('='): # kotlin default value
                (self.parse_matching_paren('(', ')') or
                 self.parse_matching_paren('{', '}') or
                 self.parse_token() and self.parse_matching_paren('(', ')'))
        return type

    def parse_throws(self):
        ret = []
+15 −0
Original line number Diff line number Diff line
@@ -154,6 +154,14 @@ class V2TokenizerTests(unittest.TestCase):
        self._test("class Some.Class extends SomeOther {",
                   ['class', 'Some.Class', 'extends', 'SomeOther', '{'])

    def test_varargs(self):
        self._test("name(String...)",
                   ['name', '(', 'String', '...', ')'])

    def test_kotlin(self):
        self._test("String? name(String!...)",
                   ['String', '?', 'name', '(', 'String', '!',  '...', ')'])

    def test_annotation(self):
        self._test("method @Nullable public void name();",
                   ['method', '@', 'Nullable', 'public', 'void', 'name', '(', ')', ';'])
@@ -271,5 +279,12 @@ class V2ParserTests(unittest.TestCase):
        self.assertEquals('NAME', f.name)
        self.assertEquals('( 0.0 / 0.0 )', f.value)

    def test_kotlin_types(self):
        self._field('field public List<Integer[]?[]!>?[]![]? NAME;')
        self._method("method <T?> Class<T!>?[]![][]? name(Type!, Type argname,"
                         + "Class<T?>[][]?[]!...!) throws Exception, T;")
        self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, "
                         + """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""")

if __name__ == "__main__":
    unittest.main()