From: Douglas Gregor Date: Thu, 25 Aug 2011 14:51:20 +0000 (+0000) Subject: Use the module manager's search facility to look for methods with a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3d15ab8d0822637ff5e39594c4f34172241cad2e;p=clang Use the module manager's search facility to look for methods with a given selector, rather than walking the chain backwards. Teach its visitor how to merge multiple result sets into a single result set, combining the results of selector lookup in several different modules into a single result set. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138556 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 29bebcde28..4fab0bd2da 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -574,6 +574,8 @@ public: void *UserData); }; +class ReadMethodPoolVisitor; + } // end namespace serialization /// \brief Reads an AST files chain containing the contents of a translation @@ -608,6 +610,7 @@ public: friend class TypeLocReader; friend class ASTWriter; friend class ASTUnit; // ASTUnit needs to remap source locations. + friend class serialization::ReadMethodPoolVisitor; typedef serialization::Module Module; typedef serialization::ModuleKind ModuleKind; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index cb1498e815..9b23e9ab4f 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -487,7 +487,8 @@ class ASTSelectorLookupTrait { public: struct data_type { SelectorID ID; - ObjCMethodList Instance, Factory; + llvm::SmallVector Instance; + llvm::SmallVector Factory; }; typedef Selector external_key_type; @@ -548,37 +549,17 @@ public: // Load instance methods ObjCMethodList *Prev = 0; for (unsigned I = 0; I != NumInstanceMethods; ++I) { - ObjCMethodDecl *Method - = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d)); - if (!Result.Instance.Method) { - // This is the first method, which is the easy case. - Result.Instance.Method = Method; - Prev = &Result.Instance; - continue; - } - - ObjCMethodList *Mem = - Reader.getSema()->BumpAlloc.Allocate(); - Prev->Next = new (Mem) ObjCMethodList(Method, 0); - Prev = Prev->Next; + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) + Result.Instance.push_back(Method); } // Load factory methods Prev = 0; for (unsigned I = 0; I != NumFactoryMethods; ++I) { - ObjCMethodDecl *Method - = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d)); - if (!Result.Factory.Method) { - // This is the first method, which is the easy case. - Result.Factory.Method = Method; - Prev = &Result.Factory; - continue; - } - - ObjCMethodList *Mem = - Reader.getSema()->BumpAlloc.Allocate(); - Prev->Next = new (Mem) ObjCMethodList(Method, 0); - Prev = Prev->Next; + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) + Result.Factory.push_back(Method); } return Result; @@ -4693,32 +4674,92 @@ IdentifierIterator *ASTReader::getIdentifiers() const { return new ASTIdentifierIterator(*this); } -std::pair -ASTReader::ReadMethodPool(Selector Sel) { - // Find this selector in a hash table. We want to find the most recent entry. - for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { - Module &F = *(*I); - if (!F.SelectorLookupTable) - continue; - - ASTSelectorLookupTable *PoolTable - = (ASTSelectorLookupTable*)F.SelectorLookupTable; - ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel); - if (Pos != PoolTable->end()) { - ++NumSelectorsRead; +namespace clang { namespace serialization { + class ReadMethodPoolVisitor { + ASTReader &Reader; + Selector Sel; + llvm::SmallVector InstanceMethods; + llvm::SmallVector FactoryMethods; + + /// \brief Build an ObjCMethodList from a vector of Objective-C method + /// declarations. + ObjCMethodList + buildObjCMethodList(const SmallVectorImpl &Vec) const + { + ObjCMethodList List; + ObjCMethodList *Prev = 0; + for (unsigned I = 0, N = Vec.size(); I != N; ++I) { + if (!List.Method) { + // This is the first method, which is the easy case. + List.Method = Vec[I]; + Prev = &List; + continue; + } + + ObjCMethodList *Mem = + Reader.getSema()->BumpAlloc.Allocate(); + Prev->Next = new (Mem) ObjCMethodList(Vec[I], 0); + Prev = Prev->Next; + } + + return List; + } + + public: + ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel) + : Reader(Reader), Sel(Sel) { } + + static bool visit(Module &M, void *UserData) { + ReadMethodPoolVisitor *This + = static_cast(UserData); + + if (!M.SelectorLookupTable) + return false; + + ASTSelectorLookupTable *PoolTable + = (ASTSelectorLookupTable*)M.SelectorLookupTable; + ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); + if (Pos == PoolTable->end()) + return false; + + ++This->Reader.NumSelectorsRead; // FIXME: Not quite happy with the statistics here. We probably should // disable this tracking when called via LoadSelector. // Also, should entries without methods count as misses? - ++NumMethodPoolEntriesRead; + ++This->Reader.NumMethodPoolEntriesRead; ASTSelectorLookupTrait::data_type Data = *Pos; - if (DeserializationListener) - DeserializationListener->SelectorRead(Data.ID, Sel); - return std::make_pair(Data.Instance, Data.Factory); + if (This->Reader.DeserializationListener) + This->Reader.DeserializationListener->SelectorRead(Data.ID, + This->Sel); + + This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); + This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + return true; } - } + + /// \brief Retrieve the instance methods found by this visitor. + ObjCMethodList getInstanceMethods() const { + return buildObjCMethodList(InstanceMethods); + } + + /// \brief Retrieve the instance methods found by this visitor. + ObjCMethodList getFactoryMethods() const { + return buildObjCMethodList(FactoryMethods); + } + }; +} } // end namespace clang::serialization - ++NumMethodPoolMisses; - return std::pair(); +std::pair +ASTReader::ReadMethodPool(Selector Sel) { + ReadMethodPoolVisitor Visitor(*this, Sel); + ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); + std::pair Result; + Result.first = Visitor.getInstanceMethods(); + Result.second = Visitor.getFactoryMethods(); + + if (!Result.first.Method && !Result.second.Method) + ++NumMethodPoolMisses; + return Result; } void ASTReader::ReadKnownNamespaces( diff --git a/test/Modules/Inputs/lookup_left.h b/test/Modules/Inputs/lookup_left.h new file mode 100644 index 0000000000..01723d40aa --- /dev/null +++ b/test/Modules/Inputs/lookup_left.h @@ -0,0 +1,3 @@ +@interface A +- (int)method; +@end diff --git a/test/Modules/Inputs/lookup_right.h b/test/Modules/Inputs/lookup_right.h new file mode 100644 index 0000000000..f8f0c97d68 --- /dev/null +++ b/test/Modules/Inputs/lookup_right.h @@ -0,0 +1,5 @@ + +@interface B +- (double)method; +@end + diff --git a/test/Modules/lookup.m b/test/Modules/lookup.m new file mode 100644 index 0000000000..bdffd44b91 --- /dev/null +++ b/test/Modules/lookup.m @@ -0,0 +1,17 @@ + +// lookup_left.h: expected-note{{using}} +// lookup_right.h: expected-note{{also found}} + +void test(id x) { + [x method]; // expected-warning{{multiple methods named 'method' found}} +} + +// RUN: %clang_cc1 -emit-pch -x objective-c -o %t_lookup_left.h.pch %S/Inputs/lookup_left.h +// RUN: %clang_cc1 -emit-pch -x objective-c -o %t_lookup_right.h.pch %S/Inputs/lookup_right.h +// RUN: %clang_cc1 -x objective-c -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s +// RUN: %clang_cc1 -ast-print -x objective-c -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch %s | FileCheck -check-prefix=CHECK-PRINT %s + +// CHECK-PRINT: - (int) method; +// CHECK-PRINT: - (double) method +// CHECK-PRINT: void test(id x) +