mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 21:06:06 +00:00
Introduce four new code-completion hooks for C++:
- after "using", show anything that can be a nested-name-specifier. - after "using namespace", show any visible namespaces or namespace aliases - after "namespace", show any namespace definitions in the current scope - after "namespace identifier = ", show any visible namespaces or namespace aliases llvm-svn: 82251
This commit is contained in:
parent
559d9741a8
commit
7e90c6db18
@ -2233,10 +2233,43 @@ public:
|
||||
///
|
||||
/// \param SS the scope specifier ending with "::".
|
||||
///
|
||||
/// \parameter EnteringContext whether we're entering the context of this
|
||||
/// \parame EnteringContext whether we're entering the context of this
|
||||
/// scope specifier.
|
||||
virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
|
||||
bool EnteringContext) { }
|
||||
|
||||
/// \brief Code completion for a C++ "using" declaration or directive.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after the "using" keyword.
|
||||
///
|
||||
/// \param S the scope in which the "using" occurs.
|
||||
virtual void CodeCompleteUsing(Scope *S) { }
|
||||
|
||||
/// \brief Code completion for a C++ using directive.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after "using namespace".
|
||||
///
|
||||
/// \param S the scope in which the "using namespace" occurs.
|
||||
virtual void CodeCompleteUsingDirective(Scope *S) { }
|
||||
|
||||
/// \brief Code completion for a C++ namespace declaration or namespace
|
||||
/// alias declaration.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after "namespace".
|
||||
///
|
||||
/// \param S the scope in which the "namespace" token occurs.
|
||||
virtual void CodeCompleteNamespaceDecl(Scope *S) { }
|
||||
|
||||
/// \brief Code completion for a C++ namespace alias declaration.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after "namespace identifier = ".
|
||||
///
|
||||
/// \param S the scope in which the namespace alias declaration occurs.
|
||||
virtual void CodeCompleteNamespaceAliasDecl(Scope *S) { }
|
||||
//@}
|
||||
};
|
||||
|
||||
|
@ -187,6 +187,39 @@ public:
|
||||
/// the qualified-id.
|
||||
virtual void CodeCompleteQualifiedId(Scope *S, NestedNameSpecifier *NNS,
|
||||
bool EnteringContext);
|
||||
|
||||
/// \brief Code completion for a C++ "using" declaration or directive.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after the "using" keyword.
|
||||
///
|
||||
/// \param S the scope in which the "using" occurs.
|
||||
virtual void CodeCompleteUsing(Scope *S);
|
||||
|
||||
/// \brief Code completion for a C++ using directive.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after "using namespace".
|
||||
///
|
||||
/// \param S the scope in which the "using namespace" occurs.
|
||||
virtual void CodeCompleteUsingDirective(Scope *S);
|
||||
|
||||
/// \brief Code completion for a C++ namespace declaration or namespace
|
||||
/// alias declaration.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after "namespace".
|
||||
///
|
||||
/// \param S the scope in which the "namespace" token occurs.
|
||||
virtual void CodeCompleteNamespaceDecl(Scope *S);
|
||||
|
||||
/// \brief Code completion for a C++ namespace alias declaration.
|
||||
///
|
||||
/// This code completion action is invoked when the code-completion token is
|
||||
/// found after "namespace identifier = ".
|
||||
///
|
||||
/// \param S the scope in which the namespace alias declaration occurs.
|
||||
virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
|
||||
//@}
|
||||
|
||||
/// \name Name lookup functions
|
||||
@ -213,6 +246,8 @@ public:
|
||||
bool IsEnum(NamedDecl *ND) const;
|
||||
bool IsClassOrStruct(NamedDecl *ND) const;
|
||||
bool IsUnion(NamedDecl *ND) const;
|
||||
bool IsNamespace(NamedDecl *ND) const;
|
||||
bool IsNamespaceOrAlias(NamedDecl *ND) const;
|
||||
//@}
|
||||
|
||||
/// \name Utility functions
|
||||
|
@ -47,6 +47,11 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
|
||||
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
|
||||
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
Actions.CodeCompleteNamespaceDecl(CurScope);
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
SourceLocation IdentLoc;
|
||||
IdentifierInfo *Ident = 0;
|
||||
|
||||
@ -115,6 +120,11 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
|
||||
|
||||
ConsumeToken(); // eat the '='.
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
Actions.CodeCompleteNamespaceAliasDecl(CurScope);
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
CXXScopeSpec SS;
|
||||
// Parse (optional) nested-name-specifier.
|
||||
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
||||
@ -188,6 +198,11 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
||||
// Eat 'using'.
|
||||
SourceLocation UsingLoc = ConsumeToken();
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
Actions.CodeCompleteUsing(CurScope);
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
if (Tok.is(tok::kw_namespace))
|
||||
// Next token after 'using' is 'namespace' so it must be using-directive
|
||||
return ParseUsingDirective(Context, UsingLoc, DeclEnd);
|
||||
@ -214,6 +229,11 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
|
||||
// Eat 'namespace'.
|
||||
SourceLocation NamespcLoc = ConsumeToken();
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
Actions.CodeCompleteUsingDirective(CurScope);
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
CXXScopeSpec SS;
|
||||
// Parse (optional) nested-name-specifier.
|
||||
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
||||
|
@ -118,6 +118,63 @@ CodeCompleteConsumer::CodeCompleteQualifiedId(Scope *S,
|
||||
ProcessCodeCompleteResults(Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void CodeCompleteConsumer::CodeCompleteUsing(Scope *S) {
|
||||
ResultSet Results(*this, &CodeCompleteConsumer::IsNestedNameSpecifier);
|
||||
|
||||
// If we aren't in class scope, we could see the "namespace" keyword.
|
||||
if (!S->isClassScope())
|
||||
Results.MaybeAddResult(Result("namespace", 0));
|
||||
|
||||
// After "using", we can see anything that would start a
|
||||
// nested-name-specifier.
|
||||
CollectLookupResults(S, 0, Results);
|
||||
|
||||
ProcessCodeCompleteResults(Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void CodeCompleteConsumer::CodeCompleteUsingDirective(Scope *S) {
|
||||
// After "using namespace", we expect to see a namespace name or namespace
|
||||
// alias.
|
||||
ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias);
|
||||
CollectLookupResults(S, 0, Results);
|
||||
ProcessCodeCompleteResults(Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void CodeCompleteConsumer::CodeCompleteNamespaceDecl(Scope *S) {
|
||||
ResultSet Results(*this, &CodeCompleteConsumer::IsNamespace);
|
||||
DeclContext *Ctx = (DeclContext *)S->getEntity();
|
||||
if (!S->getParent())
|
||||
Ctx = getSema().Context.getTranslationUnitDecl();
|
||||
|
||||
if (Ctx && Ctx->isFileContext()) {
|
||||
// We only want to see those namespaces that have already been defined
|
||||
// within this scope, because its likely that the user is creating an
|
||||
// extended namespace declaration. Keep track of the most recent
|
||||
// definition of each namespace.
|
||||
std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest;
|
||||
for (DeclContext::specific_decl_iterator<NamespaceDecl>
|
||||
NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end());
|
||||
NS != NSEnd; ++NS)
|
||||
OrigToLatest[NS->getOriginalNamespace()] = *NS;
|
||||
|
||||
// Add the most recent definition (or extended definition) of each
|
||||
// namespace to the list of results.
|
||||
for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
|
||||
NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
|
||||
NS != NSEnd; ++NS)
|
||||
Results.MaybeAddResult(Result(NS->second, 0));
|
||||
}
|
||||
|
||||
ProcessCodeCompleteResults(Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void CodeCompleteConsumer::CodeCompleteNamespaceAliasDecl(Scope *S) {
|
||||
// After "namespace", we expect to see a namespace or alias.
|
||||
ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias);
|
||||
CollectLookupResults(S, 0, 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.
|
||||
@ -454,6 +511,17 @@ bool CodeCompleteConsumer::IsUnion(NamedDecl *ND) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Determines whether the given declaration is a namespace.
|
||||
bool CodeCompleteConsumer::IsNamespace(NamedDecl *ND) const {
|
||||
return isa<NamespaceDecl>(ND);
|
||||
}
|
||||
|
||||
/// \brief Determines whether the given declaration is a namespace or
|
||||
/// namespace alias.
|
||||
bool CodeCompleteConsumer::IsNamespaceOrAlias(NamedDecl *ND) const {
|
||||
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct VISIBILITY_HIDDEN SortCodeCompleteResult {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
|
@ -3635,11 +3635,13 @@ public:
|
||||
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
|
||||
SourceLocation OpLoc,
|
||||
bool IsArrow);
|
||||
|
||||
virtual void CodeCompleteTag(Scope *S, unsigned TagSpec);
|
||||
|
||||
virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
|
||||
bool EnteringContext);
|
||||
virtual void CodeCompleteUsing(Scope *S);
|
||||
virtual void CodeCompleteUsingDirective(Scope *S);
|
||||
virtual void CodeCompleteNamespaceDecl(Scope *S);
|
||||
virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
|
||||
//@}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -72,3 +72,33 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
|
||||
(NestedNameSpecifier *)SS.getScopeRep(),
|
||||
EnteringContext);
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteUsing(Scope *S) {
|
||||
if (!CodeCompleter)
|
||||
return;
|
||||
|
||||
CodeCompleter->CodeCompleteUsing(S);
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteUsingDirective(Scope *S) {
|
||||
if (!CodeCompleter)
|
||||
return;
|
||||
|
||||
CodeCompleter->CodeCompleteUsingDirective(S);
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteNamespaceDecl(Scope *S) {
|
||||
if (!CodeCompleter)
|
||||
return;
|
||||
|
||||
CodeCompleter->CodeCompleteNamespaceDecl(S);
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
|
||||
if (!CodeCompleter)
|
||||
return;
|
||||
|
||||
CodeCompleter->CodeCompleteNamespaceAliasDecl(S);
|
||||
}
|
||||
|
||||
|
||||
|
22
clang/test/CodeCompletion/namespace-alias.cpp
Normal file
22
clang/test/CodeCompletion/namespace-alias.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N4 {
|
||||
namespace N3 { }
|
||||
}
|
||||
|
||||
class N3;
|
||||
|
||||
namespace N2 {
|
||||
namespace I1 { }
|
||||
namespace I4 = I1;
|
||||
namespace I5 { }
|
||||
namespace I1 { }
|
||||
|
||||
// CHECK-CC1: I1 : 1
|
||||
// CHECK-CC1: I4 : 1
|
||||
// CHECK-CC1: I5 : 1
|
||||
// CHECK-CC1: N2 : 2
|
||||
// CHECK-NEXT-CC1: N4 : 2
|
||||
namespace New =
|
||||
|
15
clang/test/CodeCompletion/namespace.cpp
Normal file
15
clang/test/CodeCompletion/namespace.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N3 {
|
||||
}
|
||||
|
||||
namespace N2 {
|
||||
namespace I1 { }
|
||||
namespace I4 = I1;
|
||||
namespace I5 { }
|
||||
namespace I1 { }
|
||||
|
||||
// CHECK-CC1: I1 : 0
|
||||
// CHECK-NEXT-CC1: I5 : 0
|
||||
namespace
|
24
clang/test/CodeCompletion/using-namespace.cpp
Normal file
24
clang/test/CodeCompletion/using-namespace.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N4 {
|
||||
namespace N3 { }
|
||||
}
|
||||
|
||||
class N3;
|
||||
|
||||
namespace N2 {
|
||||
namespace I1 { }
|
||||
namespace I4 = I1;
|
||||
namespace I5 { }
|
||||
namespace I1 { }
|
||||
|
||||
void foo() {
|
||||
// CHECK-CC1: I1 : 2
|
||||
// CHECK-CC1: I4 : 2
|
||||
// CHECK-CC1: I5 : 2
|
||||
// CHECK-CC1: N2 : 3
|
||||
// CHECK-NEXT-CC1: N4 : 3
|
||||
using namespace
|
||||
|
||||
|
27
clang/test/CodeCompletion/using.cpp
Normal file
27
clang/test/CodeCompletion/using.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N4 {
|
||||
namespace N3 { }
|
||||
}
|
||||
|
||||
class N3;
|
||||
|
||||
namespace N2 {
|
||||
namespace I1 { }
|
||||
namespace I4 = I1;
|
||||
namespace I5 { }
|
||||
namespace I1 { }
|
||||
|
||||
void foo() {
|
||||
int N3;
|
||||
|
||||
// CHECK-CC1: I1 : 2
|
||||
// CHECK-CC1: I4 : 2
|
||||
// CHECK-CC1: I5 : 2
|
||||
// CHECK-CC1: N2 : 3
|
||||
// CHECK-CC1: N3 : 3
|
||||
// CHECK-NEXT-CC1: N4 : 3
|
||||
using
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user