Chromium Code Reviews| Index: tools/dom/scripts/databasebuilder.py |
| diff --git a/tools/dom/scripts/databasebuilder.py b/tools/dom/scripts/databasebuilder.py |
| index 46c82a831bcd166a538adb9e845f44a1760b1a55..e0fd71fbff35cae825c8179a0205ff451eb27aa8 100755 |
| --- a/tools/dom/scripts/databasebuilder.py |
| +++ b/tools/dom/scripts/databasebuilder.py |
| @@ -753,6 +753,7 @@ class DatabaseBuilder(object): |
| for interface in self._database.GetInterfaces(): |
| map(all_types, interface.all(IDLExtAttrFunctionValue)) |
| + map(all_types, interface.attributes) |
| map(all_types, interface.operations) |
| def fetch_constructor_data(self, options): |
| @@ -772,3 +773,220 @@ class DatabaseBuilder(object): |
| if 'V8EnabledAtRuntime' in attr.ext_attrs: |
| interface.ext_attrs['synthesizedV8EnabledAtRuntime'] = \ |
| attr.ext_attrs['V8EnabledAtRuntime'] or attr.id |
| + |
| + # Iterate of the database looking for relationships between dictionaries and |
| + # interfaces marked with NoInterfaceObject. This mechanism can be used for |
| + # other IDL analysis. |
| + def examine_database(self): |
| + # Contains list of dictionary structure: {'dictionary': dictionary, 'usages': []} |
| + self._diag_dictionaries = []; |
| + self._dictionaries_used_types = []; |
| + |
| + # Record any dictionary. |
| + for dictionary in self._database.GetDictionaries(): |
| + self._diag_dictionaries.append({'dictionary': dictionary, 'usages': []}); |
| + |
| + # Contains list of NoInterfaceObject structures: {'no_interface_object': dictionary, 'usages': []} |
| + self._diag_no_interfaces = []; |
| + self._no_interfaces_used_types = []; |
| + |
| + # Record any interface with Blink IDL Extended Attribute 'NoInterfaceObject'. |
| + for interface in self._database.GetInterfaces(): |
| + if interface.is_no_interface_object: |
| + self._diag_no_interfaces.append({'no_interface_object': interface, 'usages': []}); |
| + |
| + for interface in self._database.GetInterfaces(): |
| + self._constructors(interface) |
| + self._constructors(interface, is_dictionary=False) |
|
vsm
2015/03/13 14:58:11
Just a nit - I find the name "is_dictionary" a lit
terry
2015/03/13 15:53:31
Yes, good idea. Done.
|
| + |
| + for attribute in interface.attributes: |
| + self._attribute_operation(interface, attribute) |
| + self._attribute_operation(interface, attribute, is_dictionary=False) |
| + |
| + for operation in interface.operations: |
| + self._attribute_operation(interface, operation) |
| + self._attribute_operation(interface, operation, is_dictionary=False) |
| + |
| + # Report all dictionaries and their usage. |
| + self._output_examination() |
| + # Report all interface marked with NoInterfaceObject and their usage. |
| + self._output_examination(is_dictionary=False) |
| + |
| + print '\nKey:' |
| + print ' (READ-ONLY) - read-only attribute has relationship' |
| + print ' (GET/SET) - attribute has relationship' |
| + print ' RETURN - operation\'s returned value has relationship' |
| + print ' (ARGUMENT) - operation\'s argument(s) has relationship' |
| + |
| + print '\n\nExamination Complete\n' |
| + |
| + def _output_examination(self, is_dictionary=True): |
| + # Output diagnostics. First columns is Dictionary or NoInterfaceObject e.g., |
| + # | Dictionary | Used In Interface | Usage Operation/Attribute | |
| + print '\n\n' |
| + title_bar = ['Dictionary', 'Used In Interface', 'Usage Operation/Attribute'] if is_dictionary \ |
| + else ['NoInterfaceObject', 'Used In Interface', 'Usage Operation/Attribute'] |
| + self._tabulate_title(title_bar) |
| + diags = self._diag_dictionaries if is_dictionary else self._diag_no_interfaces |
| + for diag in diags: |
| + self._tabluate([diag['dictionary' if is_dictionary else 'no_interface_object'].id, '', '']) |
| + for usage in diag['usages']: |
| + detail = '' |
| + if 'attribute' in usage: |
| + attribute_type = 'READ-ONLY' if not usage['argument'] else 'GET/SET' |
| + detail = '(%s) %s' % (attribute_type, usage['attribute']) |
| + elif 'operation' in usage: |
| + detail = '%s %s%s' % ('RETURN' if usage['result'] else '', |
| + usage['operation'], |
| + '(ARGUMENT)' if usage['argument'] else '') |
| + self._tabluate([None, usage['interface'], detail]) |
| + self._tabulate_break() |
| + |
| + # operation_or_attribute either IDLOperation or IDLAttribute if None then |
| + # its a constructor (IDLExtAttrFunctionValue). |
| + def _mark_usage(self, interface, operation_or_attribute = None, is_dictionary=True): |
| + for diag in self._diag_dictionaries if is_dictionary else self._diag_no_interfaces: |
| + for usage in diag['usages']: |
| + if not usage['interface']: |
| + usage['interface'] = interface.id |
| + if isinstance(operation_or_attribute, IDLOperation): |
| + usage['operation'] = operation_or_attribute.id |
| + if is_dictionary: |
| + usage['result'] = hasattr(operation_or_attribute.type, 'dictionary') and \ |
| + operation_or_attribute.type.dictionary == diag['dictionary'].id |
| + else: |
| + usage['result'] = operation_or_attribute.type.id == diag['no_interface_object'].id |
| + usage['argument'] = False |
| + for argument in operation_or_attribute.arguments: |
| + if is_dictionary: |
| + arg = hasattr(argument.type, 'dictionary') and argument.type.dictionary == diag['dictionary'].id |
| + else: |
| + arg = argument.type.id == diag['no_interface_object'].id |
| + if arg: |
| + usage['argument'] = arg |
| + elif isinstance(operation_or_attribute, IDLAttribute): |
| + usage['attribute'] = operation_or_attribute.id |
| + usage['result'] = True |
| + usage['argument'] = not operation_or_attribute.is_read_only |
| + elif not operation_or_attribute: |
| + # Its a constructor only argument is dictionary or interface with NoInterfaceObject. |
| + usage['operation'] = 'constructor' |
| + usage['result'] = False |
| + usage['argument'] = True |
| + |
| + def _remember_usage(self, node, is_dictionary=True): |
| + if is_dictionary: |
| + used_types = self._dictionaries_used_types |
| + diag_list = self._diag_dictionaries |
| + diag_name = 'dictionary' |
| + else: |
| + used_types = self._no_interfaces_used_types |
| + diag_list = self._diag_no_interfaces |
| + diag_name = 'no_interface_object' |
| + |
| + if len(used_types) > 0: |
| + normalized_used = list(set(used_types)) |
| + for recorded_id in normalized_used: |
| + for diag in diag_list: |
| + if diag[diag_name].id == recorded_id: |
| + diag['usages'].append({'interface': None, 'node': node}) |
| + |
| + # Iterator function to look for any IDLType that is a dictionary then remember |
| + # that dictionary. |
| + def _dictionary_used(self, type_node): |
| + if hasattr(type_node, 'dictionary'): |
| + dictionary_id = type_node.dictionary |
| + if self._database.HasDictionary(dictionary_id): |
| + for diag_dictionary in self._diag_dictionaries: |
| + if diag_dictionary['dictionary'].id == dictionary_id: |
| + # Record the dictionary that was referenced. |
| + self._dictionaries_used_types.append(dictionary_id) |
| + return |
| + |
| + # If we get to this point, the IDL dictionary was never defined ... oops. |
| + print 'DIAGNOSE_ERROR: IDL Dictionary %s doesn\'t exist.' % dictionary_id |
| + |
| + # Iterator function to look for any IDLType that is an interface marked with |
| + # NoInterfaceObject then remember that interface. |
| + def _no_interface_used(self, type_node): |
| + if hasattr(type_node, 'id'): |
| + no_interface_id = type_node.id |
| + if self._database.HasInterface(no_interface_id): |
| + no_interface = self._database.GetInterface(no_interface_id) |
| + if no_interface.is_no_interface_object: |
| + for diag_no_interface in self._diag_no_interfaces: |
| + if diag_no_interface['no_interface_object'].id == no_interface_id: |
| + # Record the interface marked with NoInterfaceObject. |
| + self._no_interfaces_used_types.append(no_interface_id) |
| + return |
| + |
| + def _constructors(self, interface, is_dictionary=True): |
| + if is_dictionary: |
| + self._dictionaries_used_types = [] |
| + constructor_function = self._dictionary_constructor_types |
| + else: |
| + self._no_interfaces_used_types = []; |
| + constructor_function = self._no_interface_constructor_types |
| + |
| + map(constructor_function, interface.all(IDLExtAttrFunctionValue)) |
| + |
| + self._mark_usage(interface, is_dictionary=is_dictionary) |
| + |
| + # Scan an attribute or operation for a dictionary or interface with NoInterfaceObject |
| + # reference. |
| + def _attribute_operation(self, interface, operation_attribute, is_dictionary=True): |
| + if is_dictionary: |
| + self._dictionaries_used_types = [] |
| + used = self._dictionary_used |
| + else: |
| + self._no_interfaces_used_types = []; |
| + used = self._no_interface_used |
| + |
| + map(used, operation_attribute.all(IDLType)) |
| + |
| + self._remember_usage(operation_attribute, is_dictionary=is_dictionary) |
| + self._mark_usage(interface, operation_attribute, is_dictionary=is_dictionary) |
| + |
| + # Iterator function for map to iterate over all constructor types |
| + # (IDLExtAttrFunctionValue) that have a dictionary reference. |
| + def _dictionary_constructor_types(self, node): |
| + self._dictionaries_used_types = [] |
| + map(self._dictionary_used, node.all(IDLType)) |
| + self._remember_usage(node) |
| + |
| + # Iterator function for map to iterate over all constructor types |
| + # (IDLExtAttrFunctionValue) that reference an interface with NoInterfaceObject. |
| + def _no_interface_constructor_types(self, node): |
| + self._no_interfaces_used_types = []; |
| + map(self._no_interface_used, node.all(IDLType)) |
| + self._remember_usage(node, is_dictionary=False) |
| + |
| + # Maximum width of each column. |
| + def _TABULATE_WIDTH(self): |
| + return 45 |
| + |
| + def _tabulate_title(self, row_title): |
| + title_separator = "=" * self._TABULATE_WIDTH() |
| + self._tabluate([title_separator, title_separator, title_separator]) |
| + self._tabluate(row_title) |
| + self._tabluate([title_separator, title_separator, title_separator]) |
| + |
| + def _tabulate_break(self): |
| + break_separator = "-" * self._TABULATE_WIDTH() |
| + self._tabluate([break_separator, break_separator, break_separator]) |
| + |
| + def _tabluate(self, columns): |
| + """Tabulate a list of columns for a row. Each item in columns is a column |
| + value each column will be padded up to _TABULATE_WIDTH. Each |
| + column starts/ends with a vertical bar '|' the format a row: |
| + |
| + | columns[0] | columns[1] | columns[2] | ... | |
| + """ |
| + if len(columns) > 0: |
| + for column in columns: |
| + value = '' if not column else column |
| + sys.stdout.write('|{0:^{1}}'.format(value, self._TABULATE_WIDTH())) |
| + else: |
| + sys.stdout.write('|{0:^{1}}'.format('', self._TABULATE_WIDTH())) |
| + |
| + sys.stdout.write('|\n') |