diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2024-08-08 18:13:00 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2024-08-15 23:59:08 +0300 |
commit | 50c92cc7e2924009ecab3e4004448b01d687707c (patch) | |
tree | c22b49816a3c79dae4727780962aa0928df42b52 /utils/ipc/mojo/public/tools/bindings/checks | |
parent | d3bf27180ef1d91b86b7b87a2378e559eaff5455 (diff) |
meson: Move all code generation scripts to utils/codegen/
We have multiple code generation scripts in utils/, mixed with other
miscellaneous utilities, as well as a larger code base based on mojom in
utils/ipc/. To make code sharing easier between the generator scripts,
without creating a mess in the utils/ directory, move all the code
generation code to utils/codegen/.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Diffstat (limited to 'utils/ipc/mojo/public/tools/bindings/checks')
8 files changed, 0 insertions, 989 deletions
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/__init__.py b/utils/ipc/mojo/public/tools/bindings/checks/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/__init__.py +++ /dev/null diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py deleted file mode 100644 index e6e4f2c9..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Validate mojo attributes are allowed in Chrome before generation.""" - -import mojom.generate.check as check -import mojom.generate.module as module - -_COMMON_ATTRIBUTES = { - 'EnableIf', - 'EnableIfNot', -} - -# For struct, union & parameter lists. -_COMMON_FIELD_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'MinVersion', - 'RenamedFrom', -} - -# Note: `Default`` goes on the default _value_, not on the enum. -# Note: [Stable] without [Extensible] is not allowed. -_ENUM_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'Extensible', - 'Native', - 'Stable', - 'RenamedFrom', - 'Uuid', -} - -# TODO(crbug.com/1234883) MinVersion is not needed for EnumVal. -_ENUMVAL_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'Default', - 'MinVersion', -} - -_INTERFACE_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'RenamedFrom', - 'RequireContext', - 'RuntimeFeature', - 'ServiceSandbox', - 'Stable', - 'Uuid', -} - -_METHOD_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'AllowedContext', - 'MinVersion', - 'NoInterrupt', - 'RuntimeFeature', - 'SupportsUrgent', - 'Sync', - 'UnlimitedSize', -} - -_MODULE_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'JavaConstantsClassName', - 'JavaPackage', -} - -_PARAMETER_ATTRIBUTES = _COMMON_FIELD_ATTRIBUTES - -_STRUCT_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'CustomSerializer', - 'JavaClassName', - 'Native', - 'Stable', - 'RenamedFrom', - 'Uuid', -} - -_STRUCT_FIELD_ATTRIBUTES = _COMMON_FIELD_ATTRIBUTES - -_UNION_ATTRIBUTES = _COMMON_ATTRIBUTES | { - 'Extensible', - 'Stable', - 'RenamedFrom', - 'Uuid', -} - -_UNION_FIELD_ATTRIBUTES = _COMMON_FIELD_ATTRIBUTES | { - 'Default', -} - -# TODO(https://crbug.com/1193875) empty this set and remove the allowlist. -_STABLE_ONLY_ALLOWLISTED_ENUMS = { - 'crosapi.mojom.OptionalBool', - 'crosapi.mojom.TriState', -} - - -class Check(check.Check): - def __init__(self, *args, **kwargs): - super(Check, self).__init__(*args, **kwargs) - - def _Respell(self, allowed, attribute): - for a in allowed: - if a.lower() == attribute.lower(): - return f" - Did you mean: {a}?" - return "" - - def _CheckAttributes(self, context, allowed, attributes): - if not attributes: - return - for attribute in attributes: - if not attribute in allowed: - # Is there a close misspelling? - hint = self._Respell(allowed, attribute) - raise check.CheckException( - self.module, - f"attribute {attribute} not allowed on {context}{hint}") - - def _CheckEnumAttributes(self, enum): - if enum.attributes: - self._CheckAttributes("enum", _ENUM_ATTRIBUTES, enum.attributes) - if 'Stable' in enum.attributes and not 'Extensible' in enum.attributes: - full_name = f"{self.module.mojom_namespace}.{enum.mojom_name}" - if full_name not in _STABLE_ONLY_ALLOWLISTED_ENUMS: - raise check.CheckException( - self.module, - f"[Extensible] required on [Stable] enum {full_name}") - for enumval in enum.fields: - self._CheckAttributes("enum value", _ENUMVAL_ATTRIBUTES, - enumval.attributes) - - def _CheckInterfaceAttributes(self, interface): - self._CheckAttributes("interface", _INTERFACE_ATTRIBUTES, - interface.attributes) - for method in interface.methods: - self._CheckAttributes("method", _METHOD_ATTRIBUTES, method.attributes) - for param in method.parameters: - self._CheckAttributes("parameter", _PARAMETER_ATTRIBUTES, - param.attributes) - if method.response_parameters: - for param in method.response_parameters: - self._CheckAttributes("parameter", _PARAMETER_ATTRIBUTES, - param.attributes) - for enum in interface.enums: - self._CheckEnumAttributes(enum) - - def _CheckModuleAttributes(self): - self._CheckAttributes("module", _MODULE_ATTRIBUTES, self.module.attributes) - - def _CheckStructAttributes(self, struct): - self._CheckAttributes("struct", _STRUCT_ATTRIBUTES, struct.attributes) - for field in struct.fields: - self._CheckAttributes("struct field", _STRUCT_FIELD_ATTRIBUTES, - field.attributes) - for enum in struct.enums: - self._CheckEnumAttributes(enum) - - def _CheckUnionAttributes(self, union): - self._CheckAttributes("union", _UNION_ATTRIBUTES, union.attributes) - for field in union.fields: - self._CheckAttributes("union field", _UNION_FIELD_ATTRIBUTES, - field.attributes) - - def CheckModule(self): - """Note that duplicate attributes are forbidden at the parse phase. - We also do not need to look at the types of any parameters, as they will be - checked where they are defined. Consts do not have attributes so can be - skipped.""" - self._CheckModuleAttributes() - for interface in self.module.interfaces: - self._CheckInterfaceAttributes(interface) - for enum in self.module.enums: - self._CheckEnumAttributes(enum) - for struct in self.module.structs: - self._CheckStructAttributes(struct) - for union in self.module.unions: - self._CheckUnionAttributes(union) diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py deleted file mode 100644 index f1a50a4a..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import unittest - -import mojom.generate.check as check -from mojom_bindings_generator import LoadChecks, _Generate -from mojom_parser_test_case import MojomParserTestCase - - -class FakeArgs: - """Fakes args to _Generate - intention is to do just enough to run checks""" - - def __init__(self, tester, files=None): - """ `tester` is MojomParserTestCase for paths. - `files` will have tester path added.""" - self.checks_string = 'attributes' - self.depth = tester.GetPath('') - self.filelist = None - self.filename = [tester.GetPath(x) for x in files] - self.gen_directories = tester.GetPath('gen') - self.generators_string = '' - self.import_directories = [] - self.output_dir = tester.GetPath('out') - self.scrambled_message_id_salt_paths = None - self.typemaps = [] - self.variant = 'none' - - -class MojoBindingsCheckTest(MojomParserTestCase): - def _ParseAndGenerate(self, mojoms): - self.ParseMojoms(mojoms) - args = FakeArgs(self, files=mojoms) - _Generate(args, {}) - - def _testValid(self, filename, content): - self.WriteFile(filename, content) - self._ParseAndGenerate([filename]) - - def _testThrows(self, filename, content, regexp): - mojoms = [] - self.WriteFile(filename, content) - mojoms.append(filename) - with self.assertRaisesRegexp(check.CheckException, regexp): - self._ParseAndGenerate(mojoms) - - def testLoads(self): - """Validate that the check is registered under the expected name.""" - check_modules = LoadChecks('attributes') - self.assertTrue(check_modules['attributes']) - - def testNoAnnotations(self): - # Undecorated mojom should be fine. - self._testValid( - "a.mojom", """ - module a; - struct Bar { int32 a; }; - enum Hello { kValue }; - union Thingy { Bar b; Hello hi; }; - interface Foo { - Foo(int32 a, Hello hi, Thingy t) => (Bar b); - }; - """) - - def testValidAnnotations(self): - # Obviously this is meaningless and won't generate, but it should pass - # the attribute check's validation. - self._testValid( - "a.mojom", """ - [JavaConstantsClassName="FakeClass",JavaPackage="org.chromium.Fake"] - module a; - [Stable, Extensible] - enum Hello { [Default] kValue, kValue2, [MinVersion=2] kValue3 }; - [Native] - enum NativeEnum {}; - [Stable,Extensible] - union Thingy { Bar b; [Default]int32 c; Hello hi; }; - - [Stable,RenamedFrom="module.other.Foo", - Uuid="4C178401-4B07-4C2E-9255-5401A943D0C7"] - struct Structure { Hello hi; }; - - [ServiceSandbox=Hello.kValue,RequireContext=Hello.kValue,Stable, - Uuid="2F17D7DD-865A-4B1C-9394-9C94E035E82F"] - interface Foo { - [AllowedContext=Hello.kValue] - Foo@0(int32 a) => (int32 b); - [MinVersion=2,Sync,UnlimitedSize,NoInterrupt] - Bar@1(int32 b, [MinVersion=2]Structure? s) => (bool c); - }; - - [RuntimeFeature=test.mojom.FeatureName] - interface FooFeatureControlled {}; - - interface FooMethodFeatureControlled { - [RuntimeFeature=test.mojom.FeatureName] - MethodWithFeature() => (bool c); - }; - """) - - def testWrongModuleStable(self): - contents = """ - // err: module cannot be Stable - [Stable] - module a; - enum Hello { kValue, kValue2, kValue3 }; - enum NativeEnum {}; - struct Structure { Hello hi; }; - - interface Foo { - Foo(int32 a) => (int32 b); - Bar(int32 b, Structure? s) => (bool c); - }; - """ - self._testThrows('b.mojom', contents, - 'attribute Stable not allowed on module') - - def testWrongEnumDefault(self): - contents = """ - module a; - // err: default should go on EnumValue not Enum. - [Default=kValue] - enum Hello { kValue, kValue2, kValue3 }; - enum NativeEnum {}; - struct Structure { Hello hi; }; - - interface Foo { - Foo(int32 a) => (int32 b); - Bar(int32 b, Structure? s) => (bool c); - }; - """ - self._testThrows('b.mojom', contents, - 'attribute Default not allowed on enum') - - def testWrongStructMinVersion(self): - contents = """ - module a; - enum Hello { kValue, kValue2, kValue3 }; - enum NativeEnum {}; - // err: struct cannot have MinVersion. - [MinVersion=2] - struct Structure { Hello hi; }; - - interface Foo { - Foo(int32 a) => (int32 b); - Bar(int32 b, Structure? s) => (bool c); - }; - """ - self._testThrows('b.mojom', contents, - 'attribute MinVersion not allowed on struct') - - def testWrongMethodRequireContext(self): - contents = """ - module a; - enum Hello { kValue, kValue2, kValue3 }; - enum NativeEnum {}; - struct Structure { Hello hi; }; - - interface Foo { - // err: RequireContext is for interfaces. - [RequireContext=Hello.kValue] - Foo(int32 a) => (int32 b); - Bar(int32 b, Structure? s) => (bool c); - }; - """ - self._testThrows('b.mojom', contents, - 'RequireContext not allowed on method') - - def testWrongMethodRequireContext(self): - # crbug.com/1230122 - contents = """ - module a; - interface Foo { - // err: sync not Sync. - [sync] - Foo(int32 a) => (int32 b); - }; - """ - self._testThrows('b.mojom', contents, - 'attribute sync not allowed.*Did you mean: Sync') - - def testStableExtensibleEnum(self): - # crbug.com/1193875 - contents = """ - module a; - [Stable] - enum Foo { - kDefaultVal, - kOtherVal = 2, - }; - """ - self._testThrows('a.mojom', contents, - 'Extensible.*?required.*?Stable.*?enum') diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py deleted file mode 100644 index 702d41c3..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Ensure no duplicate type definitions before generation.""" - -import mojom.generate.check as check -import mojom.generate.module as module - - -class Check(check.Check): - def __init__(self, *args, **kwargs): - super(Check, self).__init__(*args, **kwargs) - - def CheckModule(self): - kinds = dict() - for module in self.module.imports: - for kind in module.enums + module.structs + module.unions: - kind_name = f'{kind.module.mojom_namespace}.{kind.mojom_name}' - if kind_name in kinds: - previous_module = kinds[kind_name] - if previous_module.path != module.path: - raise check.CheckException( - self.module, f"multiple-definition for type {kind_name}" + - f"(defined in both {previous_module} and {module})") - kinds[kind_name] = kind.module - - for kind in self.module.enums + self.module.structs + self.module.unions: - kind_name = f'{kind.module.mojom_namespace}.{kind.mojom_name}' - if kind_name in kinds: - previous_module = kinds[kind_name] - raise check.CheckException( - self.module, f"multiple-definition for type {kind_name}" + - f"(previous definition in {previous_module})") - return True diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py deleted file mode 100644 index 07f51a64..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2023 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Validate mojo runtime feature guarded interfaces are nullable.""" - -import mojom.generate.check as check -import mojom.generate.module as module - - -class Check(check.Check): - def __init__(self, *args, **kwargs): - super(Check, self).__init__(*args, **kwargs) - - # `param` is an Interface of some sort. - def _CheckNonNullableFeatureGuardedInterface(self, kind): - # Only need to validate interface if it has a RuntimeFeature - if not kind.kind.runtime_feature: - return - # Nullable (optional) is ok as the interface expects they might not be sent. - if kind.is_nullable: - return - interface = kind.kind.mojom_name - raise check.CheckException( - self.module, - f"interface {interface} has a RuntimeFeature but is not nullable") - - # `param` can be a lot of things so check if it is a remote/receiver. - # Array/Map must be recursed into. - def _CheckFieldOrParam(self, kind): - if module.IsAnyInterfaceKind(kind): - self._CheckNonNullableFeatureGuardedInterface(kind) - if module.IsArrayKind(kind): - self._CheckFieldOrParam(kind.kind) - if module.IsMapKind(kind): - self._CheckFieldOrParam(kind.key_kind) - self._CheckFieldOrParam(kind.value_kind) - - def _CheckInterfaceFeatures(self, interface): - for method in interface.methods: - for param in method.parameters: - self._CheckFieldOrParam(param.kind) - if method.response_parameters: - for param in method.response_parameters: - self._CheckFieldOrParam(param.kind) - - def _CheckStructFeatures(self, struct): - for field in struct.fields: - self._CheckFieldOrParam(field.kind) - - def _CheckUnionFeatures(self, union): - for field in union.fields: - self._CheckFieldOrParam(field.kind) - - def CheckModule(self): - """Validate that any runtime feature guarded interfaces that might be passed - over mojo are nullable.""" - for interface in self.module.interfaces: - self._CheckInterfaceFeatures(interface) - for struct in self.module.structs: - self._CheckStructFeatures(struct) - for union in self.module.unions: - self._CheckUnionFeatures(union) diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py deleted file mode 100644 index e96152fd..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2023 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import unittest - -import mojom.generate.check as check -from mojom_bindings_generator import LoadChecks, _Generate -from mojom_parser_test_case import MojomParserTestCase - - -class FakeArgs: - """Fakes args to _Generate - intention is to do just enough to run checks""" - def __init__(self, tester, files=None): - """ `tester` is MojomParserTestCase for paths. - `files` will have tester path added.""" - self.checks_string = 'features' - self.depth = tester.GetPath('') - self.filelist = None - self.filename = [tester.GetPath(x) for x in files] - self.gen_directories = tester.GetPath('gen') - self.generators_string = '' - self.import_directories = [] - self.output_dir = tester.GetPath('out') - self.scrambled_message_id_salt_paths = None - self.typemaps = [] - self.variant = 'none' - - -class MojoBindingsCheckTest(MojomParserTestCase): - def _ParseAndGenerate(self, mojoms): - self.ParseMojoms(mojoms) - args = FakeArgs(self, files=mojoms) - _Generate(args, {}) - - def assertValid(self, filename, content): - self.WriteFile(filename, content) - self._ParseAndGenerate([filename]) - - def assertThrows(self, filename, content, regexp): - mojoms = [] - self.WriteFile(filename, content) - mojoms.append(filename) - with self.assertRaisesRegexp(check.CheckException, regexp): - self._ParseAndGenerate(mojoms) - - def testLoads(self): - """Validate that the check is registered under the expected name.""" - check_modules = LoadChecks('features') - self.assertTrue(check_modules['features']) - - def testNullableOk(self): - self.assertValid( - "a.mojom", """ - module a; - // Scaffolding. - feature kFeature { - const string name = "Hello"; - const bool enabled_state = false; - }; - [RuntimeFeature=kFeature] - interface Guarded { - }; - - // Unguarded interfaces should be ok everywhere. - interface NotGuarded { }; - - // Optional (nullable) interfaces should be ok everywhere: - struct Bar { - pending_remote<Guarded>? remote; - pending_receiver<Guarded>? receiver; - }; - union Thingy { - pending_remote<Guarded>? remote; - pending_receiver<Guarded>? receiver; - }; - interface Foo { - Foo( - pending_remote<Guarded>? remote, - pending_receiver<Guarded>? receiver, - pending_associated_remote<Guarded>? a_remote, - pending_associated_receiver<Guarded>? a_receiver, - // Unguarded interfaces do not have to be nullable. - pending_remote<NotGuarded> remote, - pending_receiver<NotGuarded> receiver, - pending_associated_remote<NotGuarded> a_remote, - pending_associated_receiver<NotGuarded> a_receiver - ) => ( - pending_remote<Guarded>? remote, - pending_receiver<Guarded>? receiver - ); - Bar(array<pending_remote<Guarded>?> remote) - => (map<string, pending_receiver<Guarded>?> a); - }; - """) - - def testMethodParamsMustBeNullable(self): - prelude = """ - module a; - // Scaffolding. - feature kFeature { - const string name = "Hello"; - const bool enabled_state = false; - }; - [RuntimeFeature=kFeature] - interface Guarded { }; - """ - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(pending_remote<Guarded> a) => (); - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(bool foo) => (pending_receiver<Guarded> a); - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(pending_receiver<Guarded> a) => (); - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(pending_associated_remote<Guarded> a) => (); - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(pending_associated_receiver<Guarded> a) => (); - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(array<pending_associated_receiver<Guarded>> a) => (); - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - interface Trial { - Method(map<string, pending_associated_receiver<Guarded>> a) => (); - }; - """, 'interface Guarded has a RuntimeFeature') - - def testStructUnionMembersMustBeNullable(self): - prelude = """ - module a; - // Scaffolding. - feature kFeature { - const string name = "Hello"; - const bool enabled_state = false; - }; - [RuntimeFeature=kFeature] - interface Guarded { }; - """ - self.assertThrows( - 'a.mojom', prelude + """ - struct Trial { - pending_remote<Guarded> a; - }; - """, 'interface Guarded has a RuntimeFeature') - self.assertThrows( - 'a.mojom', prelude + """ - union Trial { - pending_remote<Guarded> a; - }; - """, 'interface Guarded has a RuntimeFeature') diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py deleted file mode 100644 index d570e26c..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Validate RequireContext and AllowedContext annotations before generation.""" - -import mojom.generate.check as check -import mojom.generate.module as module - - -class Check(check.Check): - def __init__(self, *args, **kwargs): - self.kind_to_interfaces = dict() - super(Check, self).__init__(*args, **kwargs) - - def _IsPassedInterface(self, candidate): - if isinstance( - candidate.kind, - (module.PendingReceiver, module.PendingRemote, - module.PendingAssociatedReceiver, module.PendingAssociatedRemote)): - return True - return False - - def _CheckInterface(self, method, param): - # |param| is a pending_x<Interface> so need .kind.kind to get Interface. - interface = param.kind.kind - if interface.require_context: - if method.allowed_context is None: - raise check.CheckException( - self.module, "method `{}` has parameter `{}` which passes interface" - " `{}` that requires an AllowedContext annotation but none exists.". - format( - method.mojom_name, - param.mojom_name, - interface.mojom_name, - )) - # If a string was provided, or if an enum was not imported, this will - # be a string and we cannot validate that it is in range. - if not isinstance(method.allowed_context, module.EnumValue): - raise check.CheckException( - self.module, - "method `{}` has AllowedContext={} which is not a valid enum value." - .format(method.mojom_name, method.allowed_context)) - # EnumValue must be from the same enum to be compared. - if interface.require_context.enum != method.allowed_context.enum: - raise check.CheckException( - self.module, "method `{}` has parameter `{}` which passes interface" - " `{}` that requires AllowedContext={} but one of kind `{}` was " - "provided.".format( - method.mojom_name, - param.mojom_name, - interface.mojom_name, - interface.require_context.enum, - method.allowed_context.enum, - )) - # RestrictContext enums have most privileged field first (lowest value). - interface_value = interface.require_context.field.numeric_value - method_value = method.allowed_context.field.numeric_value - if interface_value < method_value: - raise check.CheckException( - self.module, "RequireContext={} > AllowedContext={} for method " - "`{}` which passes interface `{}`.".format( - interface.require_context.GetSpec(), - method.allowed_context.GetSpec(), method.mojom_name, - interface.mojom_name)) - return True - - def _GatherReferencedInterfaces(self, field): - key = field.kind.spec - # structs/unions can nest themselves so we need to bookkeep. - if not key in self.kind_to_interfaces: - # Might reference ourselves so have to create the list first. - self.kind_to_interfaces[key] = set() - for param in field.kind.fields: - if self._IsPassedInterface(param): - self.kind_to_interfaces[key].add(param) - elif isinstance(param.kind, (module.Struct, module.Union)): - for iface in self._GatherReferencedInterfaces(param): - self.kind_to_interfaces[key].add(iface) - return self.kind_to_interfaces[key] - - def _CheckParams(self, method, params): - # Note: we have to repeat _CheckParams for each method as each might have - # different AllowedContext= attributes. We cannot memoize this function, - # but can do so for gathering referenced interfaces as their RequireContext - # attributes do not change. - for param in params: - if self._IsPassedInterface(param): - self._CheckInterface(method, param) - elif isinstance(param.kind, (module.Struct, module.Union)): - for interface in self._GatherReferencedInterfaces(param): - self._CheckInterface(method, interface) - - def _CheckMethod(self, method): - if method.parameters: - self._CheckParams(method, method.parameters) - if method.response_parameters: - self._CheckParams(method, method.response_parameters) - - def CheckModule(self): - for interface in self.module.interfaces: - for method in interface.methods: - self._CheckMethod(method) diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py b/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py deleted file mode 100644 index a6cd71e2..00000000 --- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py +++ /dev/null @@ -1,254 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import unittest - -import mojom.generate.check as check -from mojom_bindings_generator import LoadChecks, _Generate -from mojom_parser_test_case import MojomParserTestCase - -# Mojoms that we will use in multiple tests. -basic_mojoms = { - 'level.mojom': - """ - module level; - enum Level { - kHighest, - kMiddle, - kLowest, - }; - """, - 'interfaces.mojom': - """ - module interfaces; - import "level.mojom"; - struct Foo {int32 bar;}; - [RequireContext=level.Level.kHighest] - interface High { - DoFoo(Foo foo); - }; - [RequireContext=level.Level.kMiddle] - interface Mid { - DoFoo(Foo foo); - }; - [RequireContext=level.Level.kLowest] - interface Low { - DoFoo(Foo foo); - }; - """ -} - - -class FakeArgs: - """Fakes args to _Generate - intention is to do just enough to run checks""" - - def __init__(self, tester, files=None): - """ `tester` is MojomParserTestCase for paths. - `files` will have tester path added.""" - self.checks_string = 'restrictions' - self.depth = tester.GetPath('') - self.filelist = None - self.filename = [tester.GetPath(x) for x in files] - self.gen_directories = tester.GetPath('gen') - self.generators_string = '' - self.import_directories = [] - self.output_dir = tester.GetPath('out') - self.scrambled_message_id_salt_paths = None - self.typemaps = [] - self.variant = 'none' - - -class MojoBindingsCheckTest(MojomParserTestCase): - def _WriteBasicMojoms(self): - for filename, contents in basic_mojoms.items(): - self.WriteFile(filename, contents) - return list(basic_mojoms.keys()) - - def _ParseAndGenerate(self, mojoms): - self.ParseMojoms(mojoms) - args = FakeArgs(self, files=mojoms) - _Generate(args, {}) - - def testLoads(self): - """Validate that the check is registered under the expected name.""" - check_modules = LoadChecks('restrictions') - self.assertTrue(check_modules['restrictions']) - - def testValidAnnotations(self): - mojoms = self._WriteBasicMojoms() - - a = 'a.mojom' - self.WriteFile( - a, """ - module a; - import "level.mojom"; - import "interfaces.mojom"; - - interface PassesHigh { - [AllowedContext=level.Level.kHighest] - DoHigh(pending_receiver<interfaces.High> hi); - }; - interface PassesMedium { - [AllowedContext=level.Level.kMiddle] - DoMedium(pending_receiver<interfaces.Mid> hi); - [AllowedContext=level.Level.kMiddle] - DoMediumRem(pending_remote<interfaces.Mid> hi); - [AllowedContext=level.Level.kMiddle] - DoMediumAssoc(pending_associated_receiver<interfaces.Mid> hi); - [AllowedContext=level.Level.kMiddle] - DoMediumAssocRem(pending_associated_remote<interfaces.Mid> hi); - }; - interface PassesLow { - [AllowedContext=level.Level.kLowest] - DoLow(pending_receiver<interfaces.Low> hi); - }; - - struct One { pending_receiver<interfaces.High> hi; }; - struct Two { One one; }; - interface PassesNestedHigh { - [AllowedContext=level.Level.kHighest] - DoNestedHigh(Two two); - }; - - // Allowed as PassesHigh is not itself restricted. - interface PassesPassesHigh { - DoPass(pending_receiver<PassesHigh> hiho); - }; - """) - mojoms.append(a) - self._ParseAndGenerate(mojoms) - - def _testThrows(self, filename, content, regexp): - mojoms = self._WriteBasicMojoms() - self.WriteFile(filename, content) - mojoms.append(filename) - with self.assertRaisesRegexp(check.CheckException, regexp): - self._ParseAndGenerate(mojoms) - - def testMissingAnnotation(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - - interface PassesHigh { - // err: missing annotation. - DoHigh(pending_receiver<interfaces.High> hi); - }; - """ - self._testThrows('b.mojom', contents, 'require.*?AllowedContext') - - def testAllowTooLow(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - - interface PassesHigh { - // err: level is worse than required. - [AllowedContext=level.Level.kMiddle] - DoHigh(pending_receiver<interfaces.High> hi); - }; - """ - self._testThrows('b.mojom', contents, - 'RequireContext=.*?kHighest > AllowedContext=.*?kMiddle') - - def testWrongEnumInAllow(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - enum Blah { - kZero, - }; - interface PassesHigh { - // err: different enums. - [AllowedContext=Blah.kZero] - DoHigh(pending_receiver<interfaces.High> hi); - }; - """ - self._testThrows('b.mojom', contents, 'but one of kind') - - def testNotAnEnumInAllow(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - interface PassesHigh { - // err: not an enum. - [AllowedContext=doopdedoo.mojom.kWhatever] - DoHigh(pending_receiver<interfaces.High> hi); - }; - """ - self._testThrows('b.mojom', contents, 'not a valid enum value') - - def testMissingAllowedForNestedStructs(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - struct One { pending_receiver<interfaces.High> hi; }; - struct Two { One one; }; - interface PassesNestedHigh { - // err: missing annotation. - DoNestedHigh(Two two); - }; - """ - self._testThrows('b.mojom', contents, 'require.*?AllowedContext') - - def testMissingAllowedForNestedUnions(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - struct One { pending_receiver<interfaces.High> hi; }; - struct Two { One one; }; - union Three {One one; Two two; }; - interface PassesNestedHigh { - // err: missing annotation. - DoNestedHigh(Three three); - }; - """ - self._testThrows('b.mojom', contents, 'require.*?AllowedContext') - - def testMultipleInterfacesThrows(self): - contents = """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - struct One { pending_receiver<interfaces.High> hi; }; - interface PassesMultipleInterfaces { - [AllowedContext=level.Level.kMiddle] - DoMultiple( - pending_remote<interfaces.Mid> mid, - pending_receiver<interfaces.High> hi, - One one - ); - }; - """ - self._testThrows('b.mojom', contents, - 'RequireContext=.*?kHighest > AllowedContext=.*?kMiddle') - - def testMultipleInterfacesAllowed(self): - """Multiple interfaces can be passed, all satisfy the level.""" - mojoms = self._WriteBasicMojoms() - - b = "b.mojom" - self.WriteFile( - b, """ - module b; - import "level.mojom"; - import "interfaces.mojom"; - struct One { pending_receiver<interfaces.High> hi; }; - interface PassesMultipleInterfaces { - [AllowedContext=level.Level.kHighest] - DoMultiple( - pending_receiver<interfaces.High> hi, - pending_remote<interfaces.Mid> mid, - One one - ); - }; - """) - mojoms.append(b) - self._ParseAndGenerate(mojoms) |