diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 473 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 113 |
2 files changed, 533 insertions, 53 deletions
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 9b24d55f3e..cb4e8ef826 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -16,6 +16,7 @@ #include "clang/Lex/Preprocessor.h" #include "Sema.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -26,14 +27,62 @@ using namespace clang; //===----------------------------------------------------------------------===// // Code completion string implementation //===----------------------------------------------------------------------===// -CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) : Kind(Kind), Text(0) { - assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative) - && "Invalid text chunk kind"); - char *New = new char [std::strlen(Text) + 1]; - std::strcpy(New, Text); - this->Text = New; + switch (Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: { + char *New = new char [Text.size() + 1]; + std::memcpy(New, Text.data(), Text.size()); + New[Text.size()] = '\0'; + this->Text = New; + break; + } + + case CK_Optional: + llvm::llvm_unreachable("Optional strings cannot be created from text"); + break; + + case CK_LeftParen: + this->Text = "("; + break; + + case CK_RightParen: + this->Text = ")"; + break; + + case CK_LeftBracket: + this->Text = "["; + break; + + case CK_RightBracket: + this->Text = "]"; + break; + + case CK_LeftBrace: + this->Text = "{"; + break; + + case CK_RightBrace: + this->Text = "}"; + break; + + case CK_LeftAngle: + this->Text = "<"; + break; + + case CK_RightAngle: + this->Text = ">"; + break; + + case CK_Comma: + this->Text = ", "; + break; + } } CodeCompletionString::Chunk @@ -60,6 +109,13 @@ CodeCompletionString::Chunk::CreateInformative(const char *Informative) { return Chunk(CK_Informative, Informative); } +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateCurrentParameter( + const char *CurrentParameter) { + return Chunk(CK_CurrentParameter, CurrentParameter); +} + + void CodeCompletionString::Chunk::Destroy() { switch (Kind) { @@ -67,10 +123,23 @@ CodeCompletionString::Chunk::Destroy() { delete Optional; break; + case CK_TypedText: case CK_Text: case CK_Placeholder: case CK_Informative: - delete [] Text; + 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: break; } } @@ -86,16 +155,322 @@ std::string CodeCompletionString::getAsString() const { for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { switch (C->Kind) { - case CK_Text: OS << C->Text; break; case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; case CK_Informative: OS << "[#" << C->Text << "#]"; break; + case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break; + default: OS << C->Text; break; } } OS.flush(); return Result; } + +namespace { + // Escape a string for XML-like formatting. + struct EscapedString { + EscapedString(llvm::StringRef Str) : Str(Str) { } + + llvm::StringRef Str; + }; + + llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) { + llvm::StringRef Str = EStr.Str; + while (!Str.empty()) { + // Find the next escaped character. + llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'"); + + // Print everything before that escaped character. + OS << Str.substr(0, Pos); + + // If we didn't find any escaped characters, we're done. + if (Pos == llvm::StringRef::npos) + break; + + // Print the appropriate escape sequence. + switch (Str[Pos]) { + case '<': OS << "<"; break; + case '>': OS << ">"; break; + case '&': OS << "&"; break; + case '"': OS << """; break; + case '\'': OS << "'"; break; + } + + // Remove everything up to and including that escaped character. + Str = Str.substr(Pos + 1); + } + + return OS; + } + + /// \brief Remove XML-like escaping from a string. + std::string UnescapeString(llvm::StringRef Str) { + using llvm::StringRef; + + std::string Result; + llvm::raw_string_ostream OS(Result); + + while (!Str.empty()) { + StringRef::size_type Amp = Str.find('&'); + OS << Str.substr(0, Amp); + + if (Amp == StringRef::npos) + break; + + StringRef::size_type Semi = Str.substr(Amp).find(';'); + if (Semi == StringRef::npos) { + // Malformed input; do the best we can. + OS << '&'; + Str = Str.substr(Amp + 1); + continue; + } + + char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1)) + .Case("lt", '<') + .Case("gt", '>') + .Case("amp", '&') + .Case("quot", '"') + .Case("apos", '\'') + .Default('\0'); + + if (Unescaped) + OS << Unescaped; + else + OS << Str.substr(Amp, Semi + 1); + Str = Str.substr(Amp + Semi + 1); + } + + return OS.str(); + } +} + +void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { + switch (C->Kind) { + case CK_TypedText: + OS << "<typed-text>" << EscapedString(C->Text) << "</>"; + break; + case CK_Text: + OS << "<text>" << EscapedString(C->Text) << "</>"; + break; + case CK_Optional: + OS << "<optional>"; + C->Optional->Serialize(OS); + OS << "</>"; + break; + case CK_Placeholder: + OS << "<placeholder>" << EscapedString(C->Text) << "</>"; + break; + case CK_Informative: + OS << "<informative>" << EscapedString(C->Text) << "</>"; + break; + case CK_CurrentParameter: + OS << "<current-parameter>" << EscapedString(C->Text) << "</>"; + break; + case CK_LeftParen: + OS << "<lparen/>"; + break; + case CK_RightParen: + OS << "<rparen/>"; + break; + case CK_LeftBracket: + OS << "<lbracket/>"; + break; + case CK_RightBracket: + OS << "<rbracket/>"; + break; + case CK_LeftBrace: + OS << "<lbrace/>"; + break; + case CK_RightBrace: + OS << "<rbrace/>"; + break; + case CK_LeftAngle: + OS << "<langle/>"; + break; + case CK_RightAngle: + OS << "<rangle/>"; + break; + case CK_Comma: + OS << "<comma/>"; + break; + } + } +} + +/// \brief Parse the next XML-ish tag of the form <blah>. +/// +/// \param Str the string in which we're looking for the next tag. +/// +/// \param TagPos if successful, will be set to the start of the tag we found. +/// +/// \param Standalone will indicate whether this is a "standalone" tag that +/// has no associated data, e.g., <comma/>. +/// +/// \param Terminator will indicate whether this is a terminating tag (that is +/// or starts with '/'). +/// +/// \returns the tag itself, without the angle brackets. +static llvm::StringRef ParseNextTag(llvm::StringRef Str, + llvm::StringRef::size_type &StartTag, + llvm::StringRef::size_type &AfterTag, + bool &Standalone, bool &Terminator) { + using llvm::StringRef; + + Standalone = false; + Terminator = false; + AfterTag = StringRef::npos; + + // Find the starting '<'. + StartTag = Str.find('<'); + if (StartTag == StringRef::npos) + return llvm::StringRef(); + + // Find the corresponding '>'. + llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>'); + if (EndTag == StringRef::npos) + return llvm::StringRef(); + AfterTag = StartTag + EndTag + 1; + + // Determine whether this is a terminating tag. + if (Str[StartTag + 1] == '/') { + Terminator = true; + Str = Str.substr(1); + --EndTag; + } + + // Determine whether this is a standalone tag. + if (!Terminator && Str[StartTag + EndTag - 1] == '/') { + Standalone = true; + if (EndTag > 1) + --EndTag; + } + + return Str.substr(StartTag + 1, EndTag - 1); +} + +CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) { + using llvm::StringRef; + + CodeCompletionString *Result = new CodeCompletionString; + + do { + // Parse the next tag. + StringRef::size_type StartTag, AfterTag; + bool Standalone, Terminator; + StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone, + Terminator); + + if (StartTag == StringRef::npos) + break; + + // Figure out what kind of chunk we have. + const unsigned UnknownKind = 10000; + unsigned Kind = llvm::StringSwitch<unsigned>(Tag) + .Case("typed-text", CK_TypedText) + .Case("text", CK_Text) + .Case("optional", CK_Optional) + .Case("placeholder", CK_Placeholder) + .Case("informative", CK_Informative) + .Case("current-parameter", CK_CurrentParameter) + .Case("lparen", CK_LeftParen) + .Case("rparen", CK_RightParen) + .Case("lbracket", CK_LeftBracket) + .Case("rbracket", CK_RightBracket) + .Case("lbrace", CK_LeftBrace) + .Case("rbrace", CK_RightBrace) + .Case("langle", CK_LeftAngle) + .Case("rangle", CK_RightAngle) + .Case("comma", CK_Comma) + .Default(UnknownKind); + + // If we've hit a terminator tag, we're done. + if (Terminator) + break; + + // Consume the tag. + Str = Str.substr(AfterTag); + + // Handle standalone tags now, since they don't need to be matched to + // anything. + if (Standalone) { + // Ignore anything we don't know about. + if (Kind == UnknownKind) + continue; + + switch ((ChunkKind)Kind) { + case CK_TypedText: + case CK_Text: + case CK_Optional: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: + // There is no point in creating empty chunks of these kinds. + 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: + Result->AddChunk(Chunk((ChunkKind)Kind)); + break; + } + + continue; + } + + if (Kind == CK_Optional) { + // Deserialize the optional code-completion string. + std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str)); + Result->AddOptionalChunk(Optional); + } + + StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone, + Terminator); + if (StartTag == StringRef::npos || !Terminator || Standalone) + break; // Parsing failed; just give up. + + if (EndTag.empty() || Tag == EndTag) { + // Found the matching end tag. Add this chunk based on the text + // between the tags, then consume that input. + StringRef Text = Str.substr(0, StartTag); + switch ((ChunkKind)Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + 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: + Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text))); + break; + + case CK_Optional: + // We've already added the optional chunk. + break; + } + } + + // Remove this tag. + Str = Str.substr(AfterTag); + } while (!Str.empty()); + + return Result; +} + //===----------------------------------------------------------------------===// // Code completion overload candidate implementation //===----------------------------------------------------------------------===// @@ -193,3 +568,85 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, // FIXME: Move this somewhere else! SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } + +void +CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, + unsigned NumResults) { + // Print the results. + for (unsigned I = 0; I != NumResults; ++I) { + OS << "COMPLETION:" << Results[I].Rank << ":"; + switch (Results[I].Kind) { + case Result::RK_Declaration: + if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) { + if (Record->isStruct()) + OS << "Struct:"; + else if (Record->isUnion()) + OS << "Union:"; + else + OS << "Class:"; + } else if (ObjCMethodDecl *Method + = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) { + if (Method->isInstanceMethod()) + OS << "ObjCInstanceMethod:"; + else + OS << "ObjCClassMethod:"; + } else { + OS << Results[I].Declaration->getDeclKindName() << ":"; + } + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + CCS->Serialize(OS); + delete CCS; + } else { + OS << "<typed-text>" + << Results[I].Declaration->getNameAsString() + << "</>"; + } + + OS << '\n'; + break; + + case Result::RK_Keyword: + OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n"; + break; + + case Result::RK_Macro: { + OS << "Macro:"; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + CCS->Serialize(OS); + delete CCS; + } else { + OS << "<typed-text>" << Results[I].Macro->getName() << "</>"; + } + OS << '\n'; + break; + } + } + } + + // Once we've printed the code-completion results, suppress remaining + // diagnostics. + // FIXME: Move this somewhere else! + SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); +} + +void +CIndexCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + for (unsigned I = 0; I != NumCandidates; ++I) { + if (CodeCompletionString *CCS + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { + OS << "OVERLOAD:"; + CCS->Serialize(OS); + OS << '\n'; + delete CCS; + } + } + + // Once we've printed the code-completion results, suppress remaining + // diagnostics. + // FIXME: Move this somewhere else! + SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e9df17d6a1..9963fc3d45 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -187,8 +187,7 @@ getRequiredQualification(ASTContext &Context, Context.getTypeDeclType(TD).getTypePtr()); else assert(Parent->isTranslationUnit()); - } - + } return Result; } @@ -674,6 +673,8 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, static void AddFunctionParameterChunks(ASTContext &Context, FunctionDecl *Function, CodeCompletionString *Result) { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionString *CCStr = Result; for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) { @@ -688,7 +689,7 @@ static void AddFunctionParameterChunks(ASTContext &Context, } if (P != 0) - CCStr->AddTextChunk(", "); + CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Format the placeholder string. std::string PlaceholderStr; @@ -713,6 +714,8 @@ static void AddTemplateParameterChunks(ASTContext &Context, TemplateDecl *Template, CodeCompletionString *Result, unsigned MaxParameters = 0) { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionString *CCStr = Result; bool FirstParameter = true; @@ -768,7 +771,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, if (FirstParameter) FirstParameter = false; else - CCStr->AddTextChunk(", "); + CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Add the placeholder string. CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); @@ -803,6 +806,8 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, /// result is all that is needed. CodeCompletionString * CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { + typedef CodeCompletionString::Chunk Chunk; + if (Kind == RK_Keyword) return 0; @@ -813,12 +818,12 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { // Format a function-like macro with placeholders for the arguments. CodeCompletionString *Result = new CodeCompletionString; - Result->AddTextChunk(Macro->getName().str().c_str()); - Result->AddTextChunk("("); + Result->AddTypedTextChunk(Macro->getName().str().c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); A != AEnd; ++A) { if (A != MI->arg_begin()) - Result->AddTextChunk(", "); + Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); if (!MI->isVariadic() || A != AEnd - 1) { // Non-variadic argument. @@ -837,21 +842,28 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddPlaceholderChunk(Arg.c_str()); } } - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } assert(Kind == RK_Declaration && "Missed a macro kind?"); NamedDecl *ND = Declaration; + if (StartsNestedNameSpecifier) { + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTypedTextChunk(ND->getNameAsString().c_str()); + Result->AddTextChunk("::"); + return Result; + } + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTextChunk(Function->getNameAsString().c_str()); - Result->AddTextChunk("("); + Result->AddTypedTextChunk(Function->getNameAsString().c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -860,7 +872,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - Result->AddTextChunk(Function->getNameAsString().c_str()); + Result->AddTypedTextChunk(Function->getNameAsString().c_str()); // Figure out which template parameters are deduced (or have default // arguments). @@ -884,7 +896,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { else { assert(isa<TemplateTemplateParmDecl>(Param)); HasDefaultArg - = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument(); + = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument(); } if (!HasDefaultArg) @@ -896,16 +908,16 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { // Some of the function template arguments cannot be deduced from a // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. - Result->AddTextChunk("<"); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, FunTmpl, Result, LastDeducibleArgument); - Result->AddTextChunk(">"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } // Add the function parameters - Result->AddTextChunk("("); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -913,20 +925,18 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTextChunk(Template->getNameAsString().c_str()); - Result->AddTextChunk("<"); + Result->AddTypedTextChunk(Template->getNameAsString().c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, Template, Result); - Result->AddTextChunk(">"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); return Result; } - if (Qualifier || StartsNestedNameSpecifier) { + if (Qualifier) { CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTextChunk(ND->getNameAsString().c_str()); - if (StartsNestedNameSpecifier) - Result->AddTextChunk("::"); + Result->AddTypedTextChunk(ND->getNameAsString().c_str()); return Result; } @@ -937,6 +947,8 @@ CodeCompletionString * CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, Sema &S) const { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionString *Result = new CodeCompletionString; FunctionDecl *FDecl = getFunction(); const FunctionProtoType *Proto @@ -947,9 +959,9 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( const FunctionType *FT = getFunctionType(); Result->AddTextChunk( FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); - Result->AddTextChunk("("); - Result->AddPlaceholderChunk("..."); - Result->AddTextChunk("("); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -959,11 +971,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( Result->AddTextChunk( Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); - Result->AddTextChunk("("); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs(); for (unsigned I = 0; I != NumParams; ++I) { if (I) - Result->AddTextChunk(", "); + Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); std::string ArgString; QualType ArgType; @@ -978,19 +990,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy); if (I == CurrentArg) - Result->AddPlaceholderChunk(ArgString.c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, + ArgString.c_str())); else Result->AddTextChunk(ArgString.c_str()); } if (Proto && Proto->isVariadic()) { - Result->AddTextChunk(", "); + Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); if (CurrentArg < NumParams) Result->AddTextChunk("..."); else - Result->AddPlaceholderChunk("..."); + Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); } - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -1049,11 +1062,11 @@ namespace { }; } -// Add all of the known macros as code-completion results. static void AddMacroResults(Preprocessor &PP, unsigned Rank, ResultBuilder &Results) { Results.EnterNewScope(); - for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); + for (Preprocessor::macro_iterator M = PP.macro_begin(), + MEnd = PP.macro_end(); M != MEnd; ++M) Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); Results.ExitScope(); @@ -1073,7 +1086,8 @@ void Sema::CodeCompleteOrdinaryName(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1130,7 +1144,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, } // Add macros - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); // Hand off the results found for code completion. HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); @@ -1177,7 +1192,8 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { NextRank, CurContext, Results); } - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1255,7 +1271,8 @@ void Sema::CodeCompleteCase(Scope *S) { } Results.ExitScope(); - AddMacroResults(PP, 1, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1350,7 +1367,8 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); - AddMacroResults(PP, NextRank + 1, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank + 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1371,7 +1389,8 @@ void Sema::CodeCompleteUsing(Scope *S) { 0, CurContext, Results); Results.ExitScope(); - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1386,7 +1405,8 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); Results.ExitScope(); - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1421,7 +1441,8 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } - AddMacroResults(PP, 1, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1433,7 +1454,8 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1464,7 +1486,8 @@ void Sema::CodeCompleteOperatorName(Scope *S) { NextRank + 1, CurContext, Results); Results.ExitScope(); - AddMacroResults(PP, NextRank, Results); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } |