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

Commit 5eae9a40 authored by Adrian Roos's avatar Adrian Roos Committed by android-build-merger
Browse files

Merge "apilint: decorator-based verifier registration" am: 6e16eb10

am: b3662ec2

Change-Id: I0463569c258ecf63c61c4eefacb257d5219df3d5
parents 4895861d b3662ec2
Loading
Loading
Loading
Loading
+70 −56
Original line number Original line Diff line number Diff line
@@ -763,6 +763,14 @@ def notice(clazz):
    noticed[clazz.fullname] = hash(clazz)
    noticed[clazz.fullname] = hash(clazz)




verifiers = {}

def verifier(f):
    verifiers[f.__name__] = f
    return f


@verifier
def verify_constants(clazz):
def verify_constants(clazz):
    """All static final constants must be FOO_NAME style."""
    """All static final constants must be FOO_NAME style."""
    if re.match("android\.R\.[a-z]+", clazz.fullname): return
    if re.match("android\.R\.[a-z]+", clazz.fullname): return
@@ -780,13 +788,13 @@ def verify_constants(clazz):
            if f.typ in req and f.value is None:
            if f.typ in req and f.value is None:
                error(clazz, f, None, "All constants must be defined at compile time")
                error(clazz, f, None, "All constants must be defined at compile time")



@verifier
def verify_enums(clazz):
def verify_enums(clazz):
    """Enums are bad, mmkay?"""
    """Enums are bad, mmkay?"""
    if clazz.extends == "java.lang.Enum" or "enum" in clazz.split:
    if clazz.extends == "java.lang.Enum" or "enum" in clazz.split:
        error(clazz, None, "F5", "Enums are not allowed")
        error(clazz, None, "F5", "Enums are not allowed")



@verifier
def verify_class_names(clazz):
def verify_class_names(clazz):
    """Try catching malformed class names like myMtp or MTPUser."""
    """Try catching malformed class names like myMtp or MTPUser."""
    if clazz.fullname.startswith("android.opengl"): return
    if clazz.fullname.startswith("android.opengl"): return
@@ -801,6 +809,7 @@ def verify_class_names(clazz):
        error(clazz, None, None, "Don't expose your implementation details")
        error(clazz, None, None, "Don't expose your implementation details")




@verifier
def verify_method_names(clazz):
def verify_method_names(clazz):
    """Try catching malformed method names, like Foo() or getMTU()."""
    """Try catching malformed method names, like Foo() or getMTU()."""
    if clazz.fullname.startswith("android.opengl"): return
    if clazz.fullname.startswith("android.opengl"): return
@@ -814,6 +823,7 @@ def verify_method_names(clazz):
            error(clazz, m, "S1", "Method name must start with lowercase char")
            error(clazz, m, "S1", "Method name must start with lowercase char")




@verifier
def verify_callbacks(clazz):
def verify_callbacks(clazz):
    """Verify Callback classes.
    """Verify Callback classes.
    All callback classes must be abstract.
    All callback classes must be abstract.
@@ -834,6 +844,7 @@ def verify_callbacks(clazz):
                error(clazz, m, "L1", "Callback method names must be onFoo() style")
                error(clazz, m, "L1", "Callback method names must be onFoo() style")




@verifier
def verify_listeners(clazz):
def verify_listeners(clazz):
    """Verify Listener classes.
    """Verify Listener classes.
    All Listener classes must be interface.
    All Listener classes must be interface.
@@ -855,6 +866,7 @@ def verify_listeners(clazz):
                error(clazz, m, "L1", "Single listener method name must match class name")
                error(clazz, m, "L1", "Single listener method name must match class name")




@verifier
def verify_actions(clazz):
def verify_actions(clazz):
    """Verify intent actions.
    """Verify intent actions.
    All action names must be named ACTION_FOO.
    All action names must be named ACTION_FOO.
@@ -886,6 +898,7 @@ def verify_actions(clazz):
                        error(clazz, f, "C4", "Inconsistent action value; expected '%s'" % (expected))
                        error(clazz, f, "C4", "Inconsistent action value; expected '%s'" % (expected))




@verifier
def verify_extras(clazz):
def verify_extras(clazz):
    """Verify intent extras.
    """Verify intent extras.
    All extra names must be named EXTRA_FOO.
    All extra names must be named EXTRA_FOO.
@@ -916,6 +929,7 @@ def verify_extras(clazz):
                        error(clazz, f, "C4", "Inconsistent extra value; expected '%s'" % (expected))
                        error(clazz, f, "C4", "Inconsistent extra value; expected '%s'" % (expected))




@verifier
def verify_equals(clazz):
def verify_equals(clazz):
    """Verify that equals() and hashCode() must be overridden together."""
    """Verify that equals() and hashCode() must be overridden together."""
    eq = False
    eq = False
@@ -928,6 +942,7 @@ def verify_equals(clazz):
        error(clazz, None, "M8", "Must override both equals and hashCode; missing one")
        error(clazz, None, "M8", "Must override both equals and hashCode; missing one")




@verifier
def verify_parcelable(clazz):
def verify_parcelable(clazz):
    """Verify that Parcelable objects aren't hiding required bits."""
    """Verify that Parcelable objects aren't hiding required bits."""
    if clazz.implements == "android.os.Parcelable":
    if clazz.implements == "android.os.Parcelable":
@@ -946,6 +961,7 @@ def verify_parcelable(clazz):
                error(clazz, c, "FW3", "Parcelable inflation is exposed through CREATOR, not raw constructors")
                error(clazz, c, "FW3", "Parcelable inflation is exposed through CREATOR, not raw constructors")




@verifier
def verify_protected(clazz):
def verify_protected(clazz):
    """Verify that no protected methods or fields are allowed."""
    """Verify that no protected methods or fields are allowed."""
    for m in clazz.methods:
    for m in clazz.methods:
@@ -957,6 +973,7 @@ def verify_protected(clazz):
            error(clazz, f, "M7", "Protected fields not allowed; must be public")
            error(clazz, f, "M7", "Protected fields not allowed; must be public")




@verifier
def verify_fields(clazz):
def verify_fields(clazz):
    """Verify that all exposed fields are final.
    """Verify that all exposed fields are final.
    Exposed fields must follow myName style.
    Exposed fields must follow myName style.
@@ -1002,6 +1019,7 @@ def verify_fields(clazz):
                error(clazz, f, "C2", "Constants must be marked static final")
                error(clazz, f, "C2", "Constants must be marked static final")




@verifier
def verify_register(clazz):
def verify_register(clazz):
    """Verify parity of registration methods.
    """Verify parity of registration methods.
    Callback objects use register/unregister methods.
    Callback objects use register/unregister methods.
@@ -1035,6 +1053,7 @@ def verify_register(clazz):
                error(clazz, m, "L3", "Listener methods should be named add/remove")
                error(clazz, m, "L3", "Listener methods should be named add/remove")




@verifier
def verify_sync(clazz):
def verify_sync(clazz):
    """Verify synchronized methods aren't exposed."""
    """Verify synchronized methods aren't exposed."""
    for m in clazz.methods:
    for m in clazz.methods:
@@ -1042,6 +1061,7 @@ def verify_sync(clazz):
            error(clazz, m, "M5", "Internal locks must not be exposed")
            error(clazz, m, "M5", "Internal locks must not be exposed")




@verifier
def verify_intent_builder(clazz):
def verify_intent_builder(clazz):
    """Verify that Intent builders are createFooIntent() style."""
    """Verify that Intent builders are createFooIntent() style."""
    if clazz.name == "Intent": return
    if clazz.name == "Intent": return
@@ -1054,6 +1074,7 @@ def verify_intent_builder(clazz):
                warn(clazz, m, "FW1", "Methods creating an Intent should be named createFooIntent()")
                warn(clazz, m, "FW1", "Methods creating an Intent should be named createFooIntent()")




@verifier
def verify_helper_classes(clazz):
def verify_helper_classes(clazz):
    """Verify that helper classes are named consistently with what they extend.
    """Verify that helper classes are named consistently with what they extend.
    All developer extendable methods should be named onFoo()."""
    All developer extendable methods should be named onFoo()."""
@@ -1102,6 +1123,7 @@ def verify_helper_classes(clazz):
                    warn(clazz, m, None, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
                    warn(clazz, m, None, "If implemented by developer, should be named onFoo(); otherwise consider marking final")




@verifier
def verify_builder(clazz):
def verify_builder(clazz):
    """Verify builder classes.
    """Verify builder classes.
    Methods should return the builder to enable chaining."""
    Methods should return the builder to enable chaining."""
@@ -1134,12 +1156,14 @@ def verify_builder(clazz):
        error(clazz, None, None, "Builder should be final")
        error(clazz, None, None, "Builder should be final")




@verifier
def verify_aidl(clazz):
def verify_aidl(clazz):
    """Catch people exposing raw AIDL."""
    """Catch people exposing raw AIDL."""
    if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface":
    if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface":
        error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
        error(clazz, None, None, "Raw AIDL interfaces must not be exposed")




@verifier
def verify_internal(clazz):
def verify_internal(clazz):
    """Catch people exposing internal classes."""
    """Catch people exposing internal classes."""
    if clazz.pkg.name.startswith("com.android"):
    if clazz.pkg.name.startswith("com.android"):
@@ -1174,6 +1198,7 @@ LAYERING_PACKAGE_RANKING = layering_build_ranking([
    "android.util"
    "android.util"
])
])


@verifier
def verify_layering(clazz):
def verify_layering(clazz):
    """Catch package layering violations.
    """Catch package layering violations.
    For example, something in android.os depending on android.app."""
    For example, something in android.os depending on android.app."""
@@ -1208,6 +1233,7 @@ def verify_layering(clazz):
                warn(clazz, m, "FW6", "Method argument type violates package layering")
                warn(clazz, m, "FW6", "Method argument type violates package layering")




@verifier
def verify_boolean(clazz):
def verify_boolean(clazz):
    """Verifies that boolean accessors are named correctly.
    """Verifies that boolean accessors are named correctly.
    For example, hasFoo() and setHasFoo()."""
    For example, hasFoo() and setHasFoo()."""
@@ -1248,6 +1274,7 @@ def verify_boolean(clazz):
                error_if_exists(sets, m.name, expected, "has" + target)
                error_if_exists(sets, m.name, expected, "has" + target)




@verifier
def verify_collections(clazz):
def verify_collections(clazz):
    """Verifies that collection types are interfaces."""
    """Verifies that collection types are interfaces."""
    if clazz.fullname == "android.os.Bundle": return
    if clazz.fullname == "android.os.Bundle": return
@@ -1262,6 +1289,8 @@ def verify_collections(clazz):
            if arg in bad:
            if arg in bad:
                error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")
                error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")



@verifier
def verify_uris(clazz):
def verify_uris(clazz):
    bad = ["java.net.URL", "java.net.URI", "android.net.URL"]
    bad = ["java.net.URL", "java.net.URI", "android.net.URL"]


@@ -1276,6 +1305,8 @@ def verify_uris(clazz):
            if arg in bad:
            if arg in bad:
                error(clazz, m, None, "Argument must take android.net.Uri instead of " + arg)
                error(clazz, m, None, "Argument must take android.net.Uri instead of " + arg)



@verifier
def verify_flags(clazz):
def verify_flags(clazz):
    """Verifies that flags are non-overlapping."""
    """Verifies that flags are non-overlapping."""
    known = collections.defaultdict(int)
    known = collections.defaultdict(int)
@@ -1292,6 +1323,7 @@ def verify_flags(clazz):
            known[scope] |= val
            known[scope] |= val




@verifier
def verify_exception(clazz):
def verify_exception(clazz):
    """Verifies that methods don't throw generic exceptions."""
    """Verifies that methods don't throw generic exceptions."""
    for m in clazz.methods:
    for m in clazz.methods:
@@ -1309,8 +1341,10 @@ def verify_exception(clazz):
            if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]:
            if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]:
                warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException")
                warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException")



GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE)
GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE)


# Not marked as @verifier, because it is only conditionally applied.
def verify_google(clazz):
def verify_google(clazz):
    """Verifies that APIs never reference Google."""
    """Verifies that APIs never reference Google."""


@@ -1323,6 +1357,7 @@ def verify_google(clazz):
                error(clazz, t, None, "Must never reference Google")
                error(clazz, t, None, "Must never reference Google")




@verifier
def verify_bitset(clazz):
def verify_bitset(clazz):
    """Verifies that we avoid using heavy BitSet."""
    """Verifies that we avoid using heavy BitSet."""


@@ -1338,6 +1373,7 @@ def verify_bitset(clazz):
                error(clazz, m, None, "Argument type must not be heavy BitSet")
                error(clazz, m, None, "Argument type must not be heavy BitSet")




@verifier
def verify_manager(clazz):
def verify_manager(clazz):
    """Verifies that FooManager is only obtained from Context."""
    """Verifies that FooManager is only obtained from Context."""


@@ -1351,6 +1387,7 @@ def verify_manager(clazz):
            error(clazz, m, None, "Managers must always be obtained from Context")
            error(clazz, m, None, "Managers must always be obtained from Context")




@verifier
def verify_boxed(clazz):
def verify_boxed(clazz):
    """Verifies that methods avoid boxed primitives."""
    """Verifies that methods avoid boxed primitives."""


@@ -1373,6 +1410,7 @@ def verify_boxed(clazz):
                error(clazz, m, "M11", "Must avoid boxed primitives")
                error(clazz, m, "M11", "Must avoid boxed primitives")




@verifier
def verify_static_utils(clazz):
def verify_static_utils(clazz):
    """Verifies that helper classes can't be constructed."""
    """Verifies that helper classes can't be constructed."""
    if clazz.fullname.startswith("android.opengl"): return
    if clazz.fullname.startswith("android.opengl"): return
@@ -1392,6 +1430,7 @@ def verify_static_utils(clazz):
        error(clazz, None, None, "Fully-static utility classes must not have constructor")
        error(clazz, None, None, "Fully-static utility classes must not have constructor")




# @verifier  # Disabled for now
def verify_overload_args(clazz):
def verify_overload_args(clazz):
    """Verifies that method overloads add new arguments at the end."""
    """Verifies that method overloads add new arguments at the end."""
    if clazz.fullname.startswith("android.opengl"): return
    if clazz.fullname.startswith("android.opengl"): return
@@ -1432,6 +1471,7 @@ def verify_overload_args(clazz):
                error(clazz, m, "M2", "Expected consistent argument ordering between overloads: %s..." % (", ".join(locked_sig)))
                error(clazz, m, "M2", "Expected consistent argument ordering between overloads: %s..." % (", ".join(locked_sig)))




@verifier
def verify_callback_handlers(clazz):
def verify_callback_handlers(clazz):
    """Verifies that methods adding listener/callback have overload
    """Verifies that methods adding listener/callback have overload
    for specifying delivery thread."""
    for specifying delivery thread."""
@@ -1483,6 +1523,7 @@ def verify_callback_handlers(clazz):
            warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Executor")
            warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Executor")




@verifier
def verify_context_first(clazz):
def verify_context_first(clazz):
    """Verifies that methods accepting a Context keep it the first argument."""
    """Verifies that methods accepting a Context keep it the first argument."""
    examine = clazz.ctors + clazz.methods
    examine = clazz.ctors + clazz.methods
@@ -1495,6 +1536,7 @@ def verify_context_first(clazz):
                error(clazz, m, "M3", "ContentResolver is distinct, so it must be the first argument")
                error(clazz, m, "M3", "ContentResolver is distinct, so it must be the first argument")




@verifier
def verify_listener_last(clazz):
def verify_listener_last(clazz):
    """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
    """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
    examine = clazz.ctors + clazz.methods
    examine = clazz.ctors + clazz.methods
@@ -1508,6 +1550,7 @@ def verify_listener_last(clazz):
                warn(clazz, m, "M3", "Listeners should always be at end of argument list")
                warn(clazz, m, "M3", "Listeners should always be at end of argument list")




@verifier
def verify_resource_names(clazz):
def verify_resource_names(clazz):
    """Verifies that resource names have consistent case."""
    """Verifies that resource names have consistent case."""
    if not re.match("android\.R\.[a-z]+", clazz.fullname): return
    if not re.match("android\.R\.[a-z]+", clazz.fullname): return
@@ -1539,6 +1582,7 @@ def verify_resource_names(clazz):
            error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
            error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")




@verifier
def verify_files(clazz):
def verify_files(clazz):
    """Verifies that methods accepting File also accept streams."""
    """Verifies that methods accepting File also accept streams."""


@@ -1560,6 +1604,7 @@ def verify_files(clazz):
            warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")
            warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")




@verifier
def verify_manager_list(clazz):
def verify_manager_list(clazz):
    """Verifies that managers return List<? extends Parcelable> instead of arrays."""
    """Verifies that managers return List<? extends Parcelable> instead of arrays."""


@@ -1570,6 +1615,7 @@ def verify_manager_list(clazz):
            warn(clazz, m, None, "Methods should return List<? extends Parcelable> instead of Parcelable[] to support ParceledListSlice under the hood")
            warn(clazz, m, None, "Methods should return List<? extends Parcelable> instead of Parcelable[] to support ParceledListSlice under the hood")




@verifier
def verify_abstract_inner(clazz):
def verify_abstract_inner(clazz):
    """Verifies that abstract inner classes are static."""
    """Verifies that abstract inner classes are static."""


@@ -1578,6 +1624,7 @@ def verify_abstract_inner(clazz):
            warn(clazz, None, None, "Abstract inner classes should be static to improve testability")
            warn(clazz, None, None, "Abstract inner classes should be static to improve testability")




@verifier
def verify_runtime_exceptions(clazz):
def verify_runtime_exceptions(clazz):
    """Verifies that runtime exceptions aren't listed in throws."""
    """Verifies that runtime exceptions aren't listed in throws."""


@@ -1622,6 +1669,7 @@ def verify_runtime_exceptions(clazz):
                error(clazz, m, None, "Methods must not mention RuntimeException subclasses in throws clauses")
                error(clazz, m, None, "Methods must not mention RuntimeException subclasses in throws clauses")




@verifier
def verify_error(clazz):
def verify_error(clazz):
    """Verifies that we always use Exception instead of Error."""
    """Verifies that we always use Exception instead of Error."""
    if not clazz.extends: return
    if not clazz.extends: return
@@ -1631,6 +1679,7 @@ def verify_error(clazz):
        error(clazz, None, None, "Exceptions must be named FooException")
        error(clazz, None, None, "Exceptions must be named FooException")




@verifier
def verify_units(clazz):
def verify_units(clazz):
    """Verifies that we use consistent naming for units."""
    """Verifies that we use consistent naming for units."""


@@ -1667,6 +1716,7 @@ def verify_units(clazz):
            error(clazz, m, None, "Percentage must use ints")
            error(clazz, m, None, "Percentage must use ints")




@verifier
def verify_closable(clazz):
def verify_closable(clazz):
    """Verifies that classes are AutoClosable."""
    """Verifies that classes are AutoClosable."""
    if "java.lang.AutoCloseable" in clazz.implements_all: return
    if "java.lang.AutoCloseable" in clazz.implements_all: return
@@ -1679,6 +1729,7 @@ def verify_closable(clazz):
            return
            return




@verifier
def verify_member_name_not_kotlin_keyword(clazz):
def verify_member_name_not_kotlin_keyword(clazz):
    """Prevent method names which are keywords in Kotlin."""
    """Prevent method names which are keywords in Kotlin."""


@@ -1704,6 +1755,7 @@ def verify_member_name_not_kotlin_keyword(clazz):
            error(clazz, f, None, "Field name must not be a Kotlin keyword")
            error(clazz, f, None, "Field name must not be a Kotlin keyword")




@verifier
def verify_method_name_not_kotlin_operator(clazz):
def verify_method_name_not_kotlin_operator(clazz):
    """Warn about method names which become operators in Kotlin."""
    """Warn about method names which become operators in Kotlin."""


@@ -1753,6 +1805,7 @@ def verify_method_name_not_kotlin_operator(clazz):
            unique_binary_op(m, m.name[:-6])  # Remove 'Assign' suffix
            unique_binary_op(m, m.name[:-6])  # Remove 'Assign' suffix




@verifier
def verify_collections_over_arrays(clazz):
def verify_collections_over_arrays(clazz):
    """Warn that [] should be Collections."""
    """Warn that [] should be Collections."""


@@ -1768,6 +1821,7 @@ def verify_collections_over_arrays(clazz):
                warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array")
                warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array")




@verifier
def verify_user_handle(clazz):
def verify_user_handle(clazz):
    """Methods taking UserHandle should be ForUser or AsUser."""
    """Methods taking UserHandle should be ForUser or AsUser."""
    if clazz.name.endswith("Listener") or clazz.name.endswith("Callback") or clazz.name.endswith("Callbacks"): return
    if clazz.name.endswith("Listener") or clazz.name.endswith("Callback") or clazz.name.endswith("Callbacks"): return
@@ -1792,6 +1846,7 @@ def verify_user_handle(clazz):
                 "or 'queryFooForUser'")
                 "or 'queryFooForUser'")




@verifier
def verify_params(clazz):
def verify_params(clazz):
    """Parameter classes should be 'Params'."""
    """Parameter classes should be 'Params'."""
    if clazz.name.endswith("Params"): return
    if clazz.name.endswith("Params"): return
@@ -1807,6 +1862,7 @@ def verify_params(clazz):
            error(clazz, None, None, "Classes holding a set of parameters should be called 'FooParams'")
            error(clazz, None, None, "Classes holding a set of parameters should be called 'FooParams'")




@verifier
def verify_services(clazz):
def verify_services(clazz):
    """Service name should be FOO_BAR_SERVICE = 'foo_bar'."""
    """Service name should be FOO_BAR_SERVICE = 'foo_bar'."""
    if clazz.fullname != "android.content.Context": return
    if clazz.fullname != "android.content.Context": return
@@ -1820,6 +1876,7 @@ def verify_services(clazz):
                error(clazz, f, "C4", "Inconsistent service value; expected '%s'" % (expected))
                error(clazz, f, "C4", "Inconsistent service value; expected '%s'" % (expected))




@verifier
def verify_tense(clazz):
def verify_tense(clazz):
    """Verify tenses of method names."""
    """Verify tenses of method names."""
    if clazz.fullname.startswith("android.opengl"): return
    if clazz.fullname.startswith("android.opengl"): return
@@ -1829,6 +1886,7 @@ def verify_tense(clazz):
            warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'")
            warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'")




@verifier
def verify_icu(clazz):
def verify_icu(clazz):
    """Verifies that richer ICU replacements are used."""
    """Verifies that richer ICU replacements are used."""
    better = {
    better = {
@@ -1860,6 +1918,7 @@ def verify_icu(clazz):
                warn(clazz, m, None, "Type %s should be replaced with richer ICU type %s" % (arg, better[arg]))
                warn(clazz, m, None, "Type %s should be replaced with richer ICU type %s" % (arg, better[arg]))




@verifier
def verify_clone(clazz):
def verify_clone(clazz):
    """Verify that clone() isn't implemented; see EJ page 61."""
    """Verify that clone() isn't implemented; see EJ page 61."""
    for m in clazz.methods:
    for m in clazz.methods:
@@ -1867,6 +1926,7 @@ def verify_clone(clazz):
            error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()")
            error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()")




@verifier
def verify_pfd(clazz):
def verify_pfd(clazz):
    """Verify that android APIs use PFD over FD."""
    """Verify that android APIs use PFD over FD."""
    if clazz.fullname == "android.os.FileUtils" or clazz.fullname == "android.system.Os":
    if clazz.fullname == "android.os.FileUtils" or clazz.fullname == "android.system.Os":
@@ -1888,6 +1948,7 @@ def verify_pfd(clazz):
            error(clazz, f, "FW11", "Must use ParcelFileDescriptor")
            error(clazz, f, "FW11", "Must use ParcelFileDescriptor")




@verifier
def verify_numbers(clazz):
def verify_numbers(clazz):
    """Discourage small numbers types like short and byte."""
    """Discourage small numbers types like short and byte."""


@@ -1909,8 +1970,10 @@ def verify_numbers(clazz):
            if arg in discouraged:
            if arg in discouraged:
                warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead")
                warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead")



PRIMITIVES = {"void", "int", "float", "boolean", "short", "char", "byte", "long", "double"}
PRIMITIVES = {"void", "int", "float", "boolean", "short", "char", "byte", "long", "double"}


@verifier
def verify_nullability(clazz):
def verify_nullability(clazz):
    """Catches missing nullability annotations"""
    """Catches missing nullability annotations"""


@@ -1939,6 +2002,8 @@ def verify_nullability_args(clazz, m):
def has_nullability(annotations):
def has_nullability(annotations):
    return "@NonNull" in annotations or "@Nullable" in annotations
    return "@NonNull" in annotations or "@Nullable" in annotations



@verifier
def verify_singleton(clazz):
def verify_singleton(clazz):
    """Catch singleton objects with constructors."""
    """Catch singleton objects with constructors."""


@@ -1973,61 +2038,10 @@ def examine_clazz(clazz):


    if not is_interesting(clazz): return
    if not is_interesting(clazz): return


    verify_constants(clazz)
    for v in verifiers.itervalues():
    verify_enums(clazz)
        v(clazz)
    verify_class_names(clazz)

    verify_method_names(clazz)
    verify_callbacks(clazz)
    verify_listeners(clazz)
    verify_actions(clazz)
    verify_extras(clazz)
    verify_equals(clazz)
    verify_parcelable(clazz)
    verify_protected(clazz)
    verify_fields(clazz)
    verify_register(clazz)
    verify_sync(clazz)
    verify_intent_builder(clazz)
    verify_helper_classes(clazz)
    verify_builder(clazz)
    verify_aidl(clazz)
    verify_internal(clazz)
    verify_layering(clazz)
    verify_boolean(clazz)
    verify_collections(clazz)
    verify_uris(clazz)
    verify_flags(clazz)
    verify_exception(clazz)
    if not ALLOW_GOOGLE: verify_google(clazz)
    if not ALLOW_GOOGLE: verify_google(clazz)
    verify_bitset(clazz)
    verify_manager(clazz)
    verify_boxed(clazz)
    verify_static_utils(clazz)
    # verify_overload_args(clazz)
    verify_callback_handlers(clazz)
    verify_context_first(clazz)
    verify_listener_last(clazz)
    verify_resource_names(clazz)
    verify_files(clazz)
    verify_manager_list(clazz)
    verify_abstract_inner(clazz)
    verify_runtime_exceptions(clazz)
    verify_error(clazz)
    verify_units(clazz)
    verify_closable(clazz)
    verify_member_name_not_kotlin_keyword(clazz)
    verify_method_name_not_kotlin_operator(clazz)
    verify_collections_over_arrays(clazz)
    verify_user_handle(clazz)
    verify_params(clazz)
    verify_services(clazz)
    verify_tense(clazz)
    verify_icu(clazz)
    verify_clone(clazz)
    verify_pfd(clazz)
    verify_numbers(clazz)
    verify_singleton(clazz)
    verify_nullability(clazz)




def examine_stream(stream, base_stream=None, in_classes_with_base=[], out_classes_with_base=None):
def examine_stream(stream, base_stream=None, in_classes_with_base=[], out_classes_with_base=None):