Bug 918651 - part 7 - place includes intelligently in generated IPDL files; r=bent
authorNathan Froyd <froydnj@mozilla.com>
Tue, 01 Oct 2013 12:55:42 -0400
changeset 153261 15ea5898dbbda19bdd02dd7b571cf390bac22dde
parent 153260 945e157b06cbb0ad02ed9fdd1aa102d82afca482
child 153262 fa29d40a139d3687cfcfe1f090134a35c7eab8aa
push id25578
push userphilringnalda@gmail.com
push dateSun, 03 Nov 2013 21:05:48 +0000
treeherdermozilla-central@fc3414dda755 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs918651
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 918651 - part 7 - place includes intelligently in generated IPDL files; r=bent This is where the magic starts to happen. We move includes from the base protocol header (${NAME}.h) to the parent and child headers (${NAME}Parent.h and ${NAME}Child.h) to follow good include hygiene. For the base protocol header, we examine the set of types used by struct and union definitions to determine which headers we need to include. For parent and child headers, we forward declare what we can and include appropriate headers otherwise. For forward-declared types, we include the appropriate headers in the parent and child source files.
ipc/ipdl/ipdl/lower.py
widget/gonk/nsWindow.cpp
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1414,17 +1414,47 @@ class _GenerateProtocolCode(ipdl.ast.Vis
     def visitTranslationUnit(self, tu):
         hf = self.hdrfile
 
         hf.addthing(_DISCLAIMER)
         hf.addthings(_includeGuardStart(hf))
         hf.addthing(Whitespace.NL)
 
         for inc in builtinHeaderIncludes:
-            self.visitCxxInclude(inc)
+            self.visitBuiltinCxxInclude(inc)
+
+        # Compute the set of includes we need for declared structure/union
+        # classes for this protocol.
+        typesToIncludes = {}
+        for using in tu.using:
+            typestr = str(using.type.spec)
+            assert typestr not in typesToIncludes
+            typesToIncludes[typestr] = using.header
+
+        aggregateTypeIncludes = set()
+        for su in tu.structsAndUnions:
+            typedeps = _ComputeTypeDeps(su.decl.type, True)
+            if isinstance(su, ipdl.ast.StructDecl):
+                for f in su.fields:
+                    f.ipdltype.accept(typedeps)
+            elif isinstance(su, ipdl.ast.UnionDecl):
+                for c in su.components:
+                    c.ipdltype.accept(typedeps)
+
+            for typename in [t.fromtype.name for t in typedeps.usingTypedefs]:
+                if typename in typesToIncludes:
+                    aggregateTypeIncludes.add(typesToIncludes[typename])
+
+        if len(aggregateTypeIncludes) != 0:
+            hf.addthing(Whitespace.NL)
+            hf.addthings([ Whitespace("// Headers for typedefs"), Whitespace.NL ])
+
+            for headername in sorted(iter(aggregateTypeIncludes)):
+                hf.addthing(CppDirective('include', '"' + headername + '"'))
+            
         ipdl.ast.Visitor.visitTranslationUnit(self, tu)
         if tu.filetype == 'header':
             self.cppIncludeHeaders.append(_ipdlhHeaderName(tu))
 
         hf.addthing(Whitespace.NL)
         hf.addthings(_includeGuardEnd(hf))
 
         cf = self.cppfile
@@ -1441,17 +1471,17 @@ class _GenerateProtocolCode(ipdl.ast.Vis
             cf.addthing(_putInNamespaces(ns, self.protocol.namespaces))
             ns.addstmts(([ Whitespace.NL]
                          + self.funcDefns
                          +[ Whitespace.NL ]))
 
         cf.addthings(self.structUnionDefns)
 
 
-    def visitCxxInclude(self, inc):
+    def visitBuiltinCxxInclude(self, inc):
         self.hdrfile.addthing(CppDirective('include', '"'+ inc.file +'"'))
 
     def visitInclude(self, inc):
         if inc.tu.filetype == 'header':
             self.hdrfile.addthing(CppDirective(
                     'include', '"'+ _ipdlhHeaderName(inc.tu) +'.h"'))
 
     def processStructOrUnionClass(self, su, which, forwarddecls, cls):
@@ -2451,16 +2481,20 @@ class _GenerateProtocolActorCode(ipdl.as
         self.protocol = None
         self.hdrfile = None
         self.cppfile = None
         self.ns = None
         self.cls = None
         self.includedActorTypedefs = [ ]
         self.includedActorUsings = [ ]
         self.protocolCxxIncludes = [ ]
+        self.actorForwardDecls = [ ]
+        self.usingDecls = [ ]
+        self.externalIncludes = set()
+        self.nonForwardDeclaredHeaders = set()
 
     def lower(self, tu, clsname, cxxHeaderFile, cxxFile):
         self.clsname = clsname
         self.hdrfile = cxxHeaderFile
         self.cppfile = cxxFile
         tu.accept(self)
 
     def standardTypedefs(self):
@@ -2492,37 +2526,56 @@ class _GenerateProtocolActorCode(ipdl.as
                 Whitespace.NL,
                 CppDirective(
                     'include',
                     '"'+ _protocolHeaderName(tu.protocol) +'.h"')
             ])
 
         for inc in tu.includes:
             inc.accept(self)
+        for inc in tu.cxxIncludes:
+            inc.accept(self)
+
+        for using in tu.using:
+            using.accept(self)
 
         # this generates the actor's full impl in self.cls
         tu.protocol.accept(self)
 
         clsdecl, clsdefn = _splitClassDeclDefn(self.cls)
 
         # XXX damn C++ ... return types in the method defn aren't in
         # class scope
         for stmt in clsdefn.stmts:
             if isinstance(stmt, MethodDefn):
                 if stmt.decl.ret and stmt.decl.ret.name == 'Result':
                     stmt.decl.ret.name = clsdecl.name +'::'+ stmt.decl.ret.name
 
+        def setToIncludes(s):
+            return [ CppDirective('include', '"%s"' % i)
+                     for i in sorted(iter(s)) ]
+
         def makeNamespace(p, file):
             if 0 == len(p.namespaces):
                 return file
             ns = Namespace(p.namespaces[-1].name)
             outerns = _putInNamespaces(ns, p.namespaces[:-1])
             file.addthing(outerns)
             return ns
 
+        if len(self.nonForwardDeclaredHeaders) != 0:
+            self.hdrfile.addthings(
+                [ Whitespace('// Headers for things that cannot be forward declared'),
+                  Whitespace.NL ]
+                + setToIncludes(self.nonForwardDeclaredHeaders)
+                + [ Whitespace.NL ]
+            )
+        self.hdrfile.addthings(self.actorForwardDecls)
+        self.hdrfile.addthings(self.usingDecls)
+
         hdrns = makeNamespace(self.protocol, self.hdrfile)
         hdrns.addstmts([
             Whitespace.NL,
             Whitespace.NL,
             clsdecl,
             Whitespace.NL,
             Whitespace.NL
         ])
@@ -2540,18 +2593,18 @@ class _GenerateProtocolActorCode(ipdl.as
             + _includeGuardEnd(hf))
 
         # make the .cpp file
         cf.addthings([
             _DISCLAIMER,
             Whitespace.NL,
             CppDirective(
                 'include',
-                '"'+ _protocolHeaderName(self.protocol, self.side) +'.h"')
-        ])
+                '"'+ _protocolHeaderName(self.protocol, self.side) +'.h"') ]
+            + setToIncludes(self.externalIncludes))
              
         if self.protocol.decl.type.isToplevel():
             cf.addthings([
                 CppDirective('ifdef', 'MOZ_CRASHREPORTER'),
                 CppDirective('  include', '"nsXULAppAPI.h"'),
                 CppDirective('endif')
             ])
 
@@ -2569,23 +2622,42 @@ class _GenerateProtocolActorCode(ipdl.as
         cppns.addstmts([
             Whitespace.NL,
             Whitespace.NL,
             clsdefn,
             Whitespace.NL,
             Whitespace.NL
         ])
 
+    def visitUsingStmt(self, using):
+        if using.header is None:
+            return
+
+        if using.canBeForwardDeclared():
+            spec = using.type.spec
+
+            self.usingDecls.extend([
+                _makeForwardDeclForQClass(spec.baseid, spec.quals,
+                                          cls=using.isClass(),
+                                          struct=using.isStruct()),
+                Whitespace.NL
+            ])
+            self.externalIncludes.add(using.header)
+        else:
+            self.nonForwardDeclaredHeaders.add(using.header)
+
+    def visitCxxInclude(self, inc):
+        self.nonForwardDeclaredHeaders.add(inc.file)
 
     def visitInclude(self, inc):
         ip = inc.tu.protocol
         if not ip:
             return
 
-        self.hdrfile.addthings([
+        self.actorForwardDecls.extend([
             _makeForwardDeclForActor(ip.decl.type, self.side),
             Whitespace.NL
         ])
         self.protocolCxxIncludes.append(
             CppDirective(
                 'include',
                 '"%s.h"'% (_protocolHeaderName(ip, self.side))))
 
@@ -2643,18 +2715,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
         # |friend| managed actors so that they can call our Dealloc*()
         friends.update(ptype.manages)
 
         # don't friend ourself if we're a self-managed protocol
         friends.discard(ptype)
 
         for friend in friends:
-            self.hdrfile.addthings([
-                Whitespace.NL,
+            self.actorForwardDecls.extend([
                 _makeForwardDeclForActor(friend, self.prettyside),
                 Whitespace.NL
             ])
             self.cls.addstmts([
                 FriendClassDecl(_actorName(friend.fullname(),
                                            self.prettyside)),
                 Whitespace.NL ])
 
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -38,16 +38,17 @@
 #include "nsTArray.h"
 #include "nsWindow.h"
 #include "nsIWidgetListener.h"
 #include "cutils/properties.h"
 #include "ClientLayerManager.h"
 #include "BasicLayers.h"
 #include "libdisplay/GonkDisplay.h"
 #include "pixelflinger/format.h"
+#include "mozilla/BasicEvents.h"
 
 #include "HwcComposer2D.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args)
 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args)
 
 #define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)