From ed8d322b4086b8b1e1f78b21389cabb23457dcb3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 18 Sep 2009 20:05:18 +0000 Subject: [PATCH] C++ code completion after the "operator" keyword. Provide overloaded operators, type specifiers, type names, and nested-name-specifiers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82264 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Action.h | 8 +++ include/clang/Sema/CodeCompleteConsumer.h | 16 +++-- lib/Parse/ParseExprCXX.cpp | 12 ++++ lib/Sema/CodeCompleteConsumer.cpp | 77 ++++++++++++++++++++++- lib/Sema/Sema.h | 1 + lib/Sema/SemaCodeComplete.cpp | 6 ++ test/CodeCompletion/operator.cpp | 19 ++++++ 7 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 test/CodeCompletion/operator.cpp diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 5df0b1f596..2d37b86a28 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2270,6 +2270,14 @@ public: /// /// \param S the scope in which the namespace alias declaration occurs. virtual void CodeCompleteNamespaceAliasDecl(Scope *S) { } + + /// \brief Code completion for an operator name. + /// + /// This code completion action is invoked when the code-completion token is + /// found after the keyword "operator". + /// + /// \param S the scope in which the operator keyword occurs. + virtual void CodeCompleteOperatorName(Scope *S) { } //@} }; diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index d8d2bcc311..821678b22a 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -219,7 +219,15 @@ public: /// found after "namespace identifier = ". /// /// \param S the scope in which the namespace alias declaration occurs. - virtual void CodeCompleteNamespaceAliasDecl(Scope *S); + virtual void CodeCompleteNamespaceAliasDecl(Scope *S); + + /// \brief Code completion for an operator name. + /// + /// This code completion action is invoked when the code-completion token is + /// found after the keyword "operator". + /// + /// \param S the scope in which the operator keyword occurs. + virtual void CodeCompleteOperatorName(Scope *S); //@} /// \name Name lookup functions @@ -248,14 +256,14 @@ public: bool IsUnion(NamedDecl *ND) const; bool IsNamespace(NamedDecl *ND) const; bool IsNamespaceOrAlias(NamedDecl *ND) const; + bool IsType(NamedDecl *ND) const; //@} /// \name Utility functions /// - //@{ - + //@{ bool canHiddenResultBeFound(NamedDecl *Hidden, NamedDecl *Visible); - + void AddTypeSpecifierResults(unsigned Rank, ResultSet &Results); //@} }; diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 4c0f699b3f..325f085a49 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -835,6 +835,18 @@ Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) { *EndLoc = Loc; return OO_Subscript; + case tok::code_completion: { + // Code completion for the operator name. + Actions.CodeCompleteOperatorName(CurScope); + + // Consume the 'operator' token, then replace the code-completion token + // with an 'operator' token and try again. + SourceLocation OperatorLoc = ConsumeToken(); + Tok.setLocation(OperatorLoc); + Tok.setKind(tok::kw_operator); + return TryParseOperatorFunctionId(EndLoc); + } + default: return OO_None; } diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index fd187c5ef9..d82047d912 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -175,6 +175,28 @@ void CodeCompleteConsumer::CodeCompleteNamespaceAliasDecl(Scope *S) { ProcessCodeCompleteResults(Results.data(), Results.size()); } +void CodeCompleteConsumer::CodeCompleteOperatorName(Scope *S) { + ResultSet Results(*this, &CodeCompleteConsumer::IsType); + + // Add the names of overloadable operators. +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + if (strcmp(Spelling, "?")) \ + Results.MaybeAddResult(Result(Spelling, 0)); +#include "clang/Basic/OperatorKinds.def" + + // Add any type names visible from the current scope + unsigned NextRank = CollectLookupResults(S, 0, Results); + + // Add any type specifiers + AddTypeSpecifierResults(0, Results); + + // Add any nested-name-specifiers + Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier); + CollectLookupResults(S, NextRank + 1, Results); + + ProcessCodeCompleteResults(Results.data(), Results.size()); +} + void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) { if (R.Kind != Result::RK_Declaration) { // For non-declaration results, just add the result. @@ -208,7 +230,7 @@ void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) { if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { // __va_list_tag is a freak of nature. Find it and skip it. - if (Id->isStr("__va_list_tag")) + if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list")) return; // FIXME: Should we filter out other names in the implementation's @@ -522,6 +544,12 @@ bool CodeCompleteConsumer::IsNamespaceOrAlias(NamedDecl *ND) const { return isa(ND) || isa(ND); } +/// \brief Brief determines whether the given declaration is a namespace or +/// namespace alias. +bool CodeCompleteConsumer::IsType(NamedDecl *ND) const { + return isa(ND); +} + namespace { struct VISIBILITY_HIDDEN SortCodeCompleteResult { typedef CodeCompleteConsumer::Result Result; @@ -588,6 +616,53 @@ bool CodeCompleteConsumer::canHiddenResultBeFound(NamedDecl *Hidden, return HiddenCtx != Visible->getDeclContext()->getLookupContext(); } +/// \brief Add type specifiers for the current language as keyword results. +void CodeCompleteConsumer::AddTypeSpecifierResults(unsigned Rank, + ResultSet &Results) { + Results.MaybeAddResult(Result("short", Rank)); + Results.MaybeAddResult(Result("long", Rank)); + Results.MaybeAddResult(Result("signed", Rank)); + Results.MaybeAddResult(Result("unsigned", Rank)); + Results.MaybeAddResult(Result("void", Rank)); + Results.MaybeAddResult(Result("char", Rank)); + Results.MaybeAddResult(Result("int", Rank)); + Results.MaybeAddResult(Result("float", Rank)); + Results.MaybeAddResult(Result("double", Rank)); + Results.MaybeAddResult(Result("enum", Rank)); + Results.MaybeAddResult(Result("struct", Rank)); + Results.MaybeAddResult(Result("union", Rank)); + + if (getSema().getLangOptions().C99) { + // C99-specific + Results.MaybeAddResult(Result("_Complex", Rank)); + Results.MaybeAddResult(Result("_Imaginary", Rank)); + Results.MaybeAddResult(Result("_Bool", Rank)); + } + + if (getSema().getLangOptions().CPlusPlus) { + // C++-specific + Results.MaybeAddResult(Result("bool", Rank)); + Results.MaybeAddResult(Result("class", Rank)); + Results.MaybeAddResult(Result("typename", Rank)); + Results.MaybeAddResult(Result("wchar_t", Rank)); + + if (getSema().getLangOptions().CPlusPlus0x) { + Results.MaybeAddResult(Result("char16_t", Rank)); + Results.MaybeAddResult(Result("char32_t", Rank)); + Results.MaybeAddResult(Result("decltype", Rank)); + } + } + + // GNU extensions + if (getSema().getLangOptions().GNUMode) { + // FIXME: Enable when we actually support decimal floating point. + // Results.MaybeAddResult(Result("_Decimal32", Rank)); + // Results.MaybeAddResult(Result("_Decimal64", Rank)); + // Results.MaybeAddResult(Result("_Decimal128", Rank)); + Results.MaybeAddResult(Result("typeof", Rank)); + } +} + void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, unsigned NumResults) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 8bec9d54f5..abbf1c3bff 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3642,6 +3642,7 @@ public: virtual void CodeCompleteUsingDirective(Scope *S); virtual void CodeCompleteNamespaceDecl(Scope *S); virtual void CodeCompleteNamespaceAliasDecl(Scope *S); + virtual void CodeCompleteOperatorName(Scope *S); //@} //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 50b8ffd1f4..adb0469cf0 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -101,4 +101,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { CodeCompleter->CodeCompleteNamespaceAliasDecl(S); } +void Sema::CodeCompleteOperatorName(Scope *S) { + if (!CodeCompleter) + return; + + CodeCompleter->CodeCompleteOperatorName(S); +} diff --git a/test/CodeCompletion/operator.cpp b/test/CodeCompletion/operator.cpp new file mode 100644 index 0000000000..808940526f --- /dev/null +++ b/test/CodeCompletion/operator.cpp @@ -0,0 +1,19 @@ +// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s && +// RUN: true + +class T { }; + +typedef int Integer; + +namespace N { } + +void f() { + typedef float Float; + + // CHECK-CC1: Float : 0 + // CHECK-CC1: + : 0 + // CHECK-CC1: short : 0 + // CHECK-CC1: Integer : 2 + // CHECK-CC1: T : 2 + // CHECK-CC1: N : 5 + operator -- 2.40.0