<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Aug 31, 2011, at 6:27 PM, Douglas Gregor wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div><br>On Aug 31, 2011, at 5:58 PM, Argyrios Kyrtzidis wrote:<br><br><blockquote type="cite">Author: akirtzidis<br></blockquote><blockquote type="cite">Date: Wed Aug 31 19:58:55 2011<br></blockquote><blockquote type="cite">New Revision: 138926<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">URL: <a href="http://llvm.org/viewvc/llvm-project?rev=138926&view=rev">http://llvm.org/viewvc/llvm-project?rev=138926&view=rev</a><br></blockquote><blockquote type="cite">Log:<br></blockquote><blockquote type="cite">Support importing of ObjC categories from modules.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">The initial incentive was to fix a crash when PCH chaining categories<br></blockquote><blockquote type="cite">to an interface, but the fix was done in the "modules way" that I hear<br></blockquote><blockquote type="cite">is popular with the kids these days.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Each module stores the local chain of categories and we combine them<br></blockquote><blockquote type="cite">when the interface is loaded.<br></blockquote><br>Excellent!<br><br><blockquote type="cite">We also warn if non-dependent modules<br></blockquote><blockquote type="cite">introduce duplicate named categories.<br></blockquote><br>Bonus points for this one :)<br><br><blockquote type="cite">Added:<br></blockquote><blockquote type="cite">   cfe/trunk/test/Modules/objc-categories.m<br></blockquote><blockquote type="cite">   cfe/trunk/test/PCH/chain-categories.m<br></blockquote><blockquote type="cite">Modified:<br></blockquote><blockquote type="cite">   cfe/trunk/include/clang/AST/ASTMutationListener.h<br></blockquote><blockquote type="cite">   cfe/trunk/include/clang/Serialization/ASTBitCodes.h<br></blockquote><blockquote type="cite">   cfe/trunk/include/clang/Serialization/ASTReader.h<br></blockquote><blockquote type="cite">   cfe/trunk/include/clang/Serialization/ASTWriter.h<br></blockquote><blockquote type="cite">   cfe/trunk/include/clang/Serialization/Module.h<br></blockquote><blockquote type="cite">   cfe/trunk/lib/AST/DeclObjC.cpp<br></blockquote><blockquote type="cite">   cfe/trunk/lib/Serialization/ASTReader.cpp<br></blockquote><blockquote type="cite">   cfe/trunk/lib/Serialization/ASTReaderDecl.cpp<br></blockquote><blockquote type="cite">   cfe/trunk/lib/Serialization/ASTWriter.cpp<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h<br></blockquote><blockquote type="cite">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=138926&r1=138925&r2=138926&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=138926&r1=138925&r2=138926&view=diff</a><br></blockquote><blockquote type="cite">==============================================================================<br></blockquote><blockquote type="cite">--- cfe/trunk/include/clang/AST/ASTMutationListener.h (original)<br></blockquote><blockquote type="cite">+++ cfe/trunk/include/clang/AST/ASTMutationListener.h Wed Aug 31 19:58:55 2011<br></blockquote><blockquote type="cite">@@ -22,6 +22,8 @@<br></blockquote><blockquote type="cite">  class ClassTemplateSpecializationDecl;<br></blockquote><blockquote type="cite">  class FunctionDecl;<br></blockquote><blockquote type="cite">  class FunctionTemplateDecl;<br></blockquote><blockquote type="cite">+  class ObjCCategoryDecl;<br></blockquote><blockquote type="cite">+  class ObjCInterfaceDecl;<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">/// \brief An abstract interface that should be implemented by listeners<br></blockquote><blockquote type="cite">/// that want to be notified when an AST entity gets modified after its<br></blockquote><blockquote type="cite">@@ -54,6 +56,10 @@<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">  /// \brief A static data member was implicitly instantiated.<br></blockquote><blockquote type="cite">  virtual void StaticDataMemberInstantiated(const VarDecl *D) {}<br></blockquote><blockquote type="cite">+<br></blockquote><blockquote type="cite">+  /// \brief A new objc category class was added for an interface.<br></blockquote><blockquote type="cite">+  virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,<br></blockquote><blockquote type="cite">+                                            const ObjCInterfaceDecl *IFD) {}<br></blockquote><blockquote type="cite">};<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">} // end namespace clang<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h<br></blockquote><blockquote type="cite">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=138926&r1=138925&r2=138926&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=138926&r1=138925&r2=138926&view=diff</a><br></blockquote><blockquote type="cite">==============================================================================<br></blockquote><blockquote type="cite">--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)<br></blockquote><blockquote type="cite">+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed Aug 31 19:58:55 2011<br></blockquote><blockquote type="cite">@@ -64,6 +64,11 @@<br></blockquote><blockquote type="cite">    /// \brief a Decl::Kind/DeclID pair.<br></blockquote><blockquote type="cite">    typedef std::pair<uint32_t, DeclID> KindDeclIDPair;<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">+    // FIXME: Turn these into classes so we can have some type safety when<br></blockquote><blockquote type="cite">+    // we go from local ID to global and vice-versa.<br></blockquote><blockquote type="cite">+    typedef DeclID LocalDeclID;<br></blockquote><blockquote type="cite">+    typedef DeclID GlobalDeclID;<br></blockquote><blockquote type="cite">+<br></blockquote><blockquote type="cite">    /// \brief An ID number that refers to a type in an AST file.<br></blockquote><blockquote type="cite">    ///<br></blockquote><blockquote type="cite">    /// The ID of a type is partitioned into two parts: the lower<br></blockquote><blockquote type="cite">@@ -402,7 +407,11 @@<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">      /// \brief Record code for the source manager line table information,<br></blockquote><blockquote type="cite">      /// which stores information about #line directives.<br></blockquote><blockquote type="cite">-      SOURCE_MANAGER_LINE_TABLE = 48<br></blockquote><blockquote type="cite">+      SOURCE_MANAGER_LINE_TABLE = 48,<br></blockquote><blockquote type="cite">+<br></blockquote><blockquote type="cite">+      /// \brief Record code for ObjC categories in a module that are chained to<br></blockquote><blockquote type="cite">+      /// an interface.<br></blockquote><blockquote type="cite">+      OBJC_CHAINED_CATEGORIES<br></blockquote><blockquote type="cite">    };<br></blockquote><br>Is there any particular reason why you didn't just add another DeclUpdateKind, so the "add a category" updates will be handled the same way as adding a template specialization or defining an already-declared class? The DECL_UPDATES mechanism is a good, general way to deal with this sort of issue.<br></div></blockquote><div><br></div><div>Because I'm handling them specially (e.g. figuring out whether there is a need for a warning); not sure how I can adapt ObjCChainedCategoriesVisitor to work with ASTReader::loadDeclUpdateRecords.</div><br><blockquote type="cite"><div><br><blockquote type="cite">+namespace {<br></blockquote><blockquote type="cite">+  /// \brief Given an ObjC interface, goes through the modules and links to the<br></blockquote><blockquote type="cite">+  /// interface all the categories for it.<br></blockquote><blockquote type="cite">+  class ObjCChainedCategoriesVisitor {<br></blockquote><blockquote type="cite">+    ASTReader &Reader;<br></blockquote><blockquote type="cite">+    serialization::GlobalDeclID InterfaceID;<br></blockquote><blockquote type="cite">+    ObjCInterfaceDecl *Interface;<br></blockquote><blockquote type="cite">+    ObjCCategoryDecl *GlobHeadCat, *GlobTailCat;<br></blockquote><blockquote type="cite">+    llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap;<br></blockquote><blockquote type="cite">+<br></blockquote><blockquote type="cite">+  public:<br></blockquote><blockquote type="cite">+    ObjCChainedCategoriesVisitor(ASTReader &Reader,<br></blockquote><blockquote type="cite">+                                 serialization::GlobalDeclID InterfaceID,<br></blockquote><blockquote type="cite">+                                 ObjCInterfaceDecl *Interface)<br></blockquote><blockquote type="cite">+      : Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),<br></blockquote><blockquote type="cite">+        GlobHeadCat(0), GlobTailCat(0) { }<br></blockquote><blockquote type="cite">+<br></blockquote><blockquote type="cite">+    static bool visit(Module &M, void *UserData) {<br></blockquote><blockquote type="cite">+      return static_cast<ObjCChainedCategoriesVisitor *>(UserData)->visit(M);<br></blockquote><blockquote type="cite">+    }<br></blockquote><blockquote type="cite">+<br></blockquote><blockquote type="cite">+    bool visit(Module &M) {<br></blockquote><blockquote type="cite">+      if (Reader.isDeclIDFromModule(InterfaceID, M))<br></blockquote><blockquote type="cite">+        return true; // We reached the module where the interface originated<br></blockquote><blockquote type="cite">+                    // from. Stop traversing the imported modules.<br></blockquote><br>I don't think this is what you want… returning "true" stops the entire visitation, so you might end up skipping some modules that you didn't want to skip.<br></div></blockquote><div><br></div><div>This is not using ModuleManager's visitDepthFirst, it's using visit which skips only the modules that the current module imported:</div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; color: rgb(71, 144, 117); "><span style="color: #000000">  </span>/// \<span style="text-decoration: underline">param</span> Visitor A visitor function that will be invoked with each</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; color: rgb(71, 144, 117); "><span style="color: #000000">  </span>/// module and the given user data pointer. The return value must be</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; color: rgb(71, 144, 117); "><span style="color: #000000">  </span>/// convertible to <span style="text-decoration: underline">bool</span>; when false, the visitation continues to</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; color: rgb(71, 144, 117); "><span style="color: #000000">  </span>/// modules that the current module depends on. When true, the</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; color: rgb(71, 144, 117); "><span style="color: #000000">  </span>/// visitation skips any modules that the current module depends on.</div><div><br></div></div><br><blockquote type="cite"><div><br><span class="Apple-tab-span" style="white-space:pre"> </span>- Doug<br><br></div></blockquote></div><br></body></html>