Loading tools/apilint/apilint.py +70 −56 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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. Loading @@ -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. Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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 Loading @@ -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": Loading @@ -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: Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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: Loading @@ -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 Loading @@ -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().""" Loading Loading @@ -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.""" Loading Loading @@ -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"): Loading Loading @@ -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.""" Loading Loading @@ -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().""" Loading Loading @@ -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 Loading @@ -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"] Loading @@ -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) Loading @@ -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: Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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 Loading @@ -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 Loading Loading @@ -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.""" Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading Loading @@ -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 Loading @@ -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.""" Loading Loading @@ -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 Loading @@ -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.""" Loading @@ -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.""" Loading Loading @@ -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.""" Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 = { Loading Loading @@ -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: Loading @@ -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": Loading @@ -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.""" Loading @@ -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""" Loading Loading @@ -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.""" Loading Loading @@ -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): Loading Loading
tools/apilint/apilint.py +70 −56 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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. Loading @@ -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. Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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 Loading @@ -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": Loading @@ -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: Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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: Loading @@ -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 Loading @@ -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().""" Loading Loading @@ -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.""" Loading Loading @@ -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"): Loading Loading @@ -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.""" Loading Loading @@ -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().""" Loading Loading @@ -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 Loading @@ -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"] Loading @@ -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) Loading @@ -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: Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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 Loading @@ -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 Loading Loading @@ -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.""" Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading @@ -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.""" Loading Loading @@ -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 Loading @@ -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.""" Loading Loading @@ -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 Loading @@ -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.""" Loading @@ -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.""" Loading Loading @@ -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.""" Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 = { Loading Loading @@ -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: Loading @@ -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": Loading @@ -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.""" Loading @@ -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""" Loading Loading @@ -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.""" Loading Loading @@ -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): Loading