forked from OSchip/llvm-project
[CodeCompletion] Code complete the missing C++11 keywords
This commit adds context sensitive code completion support for the C++11 keywords that currently don't have completion results. The following keywords are supported by this patch: alignas constexpr static_assert noexcept (as a function/method qualifier) thread_local The following special identifiers are also supported: final (as a method qualifier or class qualifier) override rdar://29219185 Differential Revision: https://reviews.llvm.org/D28286 llvm-svn: 295001
This commit is contained in:
parent
5be2e8415c
commit
8f4d399c99
|
@ -2385,10 +2385,10 @@ private:
|
|||
AR_DeclspecAttributesParsed
|
||||
};
|
||||
|
||||
void ParseTypeQualifierListOpt(DeclSpec &DS,
|
||||
unsigned AttrReqs = AR_AllAttributesParsed,
|
||||
bool AtomicAllowed = true,
|
||||
bool IdentifierRequired = false);
|
||||
void ParseTypeQualifierListOpt(
|
||||
DeclSpec &DS, unsigned AttrReqs = AR_AllAttributesParsed,
|
||||
bool AtomicAllowed = true, bool IdentifierRequired = false,
|
||||
Optional<llvm::function_ref<void()>> CodeCompletionHandler = None);
|
||||
void ParseDirectDeclarator(Declarator &D);
|
||||
void ParseDecompositionDeclarator(Declarator &D);
|
||||
void ParseParenDeclarator(Declarator &D);
|
||||
|
|
|
@ -9820,6 +9820,8 @@ public:
|
|||
void CodeCompletePostfixExpression(Scope *S, ExprResult LHS);
|
||||
void CodeCompleteTag(Scope *S, unsigned TagSpec);
|
||||
void CodeCompleteTypeQualifiers(DeclSpec &DS);
|
||||
void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D,
|
||||
const VirtSpecifiers *VS = nullptr);
|
||||
void CodeCompleteBracketDeclarator(Scope *S);
|
||||
void CodeCompleteCase(Scope *S);
|
||||
void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args);
|
||||
|
|
|
@ -4802,9 +4802,10 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
|
|||
/// [ only if AttReqs & AR_CXX11AttributesParsed ]
|
||||
/// Note: vendor can be GNU, MS, etc and can be explicitly controlled via
|
||||
/// AttrRequirements bitmask values.
|
||||
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
|
||||
bool AtomicAllowed,
|
||||
bool IdentifierRequired) {
|
||||
void Parser::ParseTypeQualifierListOpt(
|
||||
DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
|
||||
bool IdentifierRequired,
|
||||
Optional<llvm::function_ref<void()>> CodeCompletionHandler) {
|
||||
if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) &&
|
||||
isCXX11AttributeSpecifier()) {
|
||||
ParsedAttributesWithRange attrs(AttrFactory);
|
||||
|
@ -4822,7 +4823,10 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
|
|||
|
||||
switch (Tok.getKind()) {
|
||||
case tok::code_completion:
|
||||
Actions.CodeCompleteTypeQualifiers(DS);
|
||||
if (CodeCompletionHandler)
|
||||
(*CodeCompletionHandler)();
|
||||
else
|
||||
Actions.CodeCompleteTypeQualifiers(DS);
|
||||
return cutOffParsing();
|
||||
|
||||
case tok::kw_const:
|
||||
|
@ -5748,7 +5752,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
|
||||
// Parse cv-qualifier-seq[opt].
|
||||
ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed,
|
||||
/*AtomicAllowed*/ false);
|
||||
/*AtomicAllowed*/ false,
|
||||
/*IdentifierRequired=*/false,
|
||||
llvm::function_ref<void()>([&]() {
|
||||
Actions.CodeCompleteFunctionQualifiers(DS, D);
|
||||
}));
|
||||
if (!DS.getSourceRange().getEnd().isInvalid()) {
|
||||
EndLoc = DS.getSourceRange().getEnd();
|
||||
ConstQualifierLoc = DS.getConstSpecLoc();
|
||||
|
|
|
@ -2285,7 +2285,11 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
|
|||
|
||||
// GNU-style and C++11 attributes are not allowed here, but they will be
|
||||
// handled by the caller. Diagnose everything else.
|
||||
ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false);
|
||||
ParseTypeQualifierListOpt(
|
||||
DS, AR_NoAttributesParsed, false,
|
||||
/*IdentifierRequired=*/false, llvm::function_ref<void()>([&]() {
|
||||
Actions.CodeCompleteFunctionQualifiers(DS, D, &VS);
|
||||
}));
|
||||
D.ExtendWithDeclSpec(DS);
|
||||
|
||||
if (D.isFunctionDeclarator()) {
|
||||
|
|
|
@ -1370,6 +1370,21 @@ static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC,
|
|||
// in C++0x as a type specifier.
|
||||
Results.AddResult(Result("extern"));
|
||||
Results.AddResult(Result("static"));
|
||||
|
||||
if (LangOpts.CPlusPlus11) {
|
||||
CodeCompletionAllocator &Allocator = Results.getAllocator();
|
||||
CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
|
||||
|
||||
// alignas
|
||||
Builder.AddTypedTextChunk("alignas");
|
||||
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Builder.AddChunk(CodeCompletionString::CK_RightParen);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
|
||||
Results.AddResult(Result("constexpr"));
|
||||
Results.AddResult(Result("thread_local"));
|
||||
}
|
||||
}
|
||||
|
||||
static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC,
|
||||
|
@ -1527,6 +1542,21 @@ static void addThisCompletion(Sema &S, ResultBuilder &Results) {
|
|||
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
|
||||
}
|
||||
|
||||
static void AddStaticAssertResult(CodeCompletionBuilder &Builder,
|
||||
ResultBuilder &Results,
|
||||
const LangOptions &LangOpts) {
|
||||
if (!LangOpts.CPlusPlus11)
|
||||
return;
|
||||
|
||||
Builder.AddTypedTextChunk("static_assert");
|
||||
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Builder.AddChunk(CodeCompletionString::CK_Comma);
|
||||
Builder.AddPlaceholderChunk("message");
|
||||
Builder.AddChunk(CodeCompletionString::CK_RightParen);
|
||||
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
|
||||
}
|
||||
|
||||
/// \brief Add language constructs that show up for "ordinary" names.
|
||||
static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
|
||||
Scope *S,
|
||||
|
@ -1611,6 +1641,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
|
|||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
|
||||
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
|
||||
|
||||
if (CCC == Sema::PCC_Class) {
|
||||
AddTypedefResult(Results);
|
||||
|
||||
|
@ -1824,6 +1856,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
|
|||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("identifier");
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
|
||||
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
|
||||
}
|
||||
|
||||
// Fall through (for statement expressions).
|
||||
|
@ -3483,6 +3517,11 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
|
|||
Results.AddResult(Result("restrict"));
|
||||
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
if (getLangOpts().CPlusPlus11 &&
|
||||
(DS.getTypeSpecType() == DeclSpec::TST_class ||
|
||||
DS.getTypeSpecType() == DeclSpec::TST_struct))
|
||||
Results.AddResult("final");
|
||||
|
||||
if (AllowNonIdentifiers) {
|
||||
Results.AddResult(Result("operator"));
|
||||
}
|
||||
|
@ -4013,30 +4052,54 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
|
|||
Results.data(),Results.size());
|
||||
}
|
||||
|
||||
static void AddTypeQualifierResults(DeclSpec &DS, ResultBuilder &Results,
|
||||
const LangOptions &LangOpts) {
|
||||
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const))
|
||||
Results.AddResult("const");
|
||||
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile))
|
||||
Results.AddResult("volatile");
|
||||
if (LangOpts.C99 && !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
|
||||
Results.AddResult("restrict");
|
||||
if (LangOpts.C11 && !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
|
||||
Results.AddResult("_Atomic");
|
||||
if (LangOpts.MSVCCompat && !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned))
|
||||
Results.AddResult("__unaligned");
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
|
||||
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
|
||||
CodeCompleter->getCodeCompletionTUInfo(),
|
||||
CodeCompletionContext::CCC_TypeQualifiers);
|
||||
Results.EnterNewScope();
|
||||
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const))
|
||||
Results.AddResult("const");
|
||||
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile))
|
||||
Results.AddResult("volatile");
|
||||
if (getLangOpts().C99 &&
|
||||
!(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
|
||||
Results.AddResult("restrict");
|
||||
if (getLangOpts().C11 &&
|
||||
!(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
|
||||
Results.AddResult("_Atomic");
|
||||
if (getLangOpts().MSVCCompat &&
|
||||
!(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned))
|
||||
Results.AddResult("__unaligned");
|
||||
AddTypeQualifierResults(DS, Results, LangOpts);
|
||||
Results.ExitScope();
|
||||
HandleCodeCompleteResults(this, CodeCompleter,
|
||||
Results.getCompletionContext(),
|
||||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D,
|
||||
const VirtSpecifiers *VS) {
|
||||
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
|
||||
CodeCompleter->getCodeCompletionTUInfo(),
|
||||
CodeCompletionContext::CCC_TypeQualifiers);
|
||||
Results.EnterNewScope();
|
||||
AddTypeQualifierResults(DS, Results, LangOpts);
|
||||
if (LangOpts.CPlusPlus11) {
|
||||
Results.AddResult("noexcept");
|
||||
if (D.getContext() == Declarator::MemberContext && !D.isCtorOrDtor() &&
|
||||
!D.isStaticMember()) {
|
||||
if (!VS || !VS->isFinalSpecified())
|
||||
Results.AddResult("final");
|
||||
if (!VS || !VS->isOverrideSpecified())
|
||||
Results.AddResult("override");
|
||||
}
|
||||
}
|
||||
Results.ExitScope();
|
||||
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
|
||||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteBracketDeclarator(Scope *S) {
|
||||
CodeCompleteExpression(S, QualType(getASTContext().getSizeType()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
int function(int x) {
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
int variable = 0;
|
||||
|
||||
class Class {
|
||||
public:
|
||||
Class() { }
|
||||
|
||||
int method(int x) {
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
virtual void virtualMethod() {
|
||||
}
|
||||
|
||||
static void staticMethod() {
|
||||
}
|
||||
|
||||
static int staticVar;
|
||||
};
|
||||
|
||||
class SubClass : public Class {
|
||||
void virtualMethod() override final {
|
||||
}
|
||||
};
|
||||
|
||||
struct Struct {
|
||||
};
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:1:1 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:5:1 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:11:1 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
|
||||
// CHECK-TOP-LEVEL: alignas(<#expression#>)
|
||||
// CHECK-TOP-LEVEL: constexpr
|
||||
// CHECK-TOP-LEVEL: static_assert(<#expression#>, <#message#>)
|
||||
// CHECK-TOP-LEVEL: thread_local
|
||||
// CHECK-TOP-LEVEL-NOT: final
|
||||
// CHECK-TOP-LEVEL-NOT: noexcept
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:1:14 %s | FileCheck --check-prefix=CHECK-PARAM %s
|
||||
// CHECK-PARAM-NOT: alignas
|
||||
// CHECK-PARAM-NOT: constexpr
|
||||
// CHECK-PARAM-NOT: final
|
||||
// CHECK-PARAM-NOT: thread_local
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:21:10 %s | FileCheck --check-prefix=CHECK-STATICVAR1 %s
|
||||
// CHECK-STATICVAR1: constexpr
|
||||
// CHECK-STATICVAR1: thread_local
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:7:13 %s | FileCheck --check-prefix=CHECK-CLASS-QUALIFIER %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:24:16 %s | FileCheck --check-prefix=CHECK-CLASS-QUALIFIER %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:29:15 %s | FileCheck --check-prefix=CHECK-CLASS-QUALIFIER %s
|
||||
// CHECK-CLASS-QUALIFIER: final
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:1:21 %s | FileCheck --check-prefix=CHECK-FUNCTION-QUALIFIER %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:9:11 %s | FileCheck --check-prefix=CHECK-FUNCTION-QUALIFIER %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:18:30 %s | FileCheck --check-prefix=CHECK-FUNCTION-QUALIFIER %s
|
||||
// CHECK-FUNCTION-QUALIFIER: noexcept
|
||||
// CHECK-FUNCTION-QUALIFIER-NOT: final
|
||||
// CHECK-FUNCTION-QUALIFIER-NOT: override
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:11:21 %s | FileCheck --check-prefix=CHECK-METHOD-QUALIFIER %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:15:32 %s | FileCheck --check-prefix=CHECK-METHOD-QUALIFIER %s
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:25:24 %s | FileCheck --check-prefix=CHECK-METHOD-QUALIFIER %s
|
||||
// CHECK-METHOD-QUALIFIER: final
|
||||
// CHECK-METHOD-QUALIFIER: noexcept
|
||||
// CHECK-METHOD-QUALIFIER: override
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:25:33 %s | FileCheck --check-prefix=CHECK-OVERRIDE-SPECIFIED %s
|
||||
// CHECK-OVERRIDE-SPECIFIED: final
|
||||
// CHECK-OVERRIDE-SPECIFIED: noexcept
|
||||
// CHECK-OVERRIDE-SPECIFIED-NOT: override
|
||||
|
||||
// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:25:39 %s | FileCheck --check-prefix=CHECK-OVERRIDE-FINAL-SPECIFIED %s
|
||||
// CHECK-OVERRIDE-FINAL-SPECIFIED: noexcept
|
||||
// CHECK-OVERRIDE-FINAL-SPECIFIED-NOT: final
|
||||
// CHECK-OVERRIDE-FINAL-SPECIFIED-NOT: override
|
|
@ -39,10 +39,12 @@ void foo() {
|
|||
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#size_t#]sizeof...(<#parameter-pack#>)
|
||||
// CHECK-CC1-NEXT: COMPLETION: static
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
|
||||
// CHECK-CC1-NEXT: COMPLETION: struct
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : switch(<#condition#>){
|
||||
// CHECK-CC1: COMPLETION: t : t
|
||||
// CHECK-CC1-NEXT: COMPLETION: thread_local
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#void#]throw <#expression#>
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#bool#]true
|
||||
// CHECK-CC1-NEXT: COMPLETION: Pattern : try{<#statements#>
|
||||
|
@ -72,6 +74,7 @@ void foo() {
|
|||
// CHECK-CC2-NEXT: COMPLETION: char32
|
||||
// CHECK-CC2-NEXT: COMPLETION: class
|
||||
// CHECK-CC2-NEXT: COMPLETION: const
|
||||
// CHECK-CC2-NEXT: COMPLETION: constexpr
|
||||
// CHECK-CC2-NEXT: COMPLETION: Pattern : decltype(<#expression#>)
|
||||
// CHECK-CC2-NEXT: COMPLETION: double
|
||||
// CHECK-CC2-NEXT: COMPLETION: enum
|
||||
|
@ -86,10 +89,12 @@ void foo() {
|
|||
// CHECK-CC2-NEXT: COMPLETION: short
|
||||
// CHECK-CC2-NEXT: COMPLETION: signed
|
||||
// CHECK-CC2-NEXT: COMPLETION: static
|
||||
// CHECK-CC2-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
|
||||
// CHECK-CC2-NEXT: COMPLETION: struct
|
||||
// CHECK-CC2-NEXT: COMPLETION: t : t
|
||||
// CHECK-CC2-NEXT: COMPLETION: Pattern : template <#declaration#>
|
||||
// CHECK-CC2-NEXT: COMPLETION: Pattern : template<<#parameters#>>
|
||||
// CHECK-CC2-NEXT: COMPLETION: thread_local
|
||||
// CHECK-CC2-NEXT: COMPLETION: TYPEDEF : TYPEDEF
|
||||
// CHECK-CC2-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
|
||||
// CHECK-CC2-NEXT: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
|
||||
|
@ -111,6 +116,7 @@ void foo() {
|
|||
// CHECK-CC3-NEXT: COMPLETION: char32_t
|
||||
// CHECK-CC3-NEXT: COMPLETION: class
|
||||
// CHECK-CC3-NEXT: COMPLETION: const
|
||||
// CHECK-CC3-NEXT: COMPLETION: constexpr
|
||||
// CHECK-CC3-NEXT: COMPLETION: Pattern : decltype(<#expression#>)
|
||||
// CHECK-CC3-NEXT: COMPLETION: double
|
||||
// CHECK-CC3-NEXT: COMPLETION: enum
|
||||
|
@ -129,8 +135,10 @@ void foo() {
|
|||
// CHECK-CC3-NEXT: COMPLETION: short
|
||||
// CHECK-CC3-NEXT: COMPLETION: signed
|
||||
// CHECK-CC3-NEXT: COMPLETION: static
|
||||
// CHECK-CC3-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
|
||||
// CHECK-CC3-NEXT: COMPLETION: struct
|
||||
// CHECK-CC3-NEXT: COMPLETION: Pattern : template<<#parameters#>>
|
||||
// CHECK-CC3-NEXT: COMPLETION: thread_local
|
||||
// CHECK-CC3-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
|
||||
// CHECK-CC3-NEXT: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
|
||||
// CHECK-CC3-NEXT: COMPLETION: Pattern : typeof <#expression#>
|
||||
|
@ -227,6 +235,7 @@ void foo() {
|
|||
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
|
||||
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#size_t#]sizeof...(<#parameter-pack#>)
|
||||
// CHECK-NO-RTTI-NEXT: COMPLETION: static
|
||||
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
|
||||
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
|
||||
// CHECK-NO-RTTI-NEXT: COMPLETION: struct
|
||||
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : switch(<#condition#>){
|
||||
|
|
Loading…
Reference in New Issue