Index: tools/dom/scripts/databasebuilder.py |
diff --git a/tools/dom/scripts/databasebuilder.py b/tools/dom/scripts/databasebuilder.py |
index 46c82a831bcd166a538adb9e845f44a1760b1a55..458f570ae888ed06fe73aba728d79a56ef0f13c8 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, check_dictionaries=False) |
+ |
+ for attribute in interface.attributes: |
+ self._attribute_operation(interface, attribute) |
+ self._attribute_operation(interface, attribute, check_dictionaries=False) |
+ |
+ for operation in interface.operations: |
+ self._attribute_operation(interface, operation) |
+ self._attribute_operation(interface, operation, check_dictionaries=False) |
+ |
+ # Report all dictionaries and their usage. |
+ self._output_examination() |
+ # Report all interface marked with NoInterfaceObject and their usage. |
+ self._output_examination(check_dictionaries=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, check_dictionaries=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 check_dictionaries \ |
+ else ['NoInterfaceObject', 'Used In Interface', 'Usage Operation/Attribute'] |
+ self._tabulate_title(title_bar) |
+ diags = self._diag_dictionaries if check_dictionaries else self._diag_no_interfaces |
+ for diag in diags: |
+ self._tabluate([diag['dictionary' if check_dictionaries 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, check_dictionaries=True): |
+ for diag in self._diag_dictionaries if check_dictionaries 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 check_dictionaries: |
+ 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 check_dictionaries: |
+ 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, check_dictionaries=True): |
+ if check_dictionaries: |
+ 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, check_dictionaries=True): |
+ if check_dictionaries: |
+ 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, check_dictionaries=check_dictionaries) |
+ |
+ # Scan an attribute or operation for a dictionary or interface with NoInterfaceObject |
+ # reference. |
+ def _attribute_operation(self, interface, operation_attribute, check_dictionaries=True): |
+ if check_dictionaries: |
+ 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, check_dictionaries=check_dictionaries) |
+ self._mark_usage(interface, operation_attribute, check_dictionaries=check_dictionaries) |
+ |
+ # 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, check_dictionaries=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') |