-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bindings: Comprehensive checks for IDL extended attributes
Introduces the syntax checks for IDL extended attributes. - Spelling - Applied targets (attribute, operation, etc.) - Format of extended attributes (no arg, single arg, etc.) will be checked in order to prevent misuse of IDL extended attributes. Finer checks can be added later. Change-Id: I6e66471ea21066112033d4a3c1c7195bc9f003ae Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4546828 Commit-Queue: Yuki Shiino <yukishiino@chromium.org> Reviewed-by: Kentaro Hara <haraken@chromium.org> Cr-Commit-Position: refs/heads/main@{#1150389}
- Loading branch information
Showing
5 changed files
with
359 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
third_party/blink/renderer/bindings/scripts/validator/rules/extended_attribute_descriptor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# Copyright 2023 The Chromium Authors. All rights reserved. | ||
# Use of this source code is governed by a BSD-style license that can be | ||
# found in the LICENSE file. | ||
|
||
import enum | ||
|
||
import web_idl | ||
|
||
|
||
class ExtendedAttributeDescriptor(object): | ||
class Target(enum.Enum): | ||
ATTRIBUTE = web_idl.Attribute | ||
CALLBACK_FUNCTION = web_idl.CallbackFunction | ||
CALLBACK_INTERFACE = web_idl.CallbackInterface | ||
CONSTANT = web_idl.Constant | ||
CONSTRUCTOR = web_idl.Constructor | ||
DICTIONARY = web_idl.Dictionary | ||
DICTIONARY_MEMBER = web_idl.DictionaryMember | ||
INTERFACE = web_idl.Interface | ||
LEGACY_WINDOW_ALIAS = web_idl.LegacyWindowAlias | ||
NAMESPACE = web_idl.Namespace | ||
OPERATION = web_idl.Operation | ||
TYPE = web_idl.IdlType | ||
|
||
class Form(enum.Enum): | ||
# https://webidl.spec.whatwg.org/#idl-extended-attributes | ||
NO_ARGS = enum.auto() # [ExtAttr] | ||
IDENT = enum.auto() # [ExtAttr=Value] | ||
IDENT_LIST = enum.auto() # [ExtAttr=(Value1, ...)] | ||
ARG_LIST = enum.auto() # [ExtAttr(V1L V1R, ...)] | ||
NAMED_ARG_LIST = enum.auto() # [ExtAttr=Name(V1L V1R, ...)] | ||
|
||
def __init__(self, | ||
name, | ||
applicable_to=None, | ||
forms=None, | ||
values=None, | ||
post_validate=None): | ||
assert isinstance(name, str) | ||
assert isinstance(applicable_to, list) and all( | ||
isinstance(target, ExtendedAttributeDescriptor.Target) | ||
for target in applicable_to) | ||
assert forms is None or isinstance( | ||
forms, ExtendedAttributeDescriptor.Form) or (isinstance( | ||
forms, list) and all( | ||
isinstance(form, ExtendedAttributeDescriptor.Form) | ||
for form in forms)) | ||
assert values is None or (isinstance(values, list) and all( | ||
isinstance(value, str) for value in values)) | ||
assert post_validate is None or callable(post_validate) | ||
|
||
self._name = name | ||
# self._applicable_to is a list of valid target object's types, e.g. | ||
# web_idl.Attribute, web_idl.Constant, etc. | ||
self._applicable_to = tuple(map(lambda e: e.value, applicable_to)) | ||
# self._forms is a list of valid forms. | ||
if forms is None: | ||
self._forms = [ExtendedAttributeDescriptor.Form.NO_ARGS] | ||
elif not isinstance(forms, list): | ||
self._forms = [forms] | ||
else: | ||
self._forms = forms | ||
# self._values is a list of valid "ident" values | ||
if values is None: | ||
self._values = None | ||
else: | ||
assert (ExtendedAttributeDescriptor.Form.IDENT in self._forms or | ||
ExtendedAttributeDescriptor.Form.IDENT_LIST in self._forms) | ||
self._values = values | ||
# self._post_validate is a callable or None. | ||
self._post_validate = post_validate | ||
|
||
@property | ||
def name(self): | ||
return self._name | ||
|
||
def validate(self, assert_, target_object, ext_attr): | ||
T = ExtendedAttributeDescriptor.Target | ||
F = ExtendedAttributeDescriptor.Form | ||
|
||
failure_count = [0] | ||
|
||
def _assert(condition, text, *args, **kwargs): | ||
if not condition: | ||
failure_count[0] = failure_count[0] + 1 | ||
assert_(condition, text, *args, **kwargs) | ||
|
||
# applicable_to | ||
_assert(isinstance(target_object, self._applicable_to), | ||
"[{}] is not applicable to {}.", self._name, | ||
target_object.__class__.__name__) | ||
|
||
# forms | ||
if ext_attr.has_values: | ||
if not ext_attr.values: | ||
_assert(F.NO_ARGS in self._forms, | ||
"[{}] needs an identifier or an argument list.", | ||
self._name) | ||
elif F.IDENT_LIST in self._forms: | ||
pass | ||
elif F.IDENT in self._forms: | ||
_assert( | ||
len(ext_attr.values) == 1, | ||
"[{}] doesn't take an identifier list.", self._name) | ||
elif F.ARG_LIST in self._forms or F.NAMED_ARG_LIST in self._forms: | ||
_assert(False, "[{}] needs an argument list.", self._name) | ||
else: # F.NO_ARGS only | ||
_assert(False, "[{}] doesn't take an identifier.", self._name) | ||
if ext_attr.has_arguments: | ||
_assert( | ||
F.ARG_LIST in self._forms or F.NAMED_ARG_LIST in self._forms, | ||
"[{}] doesn't take an argument list.", self._name) | ||
if ext_attr.has_name: | ||
_assert(F.NAMED_ARG_LIST in self._forms, | ||
"[{}] doesn't take an named argument list.", self._name) | ||
|
||
# values | ||
if self._values: | ||
for value in ext_attr.values: | ||
_assert(value in self._values, "[{}={}] is not supported.", | ||
self._name, value) | ||
|
||
# post_validate | ||
if self._post_validate: | ||
if failure_count[0] == 0: | ||
self._post_validate(assert_, target_object, ext_attr) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.