Home | History | Annotate | Download | only in scripts
      1 # Copyright (C) 2013 Google Inc. All rights reserved.
      2 #
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #     * Redistributions of source code must retain the above copyright
      8 # notice, this list of conditions and the following disclaimer.
      9 #     * Redistributions in binary form must reproduce the above
     10 # copyright notice, this list of conditions and the following disclaimer
     11 # in the documentation and/or other materials provided with the
     12 # distribution.
     13 #     * Neither the name of Google Inc. nor the names of its
     14 # contributors may be used to endorse or promote products derived from
     15 # this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 """Resolve interface dependencies, producing a merged IdlDefinitions object.
     30 
     31 This library computes interface dependencies (partial interfaces and
     32 implements), reads the dependency files, and merges them to the IdlDefinitions
     33 for the main IDL file, producing an IdlDefinitions object representing the
     34 entire interface.
     35 
     36 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler#TOC-Dependency-resolution
     37 """
     38 
     39 import os.path
     40 
     41 # The following extended attributes can be applied to a dependency interface,
     42 # and are then applied to the individual members when merging.
     43 # Note that this moves the extended attribute from the interface to the member,
     44 # which changes the semantics and yields different code than the same extended
     45 # attribute on the main interface.
     46 DEPENDENCY_EXTENDED_ATTRIBUTES = set([
     47     'Conditional',
     48     'PerContextEnabled',
     49     'RuntimeEnabled',
     50 ])
     51 
     52 
     53 class InterfaceDependencyResolver(object):
     54     def __init__(self, interfaces_info, reader):
     55         """Initialize dependency resolver.
     56 
     57         Args:
     58             interfaces_info:
     59                 dict of interfaces information, from compute_dependencies.py
     60             reader:
     61                 IdlReader, used for reading dependency files
     62         """
     63         self.interfaces_info = interfaces_info
     64         self.reader = reader
     65 
     66     def resolve_dependencies(self, definitions):
     67         """Resolve dependencies, merging them into IDL definitions of main file.
     68 
     69         Dependencies consist of 'partial interface' for the same interface as
     70         in the main file, and other interfaces that this interface 'implements'.
     71         These are merged into the main IdlInterface, as the main IdlInterface
     72         implements all these members.
     73 
     74         Referenced interfaces are added to IdlDefinitions, but not merged into
     75         the main IdlInterface, as these are only referenced (their members are
     76         introspected, but not implemented in this interface).
     77 
     78         Inherited extended attributes are also added to the main IdlInterface.
     79 
     80         Modifies definitions in place by adding parsed dependencies.
     81 
     82         Args:
     83             definitions: IdlDefinitions object, modified in place
     84         """
     85         target_interface = next(definitions.interfaces.itervalues())
     86         interface_name = target_interface.name
     87         interface_info = self.interfaces_info[interface_name]
     88 
     89         if 'inherited_extended_attributes' in interface_info:
     90             target_interface.extended_attributes.update(
     91                 interface_info['inherited_extended_attributes'])
     92 
     93         merge_interface_dependencies(definitions,
     94                                      target_interface,
     95                                      interface_info['dependencies_full_paths'],
     96                                      self.reader)
     97 
     98         for referenced_interface_name in interface_info['referenced_interfaces']:
     99             referenced_definitions = self.reader.read_idl_definitions(
    100                 self.interfaces_info[referenced_interface_name]['full_path'])
    101             definitions.update(referenced_definitions)
    102 
    103 
    104 def merge_interface_dependencies(definitions, target_interface, dependency_idl_filenames, reader):
    105     """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface.
    106 
    107     No return: modifies target_interface in place.
    108     """
    109     # Sort so order consistent, so can compare output from run to run.
    110     for dependency_idl_filename in sorted(dependency_idl_filenames):
    111         dependency_definitions = reader.read_idl_file(dependency_idl_filename)
    112         dependency_interface = next(dependency_definitions.interfaces.itervalues())
    113         dependency_interface_basename, _ = os.path.splitext(os.path.basename(dependency_idl_filename))
    114 
    115         transfer_extended_attributes(dependency_interface,
    116                                      dependency_interface_basename)
    117         definitions.update(dependency_definitions)  # merges partial interfaces
    118         if not dependency_interface.is_partial:
    119             # Implemented interfaces (non-partial dependencies) are also merged
    120             # into the target interface, so Code Generator can just iterate
    121             # over one list (and not need to handle 'implements' itself).
    122             target_interface.merge(dependency_interface)
    123 
    124 
    125 def transfer_extended_attributes(dependency_interface, dependency_interface_basename):
    126     """Transfer extended attributes from dependency interface onto members.
    127 
    128     Merging consists of storing certain interface-level data in extended
    129     attributes of the *members* (because there is no separate dependency
    130     interface post-merging).
    131 
    132     The data storing consists of:
    133     * applying certain extended attributes from the dependency interface
    134       to its members
    135     * storing the C++ class of the implementation in an internal
    136       extended attribute of each member, [PartialInterfaceImplementedAs]
    137 
    138     No return: modifies dependency_interface in place.
    139     """
    140     merged_extended_attributes = dict(
    141         (key, value)
    142         for key, value in dependency_interface.extended_attributes.iteritems()
    143         if key in DEPENDENCY_EXTENDED_ATTRIBUTES)
    144 
    145     # A partial interface's members are implemented as static member functions
    146     # in a separate C++ class. This class name is stored in
    147     # [PartialInterfaceImplementedAs] which defaults to the basename of
    148     # dependency IDL file.
    149     # This class name can be overridden by [ImplementedAs] on the partial
    150     # interface definition.
    151     #
    152     # Note that implemented interfaces do *not* need [ImplementedAs], since
    153     # they are implemented on the C++ object |impl| itself, just like members of
    154     # the main interface definition, so the bindings do not need to know in
    155     # which class implemented interfaces are implemented.
    156     #
    157     # Currently [LegacyTreatAsPartialInterface] can be used to have partial
    158     # interface behavior on implemented interfaces, but this is being removed
    159     # as legacy cruft:
    160     # FIXME: Remove [LegacyTreatAsPartialInterface]
    161     # http://crbug.com/360435
    162     #
    163     # Note that [ImplementedAs] is used with different meanings on interfaces
    164     # and members:
    165     # for Blink class name and function name (or constant name), respectively.
    166     # Thus we do not want to copy this from the interface to the member, but
    167     # instead extract it and handle it separately.
    168     if (dependency_interface.is_partial or
    169         'LegacyTreatAsPartialInterface' in dependency_interface.extended_attributes):
    170         merged_extended_attributes['PartialInterfaceImplementedAs'] = (
    171             dependency_interface.extended_attributes.get(
    172                 'ImplementedAs', dependency_interface_basename))
    173 
    174     for attribute in dependency_interface.attributes:
    175         attribute.extended_attributes.update(merged_extended_attributes)
    176     for constant in dependency_interface.constants:
    177         constant.extended_attributes.update(merged_extended_attributes)
    178     for operation in dependency_interface.operations:
    179         operation.extended_attributes.update(merged_extended_attributes)
    180