Loading tools/apilint/apilint.py +70 −56 Original line number Diff line number Diff line Loading @@ -763,6 +763,14 @@ def notice(clazz): noticed[clazz.fullname] = hash(clazz) verifiers = {} def verifier(f): verifiers[f.__name__] = f return f @verifier def verify_constants(clazz): """All static final constants must be FOO_NAME style.""" 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: error(clazz, f, None, "All constants must be defined at compile time") @verifier def verify_enums(clazz): """Enums are bad, mmkay?""" if clazz.extends == "java.lang.Enum" or "enum" in clazz.split: error(clazz, None, "F5", "Enums are not allowed") @verifier def verify_class_names(clazz): """Try catching malformed class names like myMtp or MTPUser.""" 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") @verifier def verify_method_names(clazz): """Try catching malformed method names, like Foo() or getMTU().""" 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") @verifier def verify_callbacks(clazz): """Verify Callback classes. 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") @verifier def verify_listeners(clazz): """Verify Listener classes. 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") @verifier def verify_actions(clazz): """Verify intent actions. 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)) @verifier def verify_extras(clazz): """Verify intent extras. 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)) @verifier def verify_equals(clazz): """Verify that equals() and hashCode() must be overridden together.""" eq = False Loading @@ -928,6 +942,7 @@ def verify_equals(clazz): error(clazz, None, "M8", "Must override both equals and hashCode; missing one") @verifier def verify_parcelable(clazz): """Verify that Parcelable objects aren't hiding required bits.""" 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") @verifier def verify_protected(clazz): """Verify that no protected methods or fields are allowed.""" 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") @verifier def verify_fields(clazz): """Verify that all exposed fields are final. 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") @verifier def verify_register(clazz): """Verify parity of registration 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") @verifier def verify_sync(clazz): """Verify synchronized methods aren't exposed.""" for m in clazz.methods: Loading @@ -1042,6 +1061,7 @@ def verify_sync(clazz): error(clazz, m, "M5", "Internal locks must not be exposed") @verifier def verify_intent_builder(clazz): """Verify that Intent builders are createFooIntent() style.""" 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()") @verifier def verify_helper_classes(clazz): """Verify that helper classes are named consistently with what they extend. 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") @verifier def verify_builder(clazz): """Verify builder classes. 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") @verifier def verify_aidl(clazz): """Catch people exposing raw AIDL.""" if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface": error(clazz, None, None, "Raw AIDL interfaces must not be exposed") @verifier def verify_internal(clazz): """Catch people exposing internal classes.""" if clazz.pkg.name.startswith("com.android"): Loading Loading @@ -1174,6 +1198,7 @@ LAYERING_PACKAGE_RANKING = layering_build_ranking([ "android.util" ]) @verifier def verify_layering(clazz): """Catch package layering violations. 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") @verifier def verify_boolean(clazz): """Verifies that boolean accessors are named correctly. For example, hasFoo() and setHasFoo().""" Loading Loading @@ -1248,6 +1274,7 @@ def verify_boolean(clazz): error_if_exists(sets, m.name, expected, "has" + target) @verifier def verify_collections(clazz): """Verifies that collection types are interfaces.""" if clazz.fullname == "android.os.Bundle": return Loading @@ -1262,6 +1289,8 @@ def verify_collections(clazz): if arg in bad: error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface") @verifier def verify_uris(clazz): bad = ["java.net.URL", "java.net.URI", "android.net.URL"] Loading @@ -1276,6 +1305,8 @@ def verify_uris(clazz): if arg in bad: error(clazz, m, None, "Argument must take android.net.Uri instead of " + arg) @verifier def verify_flags(clazz): """Verifies that flags are non-overlapping.""" known = collections.defaultdict(int) Loading @@ -1292,6 +1323,7 @@ def verify_flags(clazz): known[scope] |= val @verifier def verify_exception(clazz): """Verifies that methods don't throw generic exceptions.""" 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"]: warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException") GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE) # Not marked as @verifier, because it is only conditionally applied. def verify_google(clazz): """Verifies that APIs never reference Google.""" Loading @@ -1323,6 +1357,7 @@ def verify_google(clazz): error(clazz, t, None, "Must never reference Google") @verifier def verify_bitset(clazz): """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") @verifier def verify_manager(clazz): """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") @verifier def verify_boxed(clazz): """Verifies that methods avoid boxed primitives.""" Loading @@ -1373,6 +1410,7 @@ def verify_boxed(clazz): error(clazz, m, "M11", "Must avoid boxed primitives") @verifier def verify_static_utils(clazz): """Verifies that helper classes can't be constructed.""" 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") # @verifier # Disabled for now def verify_overload_args(clazz): """Verifies that method overloads add new arguments at the end.""" 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))) @verifier def verify_callback_handlers(clazz): """Verifies that methods adding listener/callback have overload 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") @verifier def verify_context_first(clazz): """Verifies that methods accepting a Context keep it the first argument.""" 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") @verifier def verify_listener_last(clazz): """Verifies that methods accepting a Listener or Callback keep them as last arguments.""" 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") @verifier def verify_resource_names(clazz): """Verifies that resource names have consistent case.""" 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") @verifier def verify_files(clazz): """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") @verifier def verify_manager_list(clazz): """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") @verifier def verify_abstract_inner(clazz): """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") @verifier def verify_runtime_exceptions(clazz): """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") @verifier def verify_error(clazz): """Verifies that we always use Exception instead of Error.""" if not clazz.extends: return Loading @@ -1631,6 +1679,7 @@ def verify_error(clazz): error(clazz, None, None, "Exceptions must be named FooException") @verifier def verify_units(clazz): """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") @verifier def verify_closable(clazz): """Verifies that classes are AutoClosable.""" if "java.lang.AutoCloseable" in clazz.implements_all: return Loading @@ -1679,6 +1729,7 @@ def verify_closable(clazz): return @verifier def verify_member_name_not_kotlin_keyword(clazz): """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") @verifier def verify_method_name_not_kotlin_operator(clazz): """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 @verifier def verify_collections_over_arrays(clazz): """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") @verifier def verify_user_handle(clazz): """Methods taking UserHandle should be ForUser or AsUser.""" 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'") @verifier def verify_params(clazz): """Parameter classes should be 'Params'.""" 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'") @verifier def verify_services(clazz): """Service name should be FOO_BAR_SERVICE = 'foo_bar'.""" 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)) @verifier def verify_tense(clazz): """Verify tenses of method names.""" 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'") @verifier def verify_icu(clazz): """Verifies that richer ICU replacements are used.""" 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])) @verifier def verify_clone(clazz): """Verify that clone() isn't implemented; see EJ page 61.""" 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()") @verifier def verify_pfd(clazz): """Verify that android APIs use PFD over FD.""" 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") @verifier def verify_numbers(clazz): """Discourage small numbers types like short and byte.""" Loading @@ -1909,8 +1970,10 @@ def verify_numbers(clazz): if arg in discouraged: warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead") PRIMITIVES = {"void", "int", "float", "boolean", "short", "char", "byte", "long", "double"} @verifier def verify_nullability(clazz): """Catches missing nullability annotations""" Loading Loading @@ -1939,6 +2002,8 @@ def verify_nullability_args(clazz, m): def has_nullability(annotations): return "@NonNull" in annotations or "@Nullable" in annotations @verifier def verify_singleton(clazz): """Catch singleton objects with constructors.""" Loading Loading @@ -1973,61 +2038,10 @@ def examine_clazz(clazz): if not is_interesting(clazz): return verify_constants(clazz) verify_enums(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) for v in verifiers.itervalues(): v(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): Loading Loading
tools/apilint/apilint.py +70 −56 Original line number Diff line number Diff line Loading @@ -763,6 +763,14 @@ def notice(clazz): noticed[clazz.fullname] = hash(clazz) verifiers = {} def verifier(f): verifiers[f.__name__] = f return f @verifier def verify_constants(clazz): """All static final constants must be FOO_NAME style.""" 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: error(clazz, f, None, "All constants must be defined at compile time") @verifier def verify_enums(clazz): """Enums are bad, mmkay?""" if clazz.extends == "java.lang.Enum" or "enum" in clazz.split: error(clazz, None, "F5", "Enums are not allowed") @verifier def verify_class_names(clazz): """Try catching malformed class names like myMtp or MTPUser.""" 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") @verifier def verify_method_names(clazz): """Try catching malformed method names, like Foo() or getMTU().""" 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") @verifier def verify_callbacks(clazz): """Verify Callback classes. 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") @verifier def verify_listeners(clazz): """Verify Listener classes. 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") @verifier def verify_actions(clazz): """Verify intent actions. 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)) @verifier def verify_extras(clazz): """Verify intent extras. 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)) @verifier def verify_equals(clazz): """Verify that equals() and hashCode() must be overridden together.""" eq = False Loading @@ -928,6 +942,7 @@ def verify_equals(clazz): error(clazz, None, "M8", "Must override both equals and hashCode; missing one") @verifier def verify_parcelable(clazz): """Verify that Parcelable objects aren't hiding required bits.""" 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") @verifier def verify_protected(clazz): """Verify that no protected methods or fields are allowed.""" 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") @verifier def verify_fields(clazz): """Verify that all exposed fields are final. 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") @verifier def verify_register(clazz): """Verify parity of registration 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") @verifier def verify_sync(clazz): """Verify synchronized methods aren't exposed.""" for m in clazz.methods: Loading @@ -1042,6 +1061,7 @@ def verify_sync(clazz): error(clazz, m, "M5", "Internal locks must not be exposed") @verifier def verify_intent_builder(clazz): """Verify that Intent builders are createFooIntent() style.""" 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()") @verifier def verify_helper_classes(clazz): """Verify that helper classes are named consistently with what they extend. 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") @verifier def verify_builder(clazz): """Verify builder classes. 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") @verifier def verify_aidl(clazz): """Catch people exposing raw AIDL.""" if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface": error(clazz, None, None, "Raw AIDL interfaces must not be exposed") @verifier def verify_internal(clazz): """Catch people exposing internal classes.""" if clazz.pkg.name.startswith("com.android"): Loading Loading @@ -1174,6 +1198,7 @@ LAYERING_PACKAGE_RANKING = layering_build_ranking([ "android.util" ]) @verifier def verify_layering(clazz): """Catch package layering violations. 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") @verifier def verify_boolean(clazz): """Verifies that boolean accessors are named correctly. For example, hasFoo() and setHasFoo().""" Loading Loading @@ -1248,6 +1274,7 @@ def verify_boolean(clazz): error_if_exists(sets, m.name, expected, "has" + target) @verifier def verify_collections(clazz): """Verifies that collection types are interfaces.""" if clazz.fullname == "android.os.Bundle": return Loading @@ -1262,6 +1289,8 @@ def verify_collections(clazz): if arg in bad: error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface") @verifier def verify_uris(clazz): bad = ["java.net.URL", "java.net.URI", "android.net.URL"] Loading @@ -1276,6 +1305,8 @@ def verify_uris(clazz): if arg in bad: error(clazz, m, None, "Argument must take android.net.Uri instead of " + arg) @verifier def verify_flags(clazz): """Verifies that flags are non-overlapping.""" known = collections.defaultdict(int) Loading @@ -1292,6 +1323,7 @@ def verify_flags(clazz): known[scope] |= val @verifier def verify_exception(clazz): """Verifies that methods don't throw generic exceptions.""" 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"]: warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException") GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE) # Not marked as @verifier, because it is only conditionally applied. def verify_google(clazz): """Verifies that APIs never reference Google.""" Loading @@ -1323,6 +1357,7 @@ def verify_google(clazz): error(clazz, t, None, "Must never reference Google") @verifier def verify_bitset(clazz): """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") @verifier def verify_manager(clazz): """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") @verifier def verify_boxed(clazz): """Verifies that methods avoid boxed primitives.""" Loading @@ -1373,6 +1410,7 @@ def verify_boxed(clazz): error(clazz, m, "M11", "Must avoid boxed primitives") @verifier def verify_static_utils(clazz): """Verifies that helper classes can't be constructed.""" 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") # @verifier # Disabled for now def verify_overload_args(clazz): """Verifies that method overloads add new arguments at the end.""" 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))) @verifier def verify_callback_handlers(clazz): """Verifies that methods adding listener/callback have overload 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") @verifier def verify_context_first(clazz): """Verifies that methods accepting a Context keep it the first argument.""" 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") @verifier def verify_listener_last(clazz): """Verifies that methods accepting a Listener or Callback keep them as last arguments.""" 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") @verifier def verify_resource_names(clazz): """Verifies that resource names have consistent case.""" 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") @verifier def verify_files(clazz): """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") @verifier def verify_manager_list(clazz): """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") @verifier def verify_abstract_inner(clazz): """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") @verifier def verify_runtime_exceptions(clazz): """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") @verifier def verify_error(clazz): """Verifies that we always use Exception instead of Error.""" if not clazz.extends: return Loading @@ -1631,6 +1679,7 @@ def verify_error(clazz): error(clazz, None, None, "Exceptions must be named FooException") @verifier def verify_units(clazz): """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") @verifier def verify_closable(clazz): """Verifies that classes are AutoClosable.""" if "java.lang.AutoCloseable" in clazz.implements_all: return Loading @@ -1679,6 +1729,7 @@ def verify_closable(clazz): return @verifier def verify_member_name_not_kotlin_keyword(clazz): """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") @verifier def verify_method_name_not_kotlin_operator(clazz): """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 @verifier def verify_collections_over_arrays(clazz): """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") @verifier def verify_user_handle(clazz): """Methods taking UserHandle should be ForUser or AsUser.""" 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'") @verifier def verify_params(clazz): """Parameter classes should be 'Params'.""" 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'") @verifier def verify_services(clazz): """Service name should be FOO_BAR_SERVICE = 'foo_bar'.""" 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)) @verifier def verify_tense(clazz): """Verify tenses of method names.""" 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'") @verifier def verify_icu(clazz): """Verifies that richer ICU replacements are used.""" 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])) @verifier def verify_clone(clazz): """Verify that clone() isn't implemented; see EJ page 61.""" 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()") @verifier def verify_pfd(clazz): """Verify that android APIs use PFD over FD.""" 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") @verifier def verify_numbers(clazz): """Discourage small numbers types like short and byte.""" Loading @@ -1909,8 +1970,10 @@ def verify_numbers(clazz): if arg in discouraged: warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead") PRIMITIVES = {"void", "int", "float", "boolean", "short", "char", "byte", "long", "double"} @verifier def verify_nullability(clazz): """Catches missing nullability annotations""" Loading Loading @@ -1939,6 +2002,8 @@ def verify_nullability_args(clazz, m): def has_nullability(annotations): return "@NonNull" in annotations or "@Nullable" in annotations @verifier def verify_singleton(clazz): """Catch singleton objects with constructors.""" Loading Loading @@ -1973,61 +2038,10 @@ def examine_clazz(clazz): if not is_interesting(clazz): return verify_constants(clazz) verify_enums(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) for v in verifiers.itervalues(): v(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): Loading