mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-19 03:46:43 +00:00
Add code completion for C++20 keywords. (#107982)
This commit adds code completion for C++20 keywords, fix https://github.com/llvm/llvm-project/issues/107868. 1. complete `concept` in template context - [x] `template<typename T> conce^` -> `concept` - [ ] `conce^` 2. complete `requires` - [x] constraints in template context: `template<typename T> requi^` -> `requires` - [x] requires expression: `int x = requ^` -> `requires (parameters) { requirements }` - [x] nested requirement: `requires { requ^ }` -> `requires expression ;` 3. complete coroutine keywords - [x] `co_await^` in expression: `co_aw^` -> `co_await expression;` - [x] `co_yield` in function body: `co_yi^` -> `co_yield expression;` - [x] `co_return` in function body: `co_re^` -> `co_return expression;` 4. specifiers: `char8_t`, `consteval`, `constinit`
This commit is contained in:
parent
4866447230
commit
ec4c47d949
@ -73,6 +73,8 @@ Hover
|
||||
Code completion
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
- Added completion for C++20 keywords.
|
||||
|
||||
Code actions
|
||||
^^^^^^^^^^^^
|
||||
|
||||
|
@ -460,6 +460,15 @@ Decl *Parser::ParseExportDeclaration() {
|
||||
assert(Tok.is(tok::kw_export));
|
||||
SourceLocation ExportLoc = ConsumeToken();
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
Actions.CodeCompletion().CodeCompleteOrdinaryName(
|
||||
getCurScope(), PP.isIncrementalProcessingEnabled()
|
||||
? SemaCodeCompletion::PCC_TopLevelOrExpression
|
||||
: SemaCodeCompletion::PCC_Namespace);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ParseScope ExportScope(this, Scope::DeclScope);
|
||||
Decl *ExportDecl = Actions.ActOnStartExportDecl(
|
||||
getCurScope(), ExportLoc,
|
||||
|
@ -1836,6 +1836,9 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
|
||||
Builder.AddChunk(CodeCompletionString::CK_RightParen);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
|
||||
if (LangOpts.Char8 || LangOpts.CPlusPlus20)
|
||||
Results.AddResult(Result("char8_t", CCP_Type));
|
||||
} else
|
||||
Results.AddResult(Result("__auto_type", CCP_Type));
|
||||
|
||||
@ -1888,6 +1891,9 @@ AddStorageSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
Results.AddResult(Result("constexpr"));
|
||||
Results.AddResult(Result("thread_local"));
|
||||
}
|
||||
|
||||
if (LangOpts.CPlusPlus20)
|
||||
Results.AddResult(Result("constinit"));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1911,6 +1917,9 @@ AddFunctionSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
case SemaCodeCompletion::PCC_Template:
|
||||
if (LangOpts.CPlusPlus || LangOpts.C99)
|
||||
Results.AddResult(Result("inline"));
|
||||
|
||||
if (LangOpts.CPlusPlus20)
|
||||
Results.AddResult(Result("consteval"));
|
||||
break;
|
||||
|
||||
case SemaCodeCompletion::PCC_ObjCInstanceVariableList:
|
||||
@ -2186,6 +2195,69 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
} else {
|
||||
Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));
|
||||
}
|
||||
|
||||
if (SemaRef.getLangOpts().CPlusPlus20 &&
|
||||
SemaRef.getLangOpts().CPlusPlusModules) {
|
||||
clang::Module *CurrentModule = SemaRef.getCurrentModule();
|
||||
if (SemaRef.CurContext->isTranslationUnit()) {
|
||||
/// Global module fragment can only be declared in the beginning of
|
||||
/// the file. CurrentModule should be null in this case.
|
||||
if (!CurrentModule) {
|
||||
// module;
|
||||
Builder.AddTypedTextChunk("module");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
|
||||
/// Named module should be declared in the beginning of the file,
|
||||
/// or after the global module fragment.
|
||||
if (!CurrentModule ||
|
||||
CurrentModule->Kind == Module::ExplicitGlobalModuleFragment ||
|
||||
CurrentModule->Kind == Module::ImplicitGlobalModuleFragment) {
|
||||
// export module;
|
||||
// module name;
|
||||
Builder.AddTypedTextChunk("module");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("name");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
|
||||
/// Import can occur in non module file or after the named module
|
||||
/// declaration.
|
||||
if (!CurrentModule ||
|
||||
CurrentModule->Kind == Module::ModuleInterfaceUnit ||
|
||||
CurrentModule->Kind == Module::ModulePartitionInterface) {
|
||||
// import name;
|
||||
Builder.AddTypedTextChunk("import");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("name");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
|
||||
if (CurrentModule &&
|
||||
(CurrentModule->Kind == Module::ModuleInterfaceUnit ||
|
||||
CurrentModule->Kind == Module::ModulePartitionInterface)) {
|
||||
// module: private;
|
||||
Builder.AddTypedTextChunk("module");
|
||||
Builder.AddChunk(CodeCompletionString::CK_Colon);
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddTypedTextChunk("private");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
}
|
||||
|
||||
// export
|
||||
if (!CurrentModule ||
|
||||
CurrentModule->Kind != Module::ModuleKind::PrivateModuleFragment)
|
||||
Results.AddResult(Result("export", CodeCompletionResult::RK_Keyword));
|
||||
}
|
||||
}
|
||||
|
||||
if (SemaRef.getLangOpts().ObjC)
|
||||
@ -2253,6 +2325,11 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
[[fallthrough]];
|
||||
|
||||
case SemaCodeCompletion::PCC_Template:
|
||||
if (SemaRef.getLangOpts().CPlusPlus20 &&
|
||||
CCC == SemaCodeCompletion::PCC_Template)
|
||||
Results.AddResult(Result("concept", CCP_Keyword));
|
||||
[[fallthrough]];
|
||||
|
||||
case SemaCodeCompletion::PCC_MemberTemplate:
|
||||
if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns()) {
|
||||
// template < parameters >
|
||||
@ -2265,6 +2342,11 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));
|
||||
}
|
||||
|
||||
if (SemaRef.getLangOpts().CPlusPlus20 &&
|
||||
(CCC == SemaCodeCompletion::PCC_Template ||
|
||||
CCC == SemaCodeCompletion::PCC_MemberTemplate))
|
||||
Results.AddResult(Result("requires", CCP_Keyword));
|
||||
|
||||
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
|
||||
AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);
|
||||
break;
|
||||
@ -2486,6 +2568,14 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
// "co_return expression ;" for coroutines(C++20).
|
||||
if (SemaRef.getLangOpts().CPlusPlus20) {
|
||||
Builder.AddTypedTextChunk("co_return");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
// When boolean, also add 'return true;' and 'return false;'.
|
||||
if (ReturnType->isBooleanType()) {
|
||||
Builder.AddTypedTextChunk("return true");
|
||||
@ -2706,6 +2796,44 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
|
||||
Builder.AddChunk(CodeCompletionString::CK_RightParen);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
|
||||
if (SemaRef.getLangOpts().CPlusPlus20) {
|
||||
// co_await expression
|
||||
Builder.AddTypedTextChunk("co_await");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
|
||||
// co_yield expression
|
||||
Builder.AddTypedTextChunk("co_yield");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
|
||||
// requires (parameters) { requirements }
|
||||
Builder.AddResultTypeChunk("bool");
|
||||
Builder.AddTypedTextChunk("requires");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
|
||||
Builder.AddPlaceholderChunk("parameters");
|
||||
Builder.AddChunk(CodeCompletionString::CK_RightParen);
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
|
||||
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
|
||||
Builder.AddPlaceholderChunk("requirements");
|
||||
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
|
||||
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
|
||||
if (SemaRef.CurContext->isRequiresExprBody()) {
|
||||
// requires expression ;
|
||||
Builder.AddTypedTextChunk("requires");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("expression");
|
||||
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
|
||||
Results.AddResult(Result(Builder.TakeString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SemaRef.getLangOpts().ObjC) {
|
||||
|
57
clang/test/CodeCompletion/keywords-cxx20.cpp
Normal file
57
clang/test/CodeCompletion/keywords-cxx20.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
module;
|
||||
|
||||
export module M;
|
||||
|
||||
export const char8_t x = 1;
|
||||
|
||||
template<typename T> requires true
|
||||
const int y = requires { typename T::type; requires T::value; };
|
||||
|
||||
class co_test {};
|
||||
|
||||
int f(){ co_test test; return 1; }
|
||||
|
||||
module: private;
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:1:3 %s | FileCheck --check-prefix=CHECK-MODULE1 %s
|
||||
// CHECK-MODULE1: module;
|
||||
// CHECK-MODULE1: module <#name#>;
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:3:11 %s | FileCheck --check-prefix=CHECK-MODULE2 %s
|
||||
// CHECK-MODULE2: module <#name#>;
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:14:3 %s | FileCheck --check-prefix=CHECK-MODULE3 %s
|
||||
// CHECK-MODULE3: module: private;
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:3:3 %s | FileCheck --check-prefix=CHECK-EXPORT %s
|
||||
// CHECK-EXPORT: export
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:5:11 %s | FileCheck --check-prefix=CHECK-CONST %s
|
||||
// CHECK-CONST: const
|
||||
// CHECK-CONST: consteval
|
||||
// CHECK-CONST: constexpr
|
||||
// CHECK-CONST: constinit
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:5:19 %s | FileCheck --check-prefix=CHECK-CHAR %s
|
||||
// CHECK-CHAR: char8_t
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:8:3 %s | FileCheck --check-prefix=CHECK-CONSTRAINT %s
|
||||
// CHECK-CONSTRAINT: concept
|
||||
// CHECK-CONSTRAINT: const
|
||||
// CHECK-CONSTRAINT: consteval
|
||||
// CHECK-CONSTRAINT: constexpr
|
||||
// CHECK-CONSTRAINT: constinit
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:7:27 %s | FileCheck --check-prefix=CHECK-REQUIRES2 %s
|
||||
// CHECK-REQUIRES2: requires
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:8:20 %s | FileCheck -check-prefix=CHECK-REQUIRE %s
|
||||
// CHECK-REQUIRE: [#bool#]requires (<#parameters#>) {
|
||||
// CHECK-REQUIRE: <#requirements#>
|
||||
// CHECK-REQUIRE: }
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:12:13 %s | FileCheck --check-prefix=CHECK-COROUTINE %s
|
||||
// CHECK-COROUTINE: co_await <#expression#>
|
||||
// CHECK-COROUTINE: co_return <#expression#>;
|
||||
// CHECK-COROUTINE: co_yield <#expression#>
|
||||
|
Loading…
x
Reference in New Issue
Block a user