Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / scripts / interface_dependency_resolver.py
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, component):
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             component:
85                 string, describing where the above definitions are defined,
86                 'core' or 'modules'. See KNOWN_COMPONENTS in utilities.py
87
88         Returns:
89             A dictionary whose key is component and value is IdlDefinitions
90             object whose dependency is resolved.
91
92         Raises:
93             Exception:
94                 A given IdlDefinitions object doesn't have any interfaces,
95                 or a given IdlDefinitions object has incorrect referenced
96                 interfaces.
97         """
98         # FIXME: we need to resolve dependency when we implement partial
99         # dictionary.
100         if not definitions.interfaces:
101             raise Exception('No need to resolve any dependencies of '
102                             'this definition: %s, because this should '
103                             'have a dictionary.' % definitions.idl_name)
104
105         target_interface = next(definitions.interfaces.itervalues())
106         interface_name = target_interface.name
107         interface_info = self.interfaces_info[interface_name]
108
109         if 'inherited_extended_attributes' in interface_info:
110             target_interface.extended_attributes.update(
111                 interface_info['inherited_extended_attributes'])
112
113         resolved_definitions = merge_interface_dependencies(
114             definitions,
115             component,
116             target_interface,
117             interface_info['dependencies_full_paths'],
118             self.reader)
119
120         for referenced_interface_name in interface_info['referenced_interfaces']:
121             referenced_definitions = self.reader.read_idl_definitions(
122                 self.interfaces_info[referenced_interface_name]['full_path'])
123
124             if component not in referenced_definitions:
125                 raise Exception('This definitions: %s is defined in %s '
126                                 'but reference interface:%s is not defined '
127                                 'in %s' % (definitions.idl_name,
128                                            component,
129                                            referenced_interface_name,
130                                            component))
131
132             resolved_definitions[component].update(referenced_definitions[component])
133         return resolved_definitions
134
135
136 def merge_interface_dependencies(definitions, component, target_interface, dependency_idl_filenames, reader):
137     """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface.
138
139     No return: modifies target_interface in place.
140     """
141     # Sort so order consistent, so can compare output from run to run.
142     for dependency_idl_filename in sorted(dependency_idl_filenames):
143         dependency_definitions = reader.read_idl_file(dependency_idl_filename)
144         # FIXME(crbug.com/358074): should not merge core definitions with
145         # modules definitions.
146         dependency_interface = next(dependency_definitions.interfaces.itervalues())
147         dependency_interface_basename, _ = os.path.splitext(os.path.basename(dependency_idl_filename))
148
149         transfer_extended_attributes(dependency_interface,
150                                      dependency_interface_basename)
151         definitions.update(dependency_definitions)  # merges partial interfaces
152         if not dependency_interface.is_partial:
153             # Implemented interfaces (non-partial dependencies) are also merged
154             # into the target interface, so Code Generator can just iterate
155             # over one list (and not need to handle 'implements' itself).
156             target_interface.merge(dependency_interface)
157
158     # FIXME: Currently, this function just returns one IdlDefinitions
159     # instance. However, for partial interface modularization, we need to
160     # make this function return multiple definitions, i.e.
161     # { 'core': ..., 'modules': ... }.
162     return {component: definitions}
163
164
165 def transfer_extended_attributes(dependency_interface, dependency_interface_basename):
166     """Transfer extended attributes from dependency interface onto members.
167
168     Merging consists of storing certain interface-level data in extended
169     attributes of the *members* (because there is no separate dependency
170     interface post-merging).
171
172     The data storing consists of:
173     * applying certain extended attributes from the dependency interface
174       to its members
175     * storing the C++ class of the implementation in an internal
176       extended attribute of each member, [PartialInterfaceImplementedAs]
177
178     No return: modifies dependency_interface in place.
179     """
180     merged_extended_attributes = dict(
181         (key, value)
182         for key, value in dependency_interface.extended_attributes.iteritems()
183         if key in DEPENDENCY_EXTENDED_ATTRIBUTES)
184
185     # A partial interface's members are implemented as static member functions
186     # in a separate C++ class. This class name is stored in
187     # [PartialInterfaceImplementedAs] which defaults to the basename of
188     # dependency IDL file.
189     # This class name can be overridden by [ImplementedAs] on the partial
190     # interface definition.
191     #
192     # Note that implemented interfaces do *not* need [ImplementedAs], since
193     # they are implemented on the C++ object |impl| itself, just like members of
194     # the main interface definition, so the bindings do not need to know in
195     # which class implemented interfaces are implemented.
196     #
197     # Currently [LegacyTreatAsPartialInterface] can be used to have partial
198     # interface behavior on implemented interfaces, but this is being removed
199     # as legacy cruft:
200     # FIXME: Remove [LegacyTreatAsPartialInterface]
201     # http://crbug.com/360435
202     #
203     # Note that [ImplementedAs] is used with different meanings on interfaces
204     # and members:
205     # for Blink class name and function name (or constant name), respectively.
206     # Thus we do not want to copy this from the interface to the member, but
207     # instead extract it and handle it separately.
208     if (dependency_interface.is_partial or
209         'LegacyTreatAsPartialInterface' in dependency_interface.extended_attributes):
210         merged_extended_attributes['PartialInterfaceImplementedAs'] = (
211             dependency_interface.extended_attributes.get(
212                 'ImplementedAs', dependency_interface_basename))
213
214     for attribute in dependency_interface.attributes:
215         attribute.extended_attributes.update(merged_extended_attributes)
216     for constant in dependency_interface.constants:
217         constant.extended_attributes.update(merged_extended_attributes)
218     for operation in dependency_interface.operations:
219         operation.extended_attributes.update(merged_extended_attributes)