diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-02-01 19:23:04 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-02-01 19:23:04 +0000 |
commit | 218937c13ef5b0625a70aad41ca7a92da9278bd2 (patch) | |
tree | f965c5449f5d1b9ae07e755f619958abc5db0a44 | |
parent | 0e2dc3a1159806c8303b0979be1ce1526cc64ed3 (diff) |
Allocate CodeCompletionString and all of its components in a
BumpPtrAllocator, rather than manually new/delete'ing them. This
optimization also allows us to avoid allocating memory for and copying
constant strings (e.g., "return", "class").
This also required embedding the priority and availability of results
within the code completion string, to avoid extra memory allocation
within libclang.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124673 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 6 | ||||
-rw-r--r-- | include/clang/Sema/CodeCompleteConsumer.h | 157 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 32 | ||||
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 137 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 1553 | ||||
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 74 |
7 files changed, 967 insertions, 994 deletions
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 12555ab1af..6ee3e85fef 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -288,6 +288,12 @@ public: } private: + /// \brief Allocator used to store temporary code completion results. + llvm::BumpPtrAllocator CompletionAllocator; + + /// \brief Allocator used to store cached code completions. + llvm::BumpPtrAllocator CachedCompletionAllocator; + /// \brief The set of cached code-completion results. std::vector<CachedCodeCompletionResult> CachedCompletionResults; diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 5cdcc27b67..9daefd72a5 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -17,8 +17,8 @@ #include "clang/AST/CanonicalType.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "clang-c/Index.h" -#include <memory> #include <string> namespace llvm { @@ -354,119 +354,149 @@ public: Chunk() : Kind(CK_Text), Text(0) { } - Chunk(ChunkKind Kind, llvm::StringRef Text = ""); + Chunk(ChunkKind Kind, const char *Text = ""); /// \brief Create a new text chunk. - static Chunk CreateText(llvm::StringRef Text); + static Chunk CreateText(const char *Text); /// \brief Create a new optional chunk. - static Chunk CreateOptional(std::auto_ptr<CodeCompletionString> Optional); + static Chunk CreateOptional(CodeCompletionString *Optional); /// \brief Create a new placeholder chunk. - static Chunk CreatePlaceholder(llvm::StringRef Placeholder); + static Chunk CreatePlaceholder(const char *Placeholder); /// \brief Create a new informative chunk. - static Chunk CreateInformative(llvm::StringRef Informative); + static Chunk CreateInformative(const char *Informative); /// \brief Create a new result type chunk. - static Chunk CreateResultType(llvm::StringRef ResultType); + static Chunk CreateResultType(const char *ResultType); /// \brief Create a new current-parameter chunk. - static Chunk CreateCurrentParameter(llvm::StringRef CurrentParameter); - - /// \brief Clone the given chunk. - Chunk Clone() const; - - /// \brief Destroy this chunk, deallocating any memory it owns. - void Destroy(); + static Chunk CreateCurrentParameter(const char *CurrentParameter); }; private: - /// \brief The chunks stored in this string. - llvm::SmallVector<Chunk, 4> Chunks; + /// \brief The number of chunks stored in this string. + unsigned NumChunks; + + /// \brief The priority of this code-completion string. + unsigned Priority : 30; + + /// \brief The availability of this code-completion result. + CXAvailabilityKind Availability : 2; CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT CodeCompletionString &operator=(const CodeCompletionString &); // DITTO -public: - CodeCompletionString() { } - ~CodeCompletionString() { clear(); } + CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, + unsigned Priority, CXAvailabilityKind Availability); + ~CodeCompletionString() { } - typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator; - iterator begin() const { return Chunks.begin(); } - iterator end() const { return Chunks.end(); } - bool empty() const { return Chunks.empty(); } - unsigned size() const { return Chunks.size(); } - void clear(); + friend class CodeCompletionBuilder; + friend class CodeCompletionResult; - Chunk &operator[](unsigned I) { +public: + typedef const Chunk *iterator; + iterator begin() const { return reinterpret_cast<const Chunk *>(this + 1); } + iterator end() const { return begin() + NumChunks; } + bool empty() const { return NumChunks == 0; } + unsigned size() const { return NumChunks; } + + const Chunk &operator[](unsigned I) const { assert(I < size() && "Chunk index out-of-range"); - return Chunks[I]; + return begin()[I]; } + + /// \brief Returns the text in the TypedText chunk. + const char *getTypedText() const; - const Chunk &operator[](unsigned I) const { - assert(I < size() && "Chunk index out-of-range"); - return Chunks[I]; + /// \brief Retrieve the priority of this code completion result. + unsigned getPriority() const { return Priority; } + + /// \brief Reteirve the availability of this code completion result. + unsigned getAvailability() const { return Availability; } + + /// \brief Retrieve a string representation of the code completion string, + /// which is mainly useful for debugging. + std::string getAsString() const; +}; + +/// \brief A builder class used to construct new code-completion strings. +class CodeCompletionBuilder { +public: + typedef CodeCompletionString::Chunk Chunk; + +private: + llvm::BumpPtrAllocator &Allocator; + unsigned Priority; + CXAvailabilityKind Availability; + + /// \brief The chunks stored in this string. + llvm::SmallVector<Chunk, 4> Chunks; + +public: + CodeCompletionBuilder(llvm::BumpPtrAllocator &Allocator) + : Allocator(Allocator), Priority(0), Availability(CXAvailability_Available){ } + CodeCompletionBuilder(llvm::BumpPtrAllocator &Allocator, + unsigned Priority, CXAvailabilityKind Availability) + : Allocator(Allocator), Priority(Priority), Availability(Availability) { } + + /// \brief Retrieve the allocator into which the code completion + /// strings will be + llvm::BumpPtrAllocator &getAllocator() const { return Allocator; } + + /// \brief Take the resulting completion string. + /// + /// This operation can only be performed once. + CodeCompletionString *TakeString(); + /// \brief Add a new typed-text chunk. /// The text string will be copied. - void AddTypedTextChunk(llvm::StringRef Text) { - Chunks.push_back(Chunk(CK_TypedText, Text)); + void AddTypedTextChunk(const char *Text) { + Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text)); } /// \brief Add a new text chunk. /// The text string will be copied. - void AddTextChunk(llvm::StringRef Text) { + void AddTextChunk(const char *Text) { Chunks.push_back(Chunk::CreateText(Text)); } /// \brief Add a new optional chunk. - void AddOptionalChunk(std::auto_ptr<CodeCompletionString> Optional) { + void AddOptionalChunk(CodeCompletionString *Optional) { Chunks.push_back(Chunk::CreateOptional(Optional)); } /// \brief Add a new placeholder chunk. /// The placeholder text will be copied. - void AddPlaceholderChunk(llvm::StringRef Placeholder) { + void AddPlaceholderChunk(const char *Placeholder) { Chunks.push_back(Chunk::CreatePlaceholder(Placeholder)); } - + /// \brief Add a new informative chunk. /// The text will be copied. - void AddInformativeChunk(llvm::StringRef Text) { + void AddInformativeChunk(const char *Text) { Chunks.push_back(Chunk::CreateInformative(Text)); } - + /// \brief Add a new result-type chunk. /// The text will be copied. - void AddResultTypeChunk(llvm::StringRef ResultType) { + void AddResultTypeChunk(const char *ResultType) { Chunks.push_back(Chunk::CreateResultType(ResultType)); } /// \brief Add a new current-parameter chunk. /// The text will be copied. - void AddCurrentParameterChunk(llvm::StringRef CurrentParameter) { + void AddCurrentParameterChunk(const char *CurrentParameter) { Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter)); } /// \brief Add a new chunk. void AddChunk(Chunk C) { Chunks.push_back(C); } - - /// \brief Returns the text in the TypedText chunk. - const char *getTypedText() const; - - /// \brief Retrieve a string representation of the code completion string, - /// which is mainly useful for debugging. - std::string getAsString() const; - - /// \brief Clone this code-completion string. - /// - /// \param Result If non-NULL, points to an empty code-completion - /// result that will be given a cloned copy of - CodeCompletionString *Clone(CodeCompletionString *Result = 0) const; }; - + /// \brief Captures a result of code completion. class CodeCompletionResult { public: @@ -597,13 +627,10 @@ public: /// /// \param S The semantic analysis that created the result. /// - /// \param Result If non-NULL, the already-allocated, empty - /// code-completion string that will be populated with the - /// appropriate code completion string for this result. + /// \param Allocator The allocator that will be used to allocate the + /// string itself. CodeCompletionString *CreateCodeCompletionString(Sema &S, - CodeCompletionString *Result = 0); - - void Destroy(); + llvm::BumpPtrAllocator &Allocator); /// \brief Determine a base priority for the given declaration. static unsigned getPriorityFromDecl(NamedDecl *ND); @@ -715,7 +742,7 @@ public: /// signature of this overload candidate. CodeCompletionString *CreateSignatureString(unsigned CurrentArg, Sema &S, - CodeCompletionString *Result = 0) const; + llvm::BumpPtrAllocator &Allocator) const; }; CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false), @@ -761,6 +788,10 @@ public: OverloadCandidate *Candidates, unsigned NumCandidates) { } //@} + + /// \brief Retrieve the allocator that will be used to allocate + /// code completion strings. + virtual llvm::BumpPtrAllocator &getAllocator() = 0; }; /// \brief A simple code-completion consumer that prints the results it @@ -769,6 +800,8 @@ class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { /// \brief The raw output stream. llvm::raw_ostream &OS; + llvm::BumpPtrAllocator Allocator; + public: /// \brief Create a new printing code-completion consumer that prints its /// results to the given raw output stream. @@ -787,6 +820,8 @@ public: virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates); + + virtual llvm::BumpPtrAllocator &getAllocator() { return Allocator; } }; } // end namespace clang diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 908d1a1ca6..9d04421715 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4909,7 +4909,7 @@ public: MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteNaturalLanguage(); - void GatherGlobalCodeCompletions( + void GatherGlobalCodeCompletions(llvm::BumpPtrAllocator &Allocator, llvm::SmallVectorImpl<CodeCompletionResult> &Results); //@} diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 9116d0ed17..5617df6881 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -222,7 +222,7 @@ void ASTUnit::CacheCodeCompletionResults() { // Gather the set of global code completions. typedef CodeCompletionResult Result; llvm::SmallVector<Result, 8> Results; - TheSema->GatherGlobalCodeCompletions(Results); + TheSema->GatherGlobalCodeCompletions(CachedCompletionAllocator, Results); // Translate global code completions into cached completions. llvm::DenseMap<CanQualType, unsigned> CompletionTypes; @@ -232,7 +232,8 @@ void ASTUnit::CacheCodeCompletionResults() { case Result::RK_Declaration: { bool IsNestedNameSpecifier = false; CachedCodeCompletionResult CachedResult; - CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, + CachedCompletionAllocator); CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, Ctx->getLangOptions(), IsNestedNameSpecifier); @@ -294,7 +295,9 @@ void ASTUnit::CacheCodeCompletionResults() { // nested-name-specifier but isn't already an option, create a // nested-name-specifier completion. Results[I].StartsNestedNameSpecifier = true; - CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.Completion + = Results[I].CreateCodeCompletionString(*TheSema, + CachedCompletionAllocator); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; CachedResult.TypeClass = STC_Void; @@ -313,7 +316,9 @@ void ASTUnit::CacheCodeCompletionResults() { case Result::RK_Macro: { CachedCodeCompletionResult CachedResult; - CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.Completion + = Results[I].CreateCodeCompletionString(*TheSema, + CachedCompletionAllocator); CachedResult.ShowInContexts = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) @@ -337,7 +342,6 @@ void ASTUnit::CacheCodeCompletionResults() { break; } } - Results[I].Destroy(); } // Make a note of the state when we performed this caching. @@ -345,10 +349,9 @@ void ASTUnit::CacheCodeCompletionResults() { } void ASTUnit::ClearCachedCompletionResults() { - for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I) - delete CachedCompletionResults[I].Completion; CachedCompletionResults.clear(); CachedCompletionTypes.clear(); + CachedCompletionAllocator.Reset(); } namespace { @@ -1657,6 +1660,10 @@ namespace { unsigned NumCandidates) { Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); } + + virtual llvm::BumpPtrAllocator &getAllocator() { + return Next.getAllocator(); + } }; } @@ -1750,7 +1757,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, // Contains the set of names that are hidden by "local" completion results. llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames; - llvm::SmallVector<CodeCompletionString *, 4> StringsToDestroy; typedef CodeCompletionResult Result; llvm::SmallVector<Result, 8> AllResults; for (ASTUnit::cached_completion_iterator @@ -1809,11 +1815,12 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) { // Create a new code-completion string that just contains the // macro name, without its arguments. - Completion = new CodeCompletionString; - Completion->AddTypedTextChunk(C->Completion->getTypedText()); - StringsToDestroy.push_back(Completion); + CodeCompletionBuilder Builder(getAllocator(), CCP_CodePattern, + C->Availability); + Builder.AddTypedTextChunk(C->Completion->getTypedText()); CursorKind = CXCursor_NotImplemented; Priority = CCP_CodePattern; + Completion = Builder.TakeString(); } AllResults.push_back(Result(Completion, Priority, CursorKind, @@ -1829,9 +1836,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), AllResults.size()); - - for (unsigned I = 0, N = StringsToDestroy.size(); I != N; ++I) - delete StringsToDestroy[I]; } diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index ee6fb3bf0e..ddfe8b0b17 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -71,7 +71,7 @@ bool CodeCompletionContext::wantConstructorResults() const { //===----------------------------------------------------------------------===// // Code completion string implementation //===----------------------------------------------------------------------===// -CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) : Kind(Kind), Text("") { switch (Kind) { @@ -80,13 +80,9 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) case CK_Placeholder: case CK_Informative: case CK_ResultType: - case CK_CurrentParameter: { - char *New = new char [Text.size() + 1]; - std::memcpy(New, Text.data(), Text.size()); - New[Text.size()] = '\0'; - this->Text = New; + case CK_CurrentParameter: + this->Text = Text; break; - } case CK_Optional: llvm_unreachable("Optional strings cannot be created from text"); @@ -151,112 +147,48 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateText(StringRef Text) { +CodeCompletionString::Chunk::CreateText(const char *Text) { return Chunk(CK_Text, Text); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateOptional( - std::auto_ptr<CodeCompletionString> Optional) { +CodeCompletionString::Chunk::CreateOptional(CodeCompletionString *Optional) { Chunk Result; Result.Kind = CK_Optional; - Result.Optional = Optional.release(); + Result.Optional = Optional; return Result; } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) { +CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { return Chunk(CK_Placeholder, Placeholder); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateInformative(StringRef Informative) { +CodeCompletionString::Chunk::CreateInformative(const char *Informative) { return Chunk(CK_Informative, Informative); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateResultType(StringRef ResultType) { +CodeCompletionString::Chunk::CreateResultType(const char *ResultType) { return Chunk(CK_ResultType, ResultType); } CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter( - StringRef CurrentParameter) { + const char *CurrentParameter) { return Chunk(CK_CurrentParameter, CurrentParameter); } -CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { - switch (Kind) { - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_ResultType: - case CK_CurrentParameter: - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - case CK_Colon: - case CK_SemiColon: - case CK_Equal: - case CK_HorizontalSpace: - case CK_VerticalSpace: - return Chunk(Kind, Text); - - case CK_Optional: { - std::auto_ptr<CodeCompletionString> Opt(Optional->Clone()); - return CreateOptional(Opt); - } - } - - // Silence GCC warning. - return Chunk(); -} - -void -CodeCompletionString::Chunk::Destroy() { - switch (Kind) { - case CK_Optional: - delete Optional; - break; - - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_ResultType: - case CK_CurrentParameter: - delete [] Text; - break; - - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - case CK_Colon: - case CK_SemiColon: - case CK_Equal: - case CK_HorizontalSpace: - case CK_VerticalSpace: - break; - } -} - -void CodeCompletionString::clear() { - std::for_each(Chunks.begin(), Chunks.end(), - std::mem_fun_ref(&Chunk::Destroy)); - Chunks.clear(); +CodeCompletionString::CodeCompletionString(const Chunk *Chunks, + unsigned NumChunks, + unsigned Priority, + CXAvailabilityKind Availability) + : NumChunks(NumChunks), Priority(Priority), Availability(Availability) +{ + Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1); + for (unsigned I = 0; I != NumChunks; ++I) + StoredChunks[I] = Chunks[I]; } std::string CodeCompletionString::getAsString() const { @@ -288,22 +220,17 @@ const char *CodeCompletionString::getTypedText() const { return 0; } -CodeCompletionString * -CodeCompletionString::Clone(CodeCompletionString *Result) const { - if (!Result) - Result = new CodeCompletionString; - for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) - Result->AddChunk(C->Clone()); +CodeCompletionString *CodeCompletionBuilder::TakeString() { + void *Mem = Allocator.Allocate( + sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(), + llvm::alignOf<CodeCompletionString>()); + CodeCompletionString *Result + = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(), + Priority, Availability); + Chunks.clear(); return Result; } -void CodeCompletionResult::Destroy() { - if (Kind == RK_Pattern) { - delete Pattern; - Pattern = 0; - } -} - unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) { if (!ND) return CCP_Unlikely; @@ -383,9 +310,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { + = Results[I].CreateCodeCompletionString(SemaRef, Allocator)) { OS << " : " << CCS->getAsString(); - delete CCS; } OS << '\n'; @@ -398,9 +324,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, case CodeCompletionResult::RK_Macro: { OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { + = Results[I].CreateCodeCompletionString(SemaRef, Allocator)) { OS << " : " << CCS->getAsString(); - delete CCS; } OS << '\n'; break; @@ -422,9 +347,9 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { if (CodeCompletionString *CCS - = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef, + Allocator)) { OS << "OVERLOAD: " << CCS->getAsString() << "\n"; - delete CCS; } } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 50ea6cb0b5..051603ce6d 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -117,6 +117,9 @@ namespace { /// \brief The semantic analysis object for which results are being /// produced. Sema &SemaRef; + + /// \brief The allocator used to allocate new code-completion strings. + llvm::BumpPtrAllocator &Allocator; /// \brief If non-NULL, a filter function used to remove any code-completion /// results that are not desirable. @@ -159,11 +162,11 @@ namespace { void MaybeAddConstructorResults(Result R); public: - explicit ResultBuilder(Sema &SemaRef, + explicit ResultBuilder(Sema &SemaRef, llvm::BumpPtrAllocator &Allocator, const CodeCompletionContext &CompletionContext, LookupFilter Filter = 0) - : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false), - HasObjectTypeQualifiers(false), + : SemaRef(SemaRef), Allocator(Allocator), Filter(Filter), + AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false), CompletionContext(CompletionContext), ObjCImplementation(0) { @@ -243,6 +246,9 @@ namespace { /// code completion results. Sema &getSema() const { return SemaRef; } + /// \brief Retrieve the allocator used to allocate code completion strings. + llvm::BumpPtrAllocator &getAllocator() const { return Allocator; } + /// \brief Determine whether the given declaration is at all interesting /// as a code-completion result. /// @@ -1189,6 +1195,7 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Results.AddResult(Result("restrict", CCP_Type)); } + CodeCompletionBuilder Builder(Results.getAllocator()); if (LangOpts.CPlusPlus) { // C++-specific Results.AddResult(Result("bool", CCP_Type + @@ -1197,25 +1204,23 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Results.AddResult(Result("wchar_t", CCP_Type)); // typename qualified-id - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typename"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualifier"); - Pattern->AddTextChunk("::"); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("typename"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("qualifier"); + Builder.AddTextChunk("::"); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(Result(Builder.TakeString())); if (LangOpts.CPlusPlus0x) { Results.AddResult(Result("auto", CCP_Type)); Results.AddResult(Result("char16_t", CCP_Type)); Results.AddResult(Result("char32_t", CCP_Type)); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("decltype"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("decltype"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); } } @@ -1226,18 +1231,16 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, // Results.AddResult(Result("_Decimal64")); // Results.AddResult(Result("_Decimal128")); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeof"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("typeof"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("typeof"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); } } @@ -1301,13 +1304,13 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts, static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt); static void AddTypedefResult(ResultBuilder &Results) { - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typedef"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(CodeCompletionResult(Pattern)); + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk("typedef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); } static bool WantTypesInContext(Sema::ParserCompletionContext CCC, @@ -1344,58 +1347,53 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Sema &SemaRef, ResultBuilder &Results) { + CodeCompletionBuilder Builder(Results.getAllocator()); + typedef CodeCompletionResult Result; switch (CCC) { case Sema::PCC_Namespace: if (SemaRef.getLangOptions().CPlusPlus) { - CodeCompletionString *Pattern = 0; - if (Results.includeCodePatterns()) { // namespace <identifier> { declarations } - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("declarations"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("identifier"); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("declarations"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } // namespace identifier = identifier ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("name"); - Pattern->AddChunk(CodeCompletionString::CK_Equal); - Pattern->AddPlaceholderChunk("namespace"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("name"); + Builder.AddChunk(CodeCompletionString::CK_Equal); + Builder.AddPlaceholderChunk("namespace"); + Results.AddResult(Result(Builder.TakeString())); // Using directives - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Builder.TakeString())); // asm(string-literal) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("asm"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("string-literal"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("asm"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("string-literal"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // Explicit template instantiation - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("template"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("declaration"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("template"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("declaration"); + Results.AddResult(Result(Builder.TakeString())); } } @@ -1408,47 +1406,42 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, case Sema::PCC_Class: if (SemaRef.getLangOptions().CPlusPlus) { // Using declaration - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualifier"); - Pattern->AddTextChunk("::"); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("qualifier"); + Builder.AddTextChunk("::"); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(Result(Builder.TakeString())); // using typename qualifier::name (only in a dependent context) if (SemaRef.CurContext->isDependentContext()) { - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); |