From: Douglas Gregor Date: Fri, 13 Aug 2010 22:48:40 +0000 (+0000) Subject: Implement caching of code-completion results for macro definitions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=87c08a5d6b9e1e44ae6f554df40139d3a6f60b33;p=clang Implement caching of code-completion results for macro definitions when the CXTranslationUnit_CacheCompletionResults option is given to clang_parseTranslationUnit(). Essentially, we compute code-completion results for macro definitions after we have parsed the file, then store an ASTContext-agnostic version of those results (completion string, cursor kind, priority, and active contexts) in the ASTUnit. When performing code completion in that ASTUnit, we splice the macro definition results into the results provided by the actual code-completion (which has had macros turned off) before libclang gets those results. We use completion context information to only splice in those results that make sense for that context. With a completion involving all of the macros from Cocoa.h and a few other system libraries (totally ~8500 macro definitions) living in a precompiled header, we get about a 9% performance improvement from code completion, since we no longer have to deserialize all of the macro definitions from the precompiled header. Note that macro definitions are merely the canary; the cache is designed to also support other top-level declarations, which should be a bigger performance win. That optimization will be next. Note also that there is no mechanism for determining when to throw away the cache and recompute its contents. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111051 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 07bba5c0aa..76a86871de 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -20,6 +20,7 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang-c/Index.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" @@ -198,6 +199,55 @@ private: /// declarations parsed within the precompiled preamble. std::vector TopLevelDeclsInPreamble; + /// + /// \defgroup CodeCompleteCaching Code-completion caching + /// + /// \{ + /// + + /// \brief Whether we should be caching code-completion results. + bool ShouldCacheCodeCompletionResults; + +public: + /// \brief A cached code-completion result, which may be introduced in one of + /// many different contexts. + struct CachedCodeCompletionResult { + /// \brief The code-completion string corresponding to this completion + /// result. + CodeCompletionString *Completion; + + /// \brief A bitmask that indicates which code-completion contexts should + /// contain this completion result. + /// + /// The bits in the bitmask correspond to the values of + /// CodeCompleteContext::Kind. To map from a completion context kind to a + /// bit, subtract one from the completion context kind and shift 1 by that + /// number of bits. Many completions can occur in several different + /// contexts. + unsigned ShowInContexts; + + /// \brief The priority given to this code-completion result. + unsigned Priority; + + /// \brief The libclang cursor kind corresponding to this code-completion + /// result. + CXCursorKind Kind; + }; + +private: + /// \brief The set of cached code-completion results. + std::vector CachedCompletionResults; + + /// \brief Cache any "global" code-completion results, so that we + void CacheCodeCompletionResults(); + + /// \brief Clear out and deallocate + void ClearCachedCompletionResults(); + + /// + /// \} + /// + /// \brief The timers we've created from the various parses, reparses, etc. /// involved in this translation unit. std::vector Timers; @@ -339,6 +389,21 @@ public: return StoredDiagnostics; } + typedef std::vector::iterator + cached_completion_iterator; + + cached_completion_iterator cached_completion_begin() { + return CachedCompletionResults.begin(); + } + + cached_completion_iterator cached_completion_end() { + return CachedCompletionResults.end(); + } + + unsigned cached_completion_size() const { + return CachedCompletionResults.size(); + } + /// \brief Whether this AST represents a complete translation unit. /// /// If false, this AST is only a partial translation unit, e.g., one @@ -380,7 +445,8 @@ public: bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, bool PrecompilePreamble = false, - bool CompleteTranslationUnit = true); + bool CompleteTranslationUnit = true, + bool CacheCodeCompletionResults = false); /// LoadFromCommandLine - Create an ASTUnit from a vector of command line /// arguments, which must specify exactly one source file. @@ -405,7 +471,8 @@ public: unsigned NumRemappedFiles = 0, bool CaptureDiagnostics = false, bool PrecompilePreamble = false, - bool CompleteTranslationUnit = true); + bool CompleteTranslationUnit = true, + bool CacheCodeCompletionResults = false); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 5310b63477..48e422383f 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -16,6 +16,7 @@ #include "clang/AST/Type.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "clang-c/Index.h" #include #include @@ -419,6 +420,9 @@ public: /// \brief The priority of this particular code-completion result. unsigned Priority; + /// \brief The cursor kind that describes this result. + CXCursorKind CursorKind; + /// \brief Specifies which parameter (of a function, Objective-C method, /// macro, etc.) we should start with when formatting the result. unsigned StartParameter; @@ -455,6 +459,7 @@ public: Hidden(false), QualifierIsInformative(QualifierIsInformative), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), DeclaringEntity(false), Qualifier(Qualifier) { + computeCursorKind(); } /// \brief Build a result that refers to a keyword or symbol. @@ -462,21 +467,29 @@ public: : Kind(RK_Keyword), Keyword(Keyword), Priority(Priority), StartParameter(0), Hidden(false), QualifierIsInformative(0), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), - DeclaringEntity(false), Qualifier(0) { } + DeclaringEntity(false), Qualifier(0) { + computeCursorKind(); + } /// \brief Build a result that refers to a macro. Result(IdentifierInfo *Macro, unsigned Priority = CCP_Macro) - : Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0), - Hidden(false), QualifierIsInformative(0), - StartsNestedNameSpecifier(false), AllParametersAreInformative(false), - DeclaringEntity(false), Qualifier(0) { } + : Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0), + Hidden(false), QualifierIsInformative(0), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(0) { + computeCursorKind(); + } /// \brief Build a result that refers to a pattern. - Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern) + Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern, + CXCursorKind CursorKind = CXCursor_NotImplemented) : Kind(RK_Pattern), Pattern(Pattern), Priority(Priority), - StartParameter(0), Hidden(false), QualifierIsInformative(0), - StartsNestedNameSpecifier(false), AllParametersAreInformative(false), - DeclaringEntity(false), Qualifier(0) { } + CursorKind(CursorKind), StartParameter(0), Hidden(false), + QualifierIsInformative(0), StartsNestedNameSpecifier(false), + AllParametersAreInformative(false), DeclaringEntity(false), + Qualifier(0) + { + } /// \brief Retrieve the declaration stored in this result. NamedDecl *getDeclaration() const { @@ -505,6 +518,9 @@ public: /// brief Determine a base priority for the given declaration. static unsigned getPriorityFromDecl(NamedDecl *ND); + + private: + void computeCursorKind(); }; class OverloadCandidate { @@ -571,7 +587,8 @@ public: Sema &S) const; }; - CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { } + CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false), + OutputIsBinary(false) { } CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, bool OutputIsBinary) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d2b89824a7..5ab6d827e1 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_AST_SEMA_H #include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Template.h" @@ -46,7 +47,6 @@ namespace llvm { namespace clang { class ASTContext; class ASTConsumer; - class CodeCompleteConsumer; class Preprocessor; class Decl; class DeclContext; @@ -4701,7 +4701,8 @@ public: TypeTy *ReturnType, IdentifierInfo **SelIdents, unsigned NumSelIdents); - + void GatherGlobalCodeCompletions( + llvm::SmallVectorImpl &Results); //@} //===--------------------------------------------------------------------===// diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index e501260af7..e6bae6b727 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -50,7 +50,8 @@ const unsigned DefaultPreambleRebuildInterval = 5; ASTUnit::ASTUnit(bool _MainFileIsAST) : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), - PreambleRebuildCounter(0), SavedMainFileBuffer(0) { + PreambleRebuildCounter(0), SavedMainFileBuffer(0), + ShouldCacheCodeCompletionResults(false) { } ASTUnit::~ASTUnit() { @@ -75,6 +76,8 @@ ASTUnit::~ASTUnit() { delete SavedMainFileBuffer; + ClearCachedCompletionResults(); + for (unsigned I = 0, N = Timers.size(); I != N; ++I) delete Timers[I]; } @@ -85,6 +88,70 @@ void ASTUnit::CleanTemporaryFiles() { TemporaryFiles.clear(); } +void ASTUnit::CacheCodeCompletionResults() { + if (!TheSema) + return; + + llvm::Timer *CachingTimer = 0; + if (TimerGroup.get()) { + CachingTimer = new llvm::Timer("Cache global code completions", + *TimerGroup); + CachingTimer->startTimer(); + Timers.push_back(CachingTimer); + } + + // Clear out the previous results. + ClearCachedCompletionResults(); + + // Gather the set of global code completions. + typedef CodeCompleteConsumer::Result Result; + llvm::SmallVector Results; + TheSema->GatherGlobalCodeCompletions(Results); + + // Translate global code completions into cached completions. + for (unsigned I = 0, N = Results.size(); I != N; ++I) { + switch (Results[I].Kind) { + case Result::RK_Declaration: + // FIXME: Handle declarations! + break; + + case Result::RK_Keyword: + case Result::RK_Pattern: + // Ignore keywords and patterns; we don't care, since they are so + // easily regenerated. + break; + + case Result::RK_Macro: { + CachedCodeCompletionResult CachedResult; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + CachedResult.Priority = Results[I].Priority; + CachedResult.Kind = Results[I].CursorKind; + CachedCompletionResults.push_back(CachedResult); + break; + } + } + Results[I].Destroy(); + } + + if (CachingTimer) + CachingTimer->stopTimer(); +} + +void ASTUnit::ClearCachedCompletionResults() { + for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I) + delete CachedCompletionResults[I].Completion; + CachedCompletionResults.clear(); +} + namespace { /// \brief Gathers information from PCHReader that will be used to initialize @@ -542,6 +609,12 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { Clang.takeDiagnosticClient(); Invocation.reset(Clang.takeInvocation()); + + // If we were asked to cache code-completion results and don't have any + // results yet, do so now. + if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty()) + CacheCodeCompletionResults(); + return false; error: @@ -579,7 +652,6 @@ static std::string GetPreamblePCHPath() { if (P.createTemporaryFileOnDisk()) return std::string(); - fprintf(stderr, "Preamble file: %s\n", P.str().c_str()); return P.str(); } @@ -1044,7 +1116,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CompleteTranslationUnit) { + bool CompleteTranslationUnit, + bool CacheCodeCompletionResults) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1059,6 +1132,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->CaptureDiagnostics = CaptureDiagnostics; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation.reset(CI); CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; @@ -1097,7 +1171,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, unsigned NumRemappedFiles, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CompleteTranslationUnit) { + bool CompleteTranslationUnit, + bool CacheCodeCompletionResults) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1159,7 +1234,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, CI->getFrontendOpts().DisableFree = true; return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble, - CompleteTranslationUnit); + CompleteTranslationUnit, + CacheCodeCompletionResults); } bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { @@ -1196,6 +1272,91 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { return Result; } +//----------------------------------------------------------------------------// +// Code completion +//----------------------------------------------------------------------------// + +namespace { + /// \brief Code completion consumer that combines the cached code-completion + /// results from an ASTUnit with the code-completion results provided to it, + /// then passes the result on to + class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer { + unsigned NormalContexts; + ASTUnit &AST; + CodeCompleteConsumer &Next; + + public: + AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, + bool IncludeMacros, bool IncludeCodePatterns) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, + Next.isOutputBinary()), AST(AST), Next(Next) + { + // Compute the set of contexts in which we will look when we don't have + // any information about the specific context. + NormalContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) + | (1 << (CodeCompletionContext::CCC_MemberAccess - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); + + if (AST.getASTContext().getLangOptions().CPlusPlus) + NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)) + | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) + | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); + } + + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + Result *Results, + unsigned NumResults) { + // Merge the results we were given with the results we cached. + bool AddedResult = false; + unsigned InContexts = + (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts + : (1 << (Context.getKind() - 1))); + typedef CodeCompleteConsumer::Result Result; + llvm::SmallVector AllResults; + for (ASTUnit::cached_completion_iterator + C = AST.cached_completion_begin(), + CEnd = AST.cached_completion_end(); + C != CEnd; ++C) { + // If the context we are in matches any of the contexts we are + // interested in, we'll add this result. + if ((C->ShowInContexts & InContexts) == 0) + continue; + + // If we haven't added any results previously, do so now. + if (!AddedResult) { + AllResults.insert(AllResults.end(), Results, Results + NumResults); + AddedResult = true; + } + + AllResults.push_back(Result(C->Completion, C->Priority, C->Kind)); + } + + // If we did not add any cached completion results, just forward the + // results we were given to the next consumer. + if (!AddedResult) { + Next.ProcessCodeCompleteResults(S, Context, Results, NumResults); + return; + } + + Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), + AllResults.size()); + } + + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); + } + }; +} void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, @@ -1223,7 +1384,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts(); PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts(); - FrontendOpts.ShowMacrosInCodeCompletion = IncludeMacros; + FrontendOpts.ShowMacrosInCodeCompletion + = IncludeMacros && CachedCompletionResults.empty(); FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns; FrontendOpts.CodeCompletionAt.FileName = File; FrontendOpts.CodeCompletionAt.Line = Line; @@ -1281,8 +1443,12 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, RemappedFiles[I].second); - // Use the code completion consumer we were given. - Clang.setCodeCompletionConsumer(&Consumer); + // Use the code completion consumer we were given, but adding any cached + // code-completion results. + AugmentedCodeCompleteConsumer + AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion, + FrontendOpts.ShowCodePatternsInCodeCompletion); + Clang.setCodeCompletionConsumer(&AugmentedConsumer); // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 6f4e1839e3..c1b666a792 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -496,95 +496,109 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } -namespace clang { - // FIXME: Used externally by CIndexCodeCompletion.cpp; this code - // will move there, eventually, when the CIndexCodeCompleteConsumer - // dies. - CXCursorKind - getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R) { - typedef CodeCompleteConsumer::Result Result; - switch (R.Kind) { - case Result::RK_Declaration: - switch (R.Declaration->getKind()) { - case Decl::Record: - case Decl::CXXRecord: - case Decl::ClassTemplateSpecialization: { - RecordDecl *Record = cast(R.Declaration); - if (Record->isStruct()) - return CXCursor_StructDecl; - else if (Record->isUnion()) - return CXCursor_UnionDecl; - else - return CXCursor_ClassDecl; - } - - case Decl::ObjCMethod: { - ObjCMethodDecl *Method = cast(R.Declaration); - if (Method->isInstanceMethod()) - return CXCursor_ObjCInstanceMethodDecl; - else - return CXCursor_ObjCClassMethodDecl; - } - - case Decl::Typedef: - return CXCursor_TypedefDecl; - - case Decl::Enum: - return CXCursor_EnumDecl; +void CodeCompleteConsumer::Result::computeCursorKind() { + switch (Kind) { + case RK_Declaration: + switch (Declaration->getKind()) { + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: { + RecordDecl *Record = cast(Declaration); + if (Record->isStruct()) + CursorKind = CXCursor_StructDecl; + else if (Record->isUnion()) + CursorKind = CXCursor_UnionDecl; + else + CursorKind = CXCursor_ClassDecl; + break; + } + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast(Declaration); + if (Method->isInstanceMethod()) + CursorKind = CXCursor_ObjCInstanceMethodDecl; + else + CursorKind = CXCursor_ObjCClassMethodDecl; + break; + } + + case Decl::Typedef: + CursorKind = CXCursor_TypedefDecl; + break; - case Decl::Field: - return CXCursor_FieldDecl; + case Decl::Enum: + CursorKind = CXCursor_EnumDecl; + break; - case Decl::EnumConstant: - return CXCursor_EnumConstantDecl; + case Decl::Field: + CursorKind = CXCursor_FieldDecl; + break; - case Decl::Function: - case Decl::CXXMethod: - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: - return CXCursor_FunctionDecl; + case Decl::EnumConstant: + CursorKind = CXCursor_EnumConstantDecl; + break; - case Decl::Var: - return CXCursor_VarDecl; + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + CursorKind = CXCursor_FunctionDecl; + break; - case Decl::ParmVar: - return CXCursor_ParmDecl; + case Decl::Var: + CursorKind = CXCursor_VarDecl; + break; - case Decl::ObjCInterface: - return CXCursor_ObjCInterfaceDecl; + case Decl::ParmVar: + CursorKind = CXCursor_ParmDecl; + break; - case Decl::ObjCCategory: - return CXCursor_ObjCCategoryDecl; + case Decl::ObjCInterface: + CursorKind = CXCursor_ObjCInterfaceDecl; + break; - case Decl::ObjCProtocol: - return CXCursor_ObjCProtocolDecl; + case Decl::ObjCCategory: + CursorKind = CXCursor_ObjCCategoryDecl; + break; - case Decl::ObjCProperty: - return CXCursor_ObjCPropertyDecl; + case Decl::ObjCProtocol: + CursorKind = CXCursor_ObjCProtocolDecl; + break; + + case Decl::ObjCProperty: + CursorKind = CXCursor_ObjCPropertyDecl; + break; - case Decl::ObjCIvar: - return CXCursor_ObjCIvarDecl; + case Decl::ObjCIvar: + CursorKind = CXCursor_ObjCIvarDecl; + break; - case Decl::ObjCImplementation: - return CXCursor_ObjCImplementationDecl; + case Decl::ObjCImplementation: + CursorKind = CXCursor_ObjCImplementationDecl; + break; - case Decl::ObjCCategoryImpl: - return CXCursor_ObjCCategoryImplDecl; + case Decl::ObjCCategoryImpl: + CursorKind = CXCursor_ObjCCategoryImplDecl; + break; - default: - break; - } + default: + CursorKind = CXCursor_NotImplemented; break; - - case Result::RK_Macro: - return CXCursor_MacroDefinition; - - case Result::RK_Keyword: - case Result::RK_Pattern: - return CXCursor_NotImplemented; } - return CXCursor_NotImplemented; + break; + + case Result::RK_Macro: + CursorKind = CXCursor_MacroDefinition; + break; + + case Result::RK_Keyword: + CursorKind = CXCursor_NotImplemented; + break; + + case Result::RK_Pattern: + // Do nothing: Patterns can come with cursor kinds! + break; } } @@ -595,7 +609,7 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { - WriteUnsigned(OS, getCursorKindForCompletionResult(Results[I])); + WriteUnsigned(OS, Results[I].CursorKind); WriteUnsigned(OS, Results[I].Priority); CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); assert(CCS && "No code-completion string?"); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index f5c85ad99c..95f08bdf01 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -269,8 +269,10 @@ void Sema::ActOnEndOfTranslationUnit() { true)), UnusedFileScopedDecls.end()); - if (!CompleteTranslationUnit) + if (!CompleteTranslationUnit) { + TUScope = 0; return; + } // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic @@ -340,6 +342,8 @@ void Sema::ActOnEndOfTranslationUnit() { Diag((*I)->getLocation(), diag::warn_unused_variable) << cast(*I)->getDeclName(); } + + TUScope = 0; } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index b8fb04425e..31185683a1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4336,3 +4336,23 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); } + +void Sema::GatherGlobalCodeCompletions( + llvm::SmallVectorImpl &Results) { + ResultBuilder Builder(*this); + +#if 0 + // FIXME: We need a name lookup that means "look for everything", + CodeCompletionDeclConsumer Consumer(Builder, + Context.getTranslationUnitDecl()); + LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupOrdinaryName, + Consumer); +#endif + + if (!CodeCompleter || CodeCompleter->includeMacros()) + AddMacroResults(PP, Builder); + + Results.clear(); + Results.insert(Results.end(), + Builder.data(), Builder.data() + Builder.size()); +} diff --git a/test/Index/complete-macros.c b/test/Index/complete-macros.c index 9a898e152a..d0974db31f 100644 --- a/test/Index/complete-macros.c +++ b/test/Index/complete-macros.c @@ -16,6 +16,7 @@ void f2() { } // RUN: c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: macro definition:{TypedText FOO}{LeftParen (}{Placeholder Arg1}{Comma , }{Placeholder Arg2}{RightParen )} // RUN: c-index-test -code-completion-at=%s:13:13 %s | FileCheck -check-prefix=CHECK-CC2 %s // RUN: c-index-test -code-completion-at=%s:14:8 %s | FileCheck -check-prefix=CHECK-CC2 %s diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index ef6bfb8a79..1b2f036fa4 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -34,6 +34,8 @@ static unsigned getDefaultParsingOptions() { if (getenv("CINDEXTEST_EDITING")) options |= clang_defaultEditingTranslationUnitOptions(); + if (getenv("CINDEXTEST_COMPLETION_CACHING")) + options |= CXTranslationUnit_CacheCompletionResults; return options; } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 93fdd96c24..f7dce99c72 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1220,7 +1220,9 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; bool CompleteTranslationUnit = ((options & CXTranslationUnit_Incomplete) == 0); - + bool CacheCodeCompetionResults + = options & CXTranslationUnit_CacheCompletionResults; + // Configure the diagnostics. DiagnosticOptions DiagOpts; llvm::IntrusiveRefCntPtr Diags; @@ -1276,7 +1278,8 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, RemappedFiles.size(), /*CaptureDiagnostics=*/true, PrecompilePreamble, - CompleteTranslationUnit)); + CompleteTranslationUnit, + CacheCodeCompetionResults)); if (NumErrors != Diags->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 813f82a4cc..f0e90212f7 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -541,14 +541,6 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, } // end extern "C" -namespace clang { - // FIXME: defined in CodeCompleteConsumer.cpp, but should be a - // static function here. - CXCursorKind - getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R); -} - - namespace { class CaptureCompletionResults : public CodeCompleteConsumer { AllocatedCXCodeCompleteResults &AllocatedResults; @@ -567,8 +559,7 @@ namespace { CXStoredCodeCompletionString *StoredCompletion = new CXStoredCodeCompletionString(Results[I].Priority); (void)Results[I].CreateCodeCompletionString(S, StoredCompletion); - AllocatedResults.Results[I].CursorKind - = getCursorKindForCompletionResult(Results[I]); + AllocatedResults.Results[I].CursorKind = Results[I].CursorKind; AllocatedResults.Results[I].CompletionString = StoredCompletion; } }