From 3f7c7f48654230d8e379214cfe49fcf2fde0a2c6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 30 Oct 2009 16:50:04 +0000 Subject: [PATCH] Include macros in code-completion results git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85594 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/CodeCompleteConsumer.h | 13 +++- lib/Sema/CodeCompleteConsumer.cpp | 11 +++ lib/Sema/SemaCodeComplete.cpp | 90 +++++++++++++++++++---- test/CodeCompletion/macros.c | 37 ++++++++++ 4 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 test/CodeCompletion/macros.c diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index d2f509df7b..5b3522c9eb 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -26,6 +26,7 @@ namespace clang { class FunctionDecl; class FunctionType; class FunctionTemplateDecl; +class IdentifierInfo; class NamedDecl; class NestedNameSpecifier; class Sema; @@ -150,7 +151,8 @@ public: /// \brief Describes the kind of result generated. enum ResultKind { RK_Declaration = 0, //< Refers to a declaration - RK_Keyword //< Refers to a keyword or symbol. + RK_Keyword, //< Refers to a keyword or symbol. + RK_Macro //< Refers to a macro }; /// \brief The kind of result stored here. @@ -164,6 +166,9 @@ public: /// \brief When Kind == RK_Keyword, the string representing the keyword /// or symbol's spelling. const char *Keyword; + + /// \brief When Kind == RK_Macro, the identifier that refers to a macro. + IdentifierInfo *Macro; }; /// \brief Describes how good this result is, with zero being the best @@ -199,6 +204,12 @@ public: QualifierIsInformative(0), StartsNestedNameSpecifier(false), Qualifier(0) { } + /// \brief Build a result that refers to a macro. + Result(IdentifierInfo *Macro, unsigned Rank) + : Kind(RK_Macro), Macro(Macro), Rank(Rank), Hidden(false), + QualifierIsInformative(0), StartsNestedNameSpecifier(false), + Qualifier(0) { } + /// \brief Retrieve the declaration stored in this result. NamedDecl *getDeclaration() const { assert(Kind == RK_Declaration && "Not a declaration result"); diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index c78ab5b3e9..9b24d55f3e 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -156,6 +156,17 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, case Result::RK_Keyword: OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; break; + + case Result::RK_Macro: { + OS << Results[I].Macro->getName() << " : " << Results[I].Rank; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + OS << " : " << CCS->getAsString(); + delete CCS; + } + OS << '\n'; + break; + } } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 9e4bb35c65..e9df17d6a1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,6 +13,8 @@ #include "Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include @@ -801,9 +803,45 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, /// result is all that is needed. CodeCompletionString * CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { - if (Kind != RK_Declaration) + if (Kind == RK_Keyword) return 0; + if (Kind == RK_Macro) { + MacroInfo *MI = S.PP.getMacroInfo(Macro); + if (!MI || !MI->isFunctionLike()) + return 0; + + // Format a function-like macro with placeholders for the arguments. + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTextChunk(Macro->getName().str().c_str()); + Result->AddTextChunk("("); + for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); + A != AEnd; ++A) { + if (A != MI->arg_begin()) + Result->AddTextChunk(", "); + + if (!MI->isVariadic() || A != AEnd - 1) { + // Non-variadic argument. + Result->AddPlaceholderChunk((*A)->getName().str().c_str()); + continue; + } + + // Variadic argument; cope with the different between GNU and C99 + // variadic macros, providing a single placeholder for the rest of the + // arguments. + if ((*A)->isStr("__VA_ARGS__")) + Result->AddPlaceholderChunk("..."); + else { + std::string Arg = (*A)->getName(); + Arg += "..."; + Result->AddPlaceholderChunk(Arg.c_str()); + } + } + Result->AddTextChunk(")"); + return Result; + } + + assert(Kind == RK_Declaration && "Missed a macro kind?"); NamedDecl *ND = Declaration; if (FunctionDecl *Function = dyn_cast(ND)) { @@ -999,6 +1037,10 @@ namespace { case Result::RK_Keyword: return strcmp(X.Keyword, Y.Keyword) < 0; + + case Result::RK_Macro: + return llvm::LowercaseString(X.Macro->getName()) < + llvm::LowercaseString(Y.Macro->getName()); } // Silence GCC warning. @@ -1007,6 +1049,16 @@ 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(); + M != MEnd; ++M) + Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); + Results.ExitScope(); +} + static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, CodeCompleteConsumer::Result *Results, unsigned NumResults) { @@ -1019,8 +1071,9 @@ static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, void Sema::CodeCompleteOrdinaryName(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1076,6 +1129,9 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, CurContext, Results); } + // Add macros + AddMacroResults(PP, NextRank, Results); + // Hand off the results found for code completion. HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); @@ -1117,10 +1173,11 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { // We could have the start of a nested-name-specifier. Add those // results as well. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, - CurContext, Results); + NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + NextRank, CurContext, Results); } + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1198,6 +1255,7 @@ void Sema::CodeCompleteCase(Scope *S) { } Results.ExitScope(); + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1292,6 +1350,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + AddMacroResults(PP, NextRank + 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1308,10 +1367,11 @@ void Sema::CodeCompleteUsing(Scope *S) { // After "using", we can see anything that would start a // nested-name-specifier. - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, - CurContext, Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1323,9 +1383,10 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { // alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1360,6 +1421,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1369,8 +1431,9 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1397,10 +1460,11 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add any nested-name-specifiers Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1, - CurContext, Results); + NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + NextRank + 1, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } diff --git a/test/CodeCompletion/macros.c b/test/CodeCompletion/macros.c new file mode 100644 index 0000000000..d5c1f8f17f --- /dev/null +++ b/test/CodeCompletion/macros.c @@ -0,0 +1,37 @@ +#define FOO +#define BAR(X, Y) X, Y +#define IDENTITY(X) X +#define WIBBLE(...) + +enum Color { + Red, Green, Blue +}; + +struct Point { + float x, y, z; + enum Color color; +}; + +void test(struct Point *p) { + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:17:14 %s -o - | FileCheck -check-prefix=CC1 %s && + switch (p->IDENTITY(color)) { + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC2 %s && + case + } + // CC1: color + // CC1: x + // CC1: y + // CC1: z + // CC1: BAR(<#X#>, <#Y#>) + // CC1: FOO + // CC1: IDENTITY(<#X#>) + // CC1: WIBBLE + // CC2: Blue + // CC2: Green + // CC2: Red + // CC2: BAR(<#X#>, <#Y#>) + // CC2: FOO + // CC2: IDENTITY(<#X#>) + // CC2: WIBBLE + // RUN: true +} -- 2.40.0