PCH support for the global method pool (= instance and factory method
pools, combined). The methods in the global method pool are lazily
loaded from an on-disk hash table when Sema looks into its version of
the hash tables.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69989 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 3702c89..367c9f5 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -163,8 +163,8 @@
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
            bool CompleteTranslationUnit)
   : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
-    Diags(PP.getDiagnostics()),
-    SourceMgr(PP.getSourceManager()), CurContext(0), PreDeclaratorDC(0),
+    Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), 
+    ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
     CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
     GlobalNewDeleteDeclared(false), 
     CompleteTranslationUnit(CompleteTranslationUnit) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b3cb5e2..7426965 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -19,13 +19,13 @@
 #include "CXXFieldCollector.h"
 #include "SemaOverload.h"
 #include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclObjC.h"
 #include "clang/Parse/Action.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/OwningPtr.h"
-#include "clang/AST/DeclObjC.h"
 #include <string>
 #include <vector>
 
@@ -40,6 +40,7 @@
   class Decl;
   class DeclContext;
   class DeclSpec;
+  class ExternalSemaSource;
   class NamedDecl;
   class Stmt;
   class Expr;
@@ -128,6 +129,9 @@
   Diagnostic &Diags;
   SourceManager &SourceMgr;
 
+  /// \brief Source of additional semantic information.
+  ExternalSemaSource *ExternalSource;
+
   /// CurContext - This is the current declaration context of parsing.
   DeclContext *CurContext;
 
@@ -243,27 +247,17 @@
   /// unit.
   bool CompleteTranslationUnit;
 
-  /// ObjCMethodList - a linked list of methods with different signatures.
-  struct ObjCMethodList {
-    ObjCMethodDecl *Method;
-    ObjCMethodList *Next;
-    
-    ObjCMethodList() {
-      Method = 0; 
-      Next = 0;
-    }
-    ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) {
-      Method = M;
-      Next = C;
-    }
-  };
+  typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool;
+
   /// Instance/Factory Method Pools - allows efficient lookup when typechecking
   /// messages to "id". We need to maintain a list, since selectors can have
   /// differing signatures across classes. In Cocoa, this happens to be 
   /// extremely uncommon (only 1% of selectors are "overloaded").
-  llvm::DenseMap<Selector, ObjCMethodList> InstanceMethodPool;
-  llvm::DenseMap<Selector, ObjCMethodList> FactoryMethodPool;
+  MethodPool InstanceMethodPool;
+  MethodPool FactoryMethodPool;
   
+  MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance);
+
   /// Private Helper predicate to check for 'self'.
   bool isSelfExpr(Expr *RExpr);
 public:
@@ -1126,6 +1120,10 @@
   /// LookupInstanceMethodInGlobalPool - Returns the method and warns if
   /// there are multiple signatures.
   ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R);
+
+  /// LookupFactoryMethodInGlobalPool - Returns the method and warns if
+  /// there are multiple signatures.
+  ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R);
   
   /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
   void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f4014d1..05e471b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "clang/Sema/ExternalSemaSource.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
@@ -1090,8 +1091,47 @@
   return true;
 }
 
+/// \brief Read the contents of the instance and factory method pools
+/// for a given selector from external storage.
+///
+/// This routine should only be called once, when neither the instance
+/// nor the factory method pool has an entry for this selector.
+Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, 
+                                                bool isInstance) {
+  assert(ExternalSource && "We need an external AST source");
+  assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() &&
+         "Selector data already loaded into the instance method pool");
+  assert(FactoryMethodPool.find(Sel) == FactoryMethodPool.end() &&
+         "Selector data already loaded into the factory method pool");
+
+  // Read the method list from the external source.
+  std::pair<ObjCMethodList, ObjCMethodList> Methods
+    = ExternalSource->ReadMethodPool(Sel);
+  
+  if (isInstance) {
+    if (Methods.second.Method)
+      FactoryMethodPool[Sel] = Methods.second;
+    return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first;
+  } 
+
+  if (Methods.first.Method)
+    InstanceMethodPool[Sel] = Methods.first;
+
+  return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first;
+}
+
 void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
-  ObjCMethodList &Entry = InstanceMethodPool[Method->getSelector()];
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = InstanceMethodPool.find(Method->getSelector());
+  if (Pos == InstanceMethodPool.end()) {
+    if (ExternalSource && !FactoryMethodPool.count(Method->getSelector()))
+      Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/true);
+    else
+      Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(),
+                                                     ObjCMethodList())).first;
+  }
+
+  ObjCMethodList &Entry = Pos->second;
   if (Entry.Method == 0) {
     // Haven't seen a method with this selector name yet - add it.
     Entry.Method = Method;
@@ -1113,7 +1153,16 @@
 // FIXME: Finish implementing -Wno-strict-selector-match.
 ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, 
                                                        SourceRange R) {
-  ObjCMethodList &MethList = InstanceMethodPool[Sel];
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = InstanceMethodPool.find(Sel);
+  if (Pos == InstanceMethodPool.end() && !FactoryMethodPool.count(Sel)) {
+    if (ExternalSource)
+      Pos = ReadMethodPool(Sel, /*isInstance=*/true);
+    else
+      return 0;
+  }
+
+  ObjCMethodList &MethList = Pos->second;
   bool issueWarning = false;
   
   if (MethList.Method && MethList.Next) {
@@ -1134,7 +1183,17 @@
 }
 
 void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
-  ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()];
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = FactoryMethodPool.find(Method->getSelector());
+  if (Pos == FactoryMethodPool.end()) {
+    if (ExternalSource && !InstanceMethodPool.count(Method->getSelector()))
+      Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/false);
+    else
+      Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(),
+                                                    ObjCMethodList())).first;
+  }
+
+  ObjCMethodList &FirstMethod = Pos->second;
   if (!FirstMethod.Method) {
     // Haven't seen a method with this selector name yet - add it.
     FirstMethod.Method = Method;
@@ -1156,6 +1215,37 @@
   }
 }
 
+ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, 
+                                                      SourceRange R) {
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = FactoryMethodPool.find(Sel);
+  if (Pos == FactoryMethodPool.end()) {
+    if (ExternalSource && !InstanceMethodPool.count(Sel)) 
+      Pos = ReadMethodPool(Sel, /*isInstance=*/false);
+    else
+      return 0;
+  }
+
+  ObjCMethodList &MethList = Pos->second;
+  bool issueWarning = false;
+  
+  if (MethList.Method && MethList.Next) {
+    for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+      // This checks if the methods differ by size & alignment.
+      if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
+        issueWarning = true;
+  }
+  if (issueWarning && (MethList.Method && MethList.Next)) {
+    Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+    Diag(MethList.Method->getLocStart(), diag::note_using_decl)
+      << MethList.Method->getSourceRange();
+    for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+      Diag(Next->Method->getLocStart(), diag::note_also_found_decl)
+        << Next->Method->getSourceRange();
+  }
+  return MethList.Method;
+}
+
 /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods 
 /// have the property type and issue diagnostics if they don't.
 /// Also synthesize a getter/setter method if none exist (and update the
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index d48ba44..f2cd001 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -497,7 +497,7 @@
     ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
                                Sel, SourceRange(lbrac,rbrac));
     if (!Method)
-      Method = FactoryMethodPool[Sel].Method;
+      Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
     if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, 
                                   lbrac, rbrac, returnType))
       return true;
@@ -523,7 +523,7 @@
     if (!Method) {
       // If not messaging 'self', look for any factory method named 'Sel'.
       if (!isSelfExpr(RExpr)) {
-        Method = FactoryMethodPool[Sel].Method;
+        Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
         if (!Method) {
           Method = LookupInstanceMethodInGlobalPool(
                                    Sel, SourceRange(lbrac,rbrac));