Bug 1428535 - Part 3: Emit override specifiers in generated ipc/ipdl code. r?froydnj draft
authorChris Peterson <cpeterson@mozilla.com>
Thu, 12 Oct 2017 00:07:35 -0700
changeset 716777 703dd9bbdc85f035f36ef773dc83edca077fe6bb
parent 716776 69cdd9c3ddd1a8c8499b9484e31ae787b857fbae
child 745092 154dc8b995d385dd9de10b2613fe817934ff8bda
push id94499
push usercpeterson@mozilla.com
push dateSat, 06 Jan 2018 08:56:35 +0000
reviewersfroydnj
bugs1428535
milestone59.0a1
Bug 1428535 - Part 3: Emit override specifiers in generated ipc/ipdl code. r?froydnj TBD: I made visitMethodDecl requiresvirtual=1 if override=1 (for consistency with its virtual and pure parameters), even though the method only emits `virtual` xor `override`. However, this makes the caller code more verbose. Should we consolidate the virtual, override, pure, and static parameters into one method type enum? Something like separate values like VIRTUAL, PURE_VIRTUAL, VIRTUAL_OVERRIDE, and STATIC. MozReview-Commit-ID: 2mpQcRKzfCo
ipc/ipdl/ipdl/cxx/ast.py
ipc/ipdl/ipdl/cxx/cgen.py
ipc/ipdl/ipdl/lower.py
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -466,20 +466,22 @@ class FriendClassDecl(Node):
     def __init__(self, friend):
         Node.__init__(self)
         self.friend = friend
 
 class MethodDecl(Node):
     def __init__(self, name, params=[ ], ret=Type('void'),
                  virtual=0, const=0, pure=0, static=0, warn_unused=0,
                  inline=0, force_inline=0, never_inline=0,
-                 typeop=None,
+                 typeop=None, override=0,
                  T=None):
         assert not (virtual and static)
         assert not pure or virtual      # pure => virtual
+        assert not override or virtual  # override => virtual
+        assert not (override and pure)
         assert not (static and typeop)
         assert not (name and typeop)
         assert name is None or isinstance(name, str)
         assert not isinstance(ret, list)
         for decl in params:  assert not isinstance(decl, str)
         assert not isinstance(T, int)
         assert not (inline and never_inline)
         assert not (force_inline and never_inline)
@@ -489,16 +491,17 @@ class MethodDecl(Node):
 
         Node.__init__(self)
         self.name = name
         self.params = params            # [ Param ]
         self.ret = ret                  # Type or None
         self.virtual = virtual          # bool
         self.const = const              # bool
         self.pure = pure                # bool
+        self.override = override        # bool
         self.static = static            # bool
         self.warn_unused = warn_unused  # bool
         self.force_inline = (force_inline or T) # bool
         self.inline = inline            # bool
         self.never_inline = never_inline # bool
         self.typeop = typeop            # Type or None
         self.T = T                      # Type or None
         self.only_for_definition = False
@@ -506,16 +509,17 @@ class MethodDecl(Node):
     def __deepcopy__(self, memo):
         return MethodDecl(
             self.name,
             params=copy.deepcopy(self.params, memo),
             ret=copy.deepcopy(self.ret, memo),
             virtual=self.virtual,
             const=self.const,
             pure=self.pure,
+            override=self.override,
             static=self.static,
             warn_unused=self.warn_unused,
             inline=self.inline,
             force_inline=self.force_inline,
             never_inline=self.never_inline,
             typeop=copy.deepcopy(self.typeop, memo),
             T=copy.deepcopy(self.T, memo))
 
@@ -550,17 +554,17 @@ class ConstructorDecl(MethodDecl):
                                self.explicit)
 
 class ConstructorDefn(MethodDefn):
     def __init__(self, decl, memberinits=[ ]):
         MethodDefn.__init__(self, decl)
         self.memberinits = memberinits
 
 class DestructorDecl(MethodDecl):
-    def __init__(self, name, virtual=0, force_inline=0, inline=0):
+    def __init__(self, name, virtual=0, override=0, force_inline=0, inline=0):
         MethodDecl.__init__(self, name, params=[ ], ret=None,
                             virtual=virtual,
                             force_inline=force_inline, inline=inline)
 
     def __deepcopy__(self, memo):
         return DestructorDecl(self.name,
                               virtual=self.virtual,
                               force_inline=self.force_inline,
--- a/ipc/ipdl/ipdl/cxx/cgen.py
+++ b/ipc/ipdl/ipdl/cxx/cgen.py
@@ -187,33 +187,36 @@ class CxxCodeGen(CodePrinter, Visitor):
         inh.type.accept(self)
 
     def visitFriendClassDecl(self, fcd):
         self.printdentln('friend class '+ fcd.friend +';')
 
 
     def visitMethodDecl(self, md):
         assert not (md.static and md.virtual)
+        assert not (md.override and md.pure)
+        assert not md.pure or md.virtual        # pure => virtual
+        assert not md.override or md.virtual    # override => virtual
 
         if md.T:
             self.write('template<')
             self.write('typename ')
             md.T.accept(self)
             self.println('>')
             self.printdent()
 
         if md.warn_unused:
             self.write('MOZ_MUST_USE ')
         if md.inline:
             self.write('inline ')
         if md.never_inline:
             self.write('MOZ_NEVER_INLINE ')
         if md.static:
             self.write('static ')
-        if md.virtual:
+        if md.virtual and not md.override:
             self.write('virtual ')
         if md.ret:
             if md.only_for_definition:
                 self.write('auto ')
             else:
                 md.ret.accept(self)
                 self.println()
                 self.printdent()
@@ -227,16 +230,19 @@ class CxxCodeGen(CodePrinter, Visitor):
         self.writeDeclList(md.params)
         self.write(')')
 
         if md.const:
             self.write(' const')
         if md.ret and md.only_for_definition:
             self.write(' -> ')
             md.ret.accept(self)
+
+        if md.override:
+            self.write(' override')
         if md.pure:
             self.write(' = 0')
 
 
     def visitMethodDefn(self, md):
         if md.decl.pure:
             return
 
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -2782,33 +2782,33 @@ class _GenerateProtocolActorCode(ipdl.as
         ])
 
         if ptype.isToplevel():
             # void ProcessingError(code); default to no-op
             processingerror = MethodDefn(
                 MethodDecl(p.processingErrorVar().name,
                            params=[ Param(_Result.Type(), 'aCode'),
                                     Param(Type('char', const=1, ptr=1), 'aReason') ],
-                           virtual=1))
+                           virtual=1, override=1))
 
             # bool ShouldContinueFromReplyTimeout(); default to |true|
             shouldcontinue = MethodDefn(
                 MethodDecl(p.shouldContinueFromTimeoutVar().name,
-                           ret=Type.BOOL, virtual=1))
+                           ret=Type.BOOL, virtual=1, override=1))
             shouldcontinue.addstmt(StmtReturn.TRUE)
 
             # void Entered*()/Exited*(); default to no-op
             entered = MethodDefn(
-                MethodDecl(p.enteredCxxStackVar().name, virtual=1))
+                MethodDecl(p.enteredCxxStackVar().name, virtual=1, override=1))
             exited = MethodDefn(
-                MethodDecl(p.exitedCxxStackVar().name, virtual=1))
+                MethodDecl(p.exitedCxxStackVar().name, virtual=1, override=1))
             enteredcall = MethodDefn(
-                MethodDecl(p.enteredCallVar().name, virtual=1))
+                MethodDecl(p.enteredCallVar().name, virtual=1, override=1))
             exitedcall = MethodDefn(
-                MethodDecl(p.exitedCallVar().name, virtual=1))
+                MethodDecl(p.exitedCallVar().name, virtual=1, override=1))
 
             self.cls.addstmts([ processingerror,
                                 shouldcontinue,
                                 entered, exited,
                                 enteredcall, exitedcall,
                                 Whitespace.NL ])
 
         self.cls.addstmts((
@@ -2943,17 +2943,17 @@ class _GenerateProtocolActorCode(ipdl.as
             self.cls.addstmts(self.implementManagerIface())
 
         def makeHandlerMethod(name, switch, hasReply, dispatches=0):
             params = [ Decl(Type('Message', const=1, ref=1), msgvar.name) ]
             if hasReply:
                 params.append(Decl(Type('Message', ref=1, ptr=1),
                                    replyvar.name))
 
-            method = MethodDefn(MethodDecl(name, virtual=True,
+            method = MethodDefn(MethodDecl(name, virtual=1, override=1,
                                            params=params, ret=_Result.Type()))
 
             if not switch:
               crash = StmtExpr(ExprCall(ExprVar('MOZ_ASSERT_UNREACHABLE'),
                                args=[ExprLiteral.String('message protocol not supported')]))
               method.addstmts([crash, StmtReturn(_Result.NotKnown)])
               return method
 
@@ -3023,34 +3023,34 @@ class _GenerateProtocolActorCode(ipdl.as
 
         destroysubtreevar = ExprVar('DestroySubtree')
         deallocsubtreevar = ExprVar('DeallocSubtree')
         deallocshmemvar = ExprVar('DeallocShmems')
         deallocselfvar = ExprVar('Dealloc' + _actorName(ptype.name(), self.side))
 
         # int32_t GetProtocolTypeId() { return PFoo; }
         gettypetag = MethodDefn(
-            MethodDecl('GetProtocolTypeId', ret=_actorTypeTagType()))
+            MethodDecl('GetProtocolTypeId', ret=_actorTypeTagType(), virtual=1, override=1))
         gettypetag.addstmt(StmtReturn(_protocolId(ptype)))
         self.cls.addstmts([ gettypetag, Whitespace.NL ])
 
         if ptype.isToplevel():
             # OnChannelClose()
-            onclose = MethodDefn(MethodDecl('OnChannelClose'))
+            onclose = MethodDefn(MethodDecl('OnChannelClose', virtual=1, override=1))
             onclose.addstmts([
                 StmtExpr(ExprCall(destroysubtreevar,
                                   args=[ _DestroyReason.NormalShutdown ])),
                 StmtExpr(ExprCall(deallocsubtreevar)),
                 StmtExpr(ExprCall(deallocshmemvar)),
                 StmtExpr(ExprCall(deallocselfvar))
             ])
             self.cls.addstmts([ onclose, Whitespace.NL ])
 
             # OnChannelError()
-            onerror = MethodDefn(MethodDecl('OnChannelError'))
+            onerror = MethodDefn(MethodDecl('OnChannelError', virtual=1, override=1))
             onerror.addstmts([
                 StmtExpr(ExprCall(destroysubtreevar,
                                   args=[ _DestroyReason.AbnormalShutdown ])),
                 StmtExpr(ExprCall(deallocsubtreevar)),
                 StmtExpr(ExprCall(deallocshmemvar)),
                 StmtExpr(ExprCall(deallocselfvar))
             ])
             self.cls.addstmts([ onerror, Whitespace.NL ])
@@ -3074,17 +3074,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
         ## private methods
         self.cls.addstmt(Label.PRIVATE)
 
         ## ProtocolName()
         actorname = _actorName(p.name, self.side)
         protocolname = MethodDefn(MethodDecl(
             'ProtocolName', params=[],
-            const=1, virtual=1, ret=Type('char', const=1, ptr=1)))
+            const=1, virtual=1, override=1, ret=Type('char', const=1, ptr=1)))
         protocolname.addstmts([
             StmtReturn(ExprLiteral.String(actorname))
         ])
         self.cls.addstmts([ protocolname, Whitespace.NL ])
 
         ## DestroySubtree(bool normal)
         whyvar = ExprVar('why')
         subtreewhyvar = ExprVar('subtreewhy')
@@ -3237,23 +3237,23 @@ class _GenerateProtocolActorCode(ipdl.as
         ithkid = ExprIndex(kidsvar, ivar)
 
         methods = []
 
         if p.decl.type.isToplevel():
             getchannel = MethodDefn(MethodDecl(
                 p.getChannelMethod().name,
                 ret=Type('MessageChannel', ptr=1),
-                virtual=1))
+                virtual=1, override=1))
             getchannel.addstmt(StmtReturn(ExprAddrOf(p.channelVar())))
 
             getchannelconst = MethodDefn(MethodDecl(
                 p.getChannelMethod().name,
                 ret=Type('MessageChannel', ptr=1, const=1),
-                virtual=1, const=1))
+                virtual=1, override=1, const=1))
             getchannelconst.addstmt(StmtReturn(ExprAddrOf(p.channelVar())))
 
             methods += [ getchannel,
                          getchannelconst ]
 
         if p.decl.type.isToplevel():
             tmpvar = ExprVar('tmp')
 
@@ -3291,17 +3291,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
         # all protocols share the "same" RemoveManagee() implementation
         pvar = ExprVar('aProtocolId')
         listenervar = ExprVar('aListener')
         removemanagee = MethodDefn(MethodDecl(
             p.removeManageeMethod().name,
             params=[ Decl(_protocolIdType(), pvar.name),
                      Decl(protocolbase, listenervar.name) ],
-            virtual=1))
+            virtual=1, override=1))
 
         if not len(p.managesStmts):
             removemanagee.addstmts([ _fatalError('unreached'), StmtReturn() ])
         else:
             switchontype = StmtSwitch(pvar)
             for managee in p.managesStmts:
                 case = StmtBlock()
                 actorvar = ExprVar('actor')
@@ -4888,16 +4888,17 @@ methodDefns."""
             defns.addstmts([ defn, Whitespace.NL ])
 
     return cls, defns
 
 def _splitMethodDefn(md, clsname):
     saveddecl = deepcopy(md.decl)
     md.decl.name = (clsname +'::'+ md.decl.name)
     md.decl.virtual = 0
+    md.decl.override = 0
     md.decl.static = 0
     md.decl.warn_unused = 0
     md.decl.never_inline = 0
     md.decl.only_for_definition = True
     for param in md.decl.params:
         if isinstance(param, Param):
             param.default = None
     return saveddecl, md