From: Douglas Gregor Date: Tue, 6 Apr 2010 17:30:22 +0000 (+0000) Subject: Make code-completion for Objective-C message sends to "id" work in the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=719770dcfcb3987e8a2377dcca97955301445eb5;p=clang Make code-completion for Objective-C message sends to "id" work in the presence of precompiled headers by forcibly loading all of the methods we know about from the PCH file before constructing our code-completion list. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100535 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index b8d80bc897..79e44511d3 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -66,6 +66,13 @@ public: /// building a new declaration. virtual Decl *GetDecl(uint32_t ID) = 0; + /// \brief Resolve a selector ID into a selector. + virtual Selector GetSelector(uint32_t ID) = 0; + + /// \brief Returns the number of selectors known to the external AST + /// source. + virtual uint32_t GetNumKnownSelectors() = 0; + /// \brief Resolve the offset of a statement in the decl stream into a /// statement. /// diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 73c1bf4cce..e324228e92 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -688,6 +688,9 @@ public: Selector DecodeSelector(unsigned Idx); + virtual Selector GetSelector(uint32_t ID); + virtual uint32_t GetNumKnownSelectors(); + Selector GetSelector(const RecordData &Record, unsigned &Idx) { return DecodeSelector(Record[Idx++]); } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index b96c04d0a8..41e06661fa 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2843,6 +2843,14 @@ Selector PCHReader::DecodeSelector(unsigned ID) { return SelectorsLoaded[Index]; } +Selector PCHReader::GetSelector(uint32_t ID) { + return DecodeSelector(ID); +} + +uint32_t PCHReader::GetNumKnownSelectors() { + return TotalNumSelectors + 1; +} + DeclarationName PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index d29cab4ca1..ac56fab9e8 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,6 +13,7 @@ #include "Sema.h" #include "Lookup.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" @@ -2977,13 +2978,26 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, else if (FName->isStr("id")) { // We're messaging "id" as a type; provide all class/factory methods. - // FIXME: Load the entire class method pool from the PCH file + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N; + ++I) { + Selector Sel = ExternalSource->GetSelector(I); + if (Sel.isNull() || FactoryMethodPool.count(Sel) || + InstanceMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, /*isInstance=*/false); + } + } + for (llvm::DenseMap::iterator M = FactoryMethodPool.begin(), MEnd = FactoryMethodPool.end(); M != MEnd; ++M) { - for (ObjCMethodList *MethList = &M->second; MethList; + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; MethList = MethList->Next) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) @@ -3056,13 +3070,29 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } // Handle messages to "id". else if (ReceiverType->isObjCIdType()) { - // FIXME: Load the entire instance method pool from the PCH file + // We're messaging "id", so provide all instance methods we know + // about as code-completion results. + + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N; + ++I) { + Selector Sel = ExternalSource->GetSelector(I); + if (Sel.isNull() || InstanceMethodPool.count(Sel) || + FactoryMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, /*isInstance=*/true); + } + } + for (llvm::DenseMap::iterator M = InstanceMethodPool.begin(), MEnd = InstanceMethodPool.end(); M != MEnd; ++M) { - for (ObjCMethodList *MethList = &M->second; MethList; + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; MethList = MethList->Next) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) diff --git a/test/Index/Inputs/complete-pch.h b/test/Index/Inputs/complete-pch.h new file mode 100644 index 0000000000..ddf5253c13 --- /dev/null +++ b/test/Index/Inputs/complete-pch.h @@ -0,0 +1,10 @@ +@interface A +- (int)instanceMethod1:(int)x; ++ (int)classMethod1:(double)d; +@end + +@interface B +- (int)instanceMethod2:(int)x; ++ (int)classMethod2:(float)f; +@end + diff --git a/test/Index/complete-pch.m b/test/Index/complete-pch.m new file mode 100644 index 0000000000..09192ae113 --- /dev/null +++ b/test/Index/complete-pch.m @@ -0,0 +1,26 @@ +// Note: the run lines follow their respective tests, since line/column +// matter in this test. + +@interface C +- (int)instanceMethod3:(int)x; ++ (int)classMethod3:(float)f; +@end + +void msg_id(id x) { + [id classMethod1:1.0]; + [x instanceMethod1:5]; +} + +// Build the precompiled header +// RUN: %clang -x objective-c-header -o %t.h.pch %S/Inputs/complete-pch.h + +// Run the actual tests +// RUN: c-index-test -code-completion-at=%s:10:7 -include %t.h %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod1:}{Placeholder (double)d} +// CHECK-CC1: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod2:}{Placeholder (float)f} +// CHECK-CC1: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod3:}{Placeholder (float)f} + +// RUN: c-index-test -code-completion-at=%s:11:6 -include %t.h %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText instanceMethod1:}{Placeholder (int)x} +// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText instanceMethod2:}{Placeholder (int)x} +// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText instanceMethod3:}{Placeholder (int)x}