diff options
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 71 | ||||
-rw-r--r-- | include/clang/Sema/CodeCompleteConsumer.h | 37 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 182 | ||||
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 164 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 20 | ||||
-rw-r--r-- | test/Index/complete-macros.c | 1 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 2 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 7 | ||||
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 11 |
11 files changed, 396 insertions, 110 deletions
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<pch::DeclID> 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<CachedCodeCompletionResult> 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<llvm::Timer *> Timers; @@ -339,6 +389,21 @@ public: return StoredDiagnostics; } + typedef std::vector<CachedCodeCompletionResult>::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 <memory> #include <string> @@ -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<CodeCompleteConsumer::Result> &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<Result, 8> 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<Result, 8> 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<RecordDecl>(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<ObjCMethodDecl>(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<RecordDecl>(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<ObjCMethodDecl>(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<VarDecl>(*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<CodeCompleteConsumer::Result> &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<Diagnostic> 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; } } |