Speed-up ObjCMethodDecl::getOverriddenMethods().

Use an newly introduce ASTContext::getBaseObjCCategoriesAfterInterface() which caches its
results instead of re-calculating the categories multiple times.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179436 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index d4878a9..6a03eef 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -328,6 +328,10 @@
   typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
   llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
 
+  /// \brief Used to cache results from \c getBaseObjCCategoriesAfterInterface.
+  mutable llvm::DenseMap<const ObjCInterfaceDecl *,
+            llvm::SmallVector<const ObjCCategoryDecl *, 2> > CatsAfterInterface;
+
   /// \brief Mapping from each declaration context to its corresponding lambda 
   /// mangling context.
   llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
@@ -682,7 +686,12 @@
   void getOverriddenMethods(
                         const NamedDecl *Method,
                         SmallVectorImpl<const NamedDecl *> &Overridden) const;
-  
+
+  /// \brief Returns the ObjC categories of base classes, that were declared
+  /// after the given interface declaration.
+  void getBaseObjCCategoriesAfterInterface(const ObjCInterfaceDecl *D,
+                         SmallVectorImpl<const ObjCCategoryDecl *> &Cats) const;
+
   /// \brief Notify the AST context that a new import declaration has been
   /// parsed or implicitly created within this translation unit.
   void addedLocalImportDecl(ImportDecl *Import);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 170cc02..8ede90d 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1127,8 +1127,8 @@
   assert(D);
 
   if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
-    Overridden.append(CXXMethod->begin_overridden_methods(),
-                      CXXMethod->end_overridden_methods());
+    Overridden.append(overridden_methods_begin(CXXMethod),
+                      overridden_methods_end(CXXMethod));
     return;
   }
 
@@ -1141,6 +1141,39 @@
   Overridden.append(OverDecls.begin(), OverDecls.end());
 }
 
+void ASTContext::getBaseObjCCategoriesAfterInterface(
+                        const ObjCInterfaceDecl *D,
+                        SmallVectorImpl<const ObjCCategoryDecl *> &Cats) const {
+  if (!D)
+    return;
+  
+  typedef llvm::SmallVector<const ObjCCategoryDecl *, 2> VecTy;
+  typedef llvm::DenseMap<const ObjCInterfaceDecl *, VecTy> MapTy;
+  
+  std::pair<MapTy::iterator, bool>
+    InsertOp = CatsAfterInterface.insert(std::make_pair(D, VecTy()));
+  VecTy &Vec = InsertOp.first->second;
+  if (!InsertOp.second) {
+    // already in map.
+    Cats.append(Vec.begin(), Vec.end());
+    return;
+  }
+  
+  SourceLocation Loc = D->getLocation();
+  for (const ObjCInterfaceDecl *
+         Class = D->getSuperClass(); Class; Class = Class->getSuperClass()) {
+    for (ObjCInterfaceDecl::known_categories_iterator
+           CatI = Class->known_categories_begin(),
+           CatEnd = Class->known_categories_end();
+         CatI != CatEnd; ++CatI) {
+      if (SourceMgr.isBeforeInTranslationUnit(Loc, CatI->getLocation()))
+        Vec.push_back(*CatI);
+    }
+  }
+
+  Cats.append(Vec.begin(), Vec.end());
+}
+
 void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
   assert(!Import->NextLocalImport && "Import declaration already in the chain");
   assert(!Import->isFromASTFile() && "Non-local import declaration");
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 5f5ba52..1fe262c 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -959,26 +959,6 @@
   }
 }
 
-static void collectOnCategoriesAfterLocation(SourceLocation Loc,
-                                             const ObjCInterfaceDecl *Class,
-                                             SourceManager &SM,
-                                             const ObjCMethodDecl *Method,
-                             SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
-  if (!Class)
-    return;
-
-  for (ObjCInterfaceDecl::known_categories_iterator
-         Cat = Class->known_categories_begin(),
-         CatEnd = Class->known_categories_end();
-       Cat != CatEnd; ++Cat) {
-    if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation()))
-      CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true);
-  }
-  
-  collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
-                                   Method, Methods);
-}
-
 /// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
 /// returns false.
 /// You'd think that in that case there are no overrides but categories can
@@ -988,7 +968,7 @@
 /// further in super classes.
 /// Methods in an implementation can overide methods in super class's category
 /// but not in current class's category. But, such methods
-static void collectOverriddenMethodsFast(SourceManager &SM,
+static void collectOverriddenMethodsFast(ASTContext &Ctx,
                                          const ObjCMethodDecl *Method,
                              SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
   assert(!Method->isOverriding());
@@ -1001,8 +981,11 @@
   if (!Class)
     return;
 
-  collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
-                                   SM, Method, Methods);
+  SmallVector<const ObjCCategoryDecl *, 32> Cats;
+  Ctx.getBaseObjCCategoriesAfterInterface(Class, Cats);
+  for (SmallVectorImpl<const ObjCCategoryDecl *>::iterator
+         I = Cats.begin(), E = Cats.end(); I != E; ++I)
+    CollectOverriddenMethodsRecurse(*I, Method, Methods, true);
 }
 
 void ObjCMethodDecl::getOverriddenMethods(
@@ -1015,8 +998,7 @@
   }
 
   if (!Method->isOverriding()) {
-    collectOverriddenMethodsFast(getASTContext().getSourceManager(),
-                                 Method, Overridden);
+    collectOverriddenMethodsFast(getASTContext(), Method, Overridden);
   } else {
     collectOverriddenMethodsSlow(Method, Overridden);
     assert(!Overridden.empty() &&