mirror of
https://github.com/dart-lang/sdk
synced 2024-09-21 07:41:39 +00:00
Added --examine to produce analysis of IDL files
Reviewers=vsm@google.com,alan@google.com R=vsm@google.com Review URL: https://codereview.chromium.org//1001983003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44467 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
d322d386db
commit
5c84e1b473
|
@ -233,6 +233,9 @@ def main():
|
|||
parser.add_option('--verbose', dest='logging_level',
|
||||
action='store_false', default=logging.WARNING,
|
||||
help='Output all informational messages')
|
||||
parser.add_option('--examine', dest='examine_idls',
|
||||
action='store_true', default=None,
|
||||
help='Analyze IDL files')
|
||||
parser.add_option('--logging', dest='logging', type='int',
|
||||
action='store', default=logging.NOTSET,
|
||||
help='Level of logging 20 is Info, 30 is Warnings, 40 is Errors')
|
||||
|
@ -263,7 +266,7 @@ def main():
|
|||
UpdateCssProperties()
|
||||
|
||||
# Parse the IDL and create the database.
|
||||
database = fremontcutbuilder.main(options.parallel, logging_level=logging_level)
|
||||
database = fremontcutbuilder.main(options.parallel, logging_level=logging_level, examine_idls=options.examine_idls)
|
||||
|
||||
GenerateFromDatabase(database, dart2js_output_dir, dartium_output_dir,
|
||||
options.update_dom_metadata, logging_level)
|
||||
|
|
|
@ -275,6 +275,13 @@ class Database(object):
|
|||
raise RuntimeError('Dictionary %s already exists' % dictionary_name)
|
||||
self._all_dictionaries[dictionary_name] = dictionary
|
||||
|
||||
def GetDictionaries(self):
|
||||
"""Returns a list of all loaded dictionaries."""
|
||||
res = []
|
||||
for _, dictionary in sorted(self._all_dictionaries.items()):
|
||||
res.append(dictionary)
|
||||
return res
|
||||
|
||||
def TransitiveSecondaryParents(self, interface, propagate_event_target):
|
||||
"""Returns a list of all non-primary parents.
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -36,7 +36,7 @@ FEATURE_DEFINES = [
|
|||
]
|
||||
|
||||
def build_database(idl_files, database_dir, feature_defines=None,
|
||||
logging_level=logging.WARNING):
|
||||
logging_level=logging.WARNING, examine_idls=False):
|
||||
"""This code reconstructs the FremontCut IDL database from W3C,
|
||||
WebKit and Dart IDL files."""
|
||||
current_dir = os.path.dirname(__file__)
|
||||
|
@ -98,6 +98,11 @@ def build_database(idl_files, database_dir, feature_defines=None,
|
|||
# Map any IDL defined dictionaries to Dictionary.
|
||||
builder.map_dictionaries()
|
||||
|
||||
# Examine all IDL and produce a diagnoses of areas (e.g., list dictionaries
|
||||
# declared and usage, etc.)
|
||||
if examine_idls:
|
||||
builder.examine_database()
|
||||
|
||||
conditionals_met = set(
|
||||
'ENABLE_' + conditional for conditional in builder.conditionals_met)
|
||||
known_conditionals = set(FEATURE_DEFINES + FEATURE_DISABLED)
|
||||
|
@ -116,12 +121,9 @@ def build_database(idl_files, database_dir, feature_defines=None,
|
|||
|
||||
print 'Merging interfaces %s seconds' % round(time.time() - start_time, 2)
|
||||
|
||||
# TODO(terry): Don't generate the database cache.
|
||||
# db.Save()
|
||||
|
||||
return db
|
||||
|
||||
def main(parallel=False, logging_level=logging.WARNING):
|
||||
def main(parallel=False, logging_level=logging.WARNING, examine_idls=False):
|
||||
current_dir = os.path.dirname(__file__)
|
||||
|
||||
idl_files = []
|
||||
|
@ -167,7 +169,7 @@ def main(parallel=False, logging_level=logging.WARNING):
|
|||
|
||||
database_dir = os.path.join(current_dir, '..', 'database')
|
||||
|
||||
return build_database(idl_files, database_dir, logging_level=logging_level)
|
||||
return build_database(idl_files, database_dir, logging_level=logging_level, examine_idls=examine_idls)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
|
|
@ -508,6 +508,7 @@ class IDLExtAttrs(IDLDictNode):
|
|||
return self.values()
|
||||
|
||||
|
||||
# IDLExtAttrFunctionValue is used for constructors defined in the IDL.
|
||||
class IDLExtAttrFunctionValue(IDLNode):
|
||||
"""IDLExtAttrFunctionValue."""
|
||||
def __init__(self, func_value_ast, arg_list_ast, is_blink=False):
|
||||
|
|
Loading…
Reference in a new issue