Skip to content

Commit ec4c47d

Browse files
authored
Add code completion for C++20 keywords. (#107982)
This commit adds code completion for C++20 keywords, fix #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`
1 parent 4866447 commit ec4c47d

File tree

4 files changed

+196
-0
lines changed

4 files changed

+196
-0
lines changed

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Hover
7373
Code completion
7474
^^^^^^^^^^^^^^^
7575

76+
- Added completion for C++20 keywords.
77+
7678
Code actions
7779
^^^^^^^^^^^^
7880

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,15 @@ Decl *Parser::ParseExportDeclaration() {
460460
assert(Tok.is(tok::kw_export));
461461
SourceLocation ExportLoc = ConsumeToken();
462462

463+
if (Tok.is(tok::code_completion)) {
464+
cutOffParsing();
465+
Actions.CodeCompletion().CodeCompleteOrdinaryName(
466+
getCurScope(), PP.isIncrementalProcessingEnabled()
467+
? SemaCodeCompletion::PCC_TopLevelOrExpression
468+
: SemaCodeCompletion::PCC_Namespace);
469+
return nullptr;
470+
}
471+
463472
ParseScope ExportScope(this, Scope::DeclScope);
464473
Decl *ExportDecl = Actions.ActOnStartExportDecl(
465474
getCurScope(), ExportLoc,

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,6 +1836,9 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
18361836
Builder.AddChunk(CodeCompletionString::CK_RightParen);
18371837
Results.AddResult(Result(Builder.TakeString()));
18381838
}
1839+
1840+
if (LangOpts.Char8 || LangOpts.CPlusPlus20)
1841+
Results.AddResult(Result("char8_t", CCP_Type));
18391842
} else
18401843
Results.AddResult(Result("__auto_type", CCP_Type));
18411844

@@ -1888,6 +1891,9 @@ AddStorageSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
18881891
Results.AddResult(Result("constexpr"));
18891892
Results.AddResult(Result("thread_local"));
18901893
}
1894+
1895+
if (LangOpts.CPlusPlus20)
1896+
Results.AddResult(Result("constinit"));
18911897
}
18921898

18931899
static void
@@ -1911,6 +1917,9 @@ AddFunctionSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
19111917
case SemaCodeCompletion::PCC_Template:
19121918
if (LangOpts.CPlusPlus || LangOpts.C99)
19131919
Results.AddResult(Result("inline"));
1920+
1921+
if (LangOpts.CPlusPlus20)
1922+
Results.AddResult(Result("consteval"));
19141923
break;
19151924

19161925
case SemaCodeCompletion::PCC_ObjCInstanceVariableList:
@@ -2186,6 +2195,69 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
21862195
} else {
21872196
Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));
21882197
}
2198+
2199+
if (SemaRef.getLangOpts().CPlusPlus20 &&
2200+
SemaRef.getLangOpts().CPlusPlusModules) {
2201+
clang::Module *CurrentModule = SemaRef.getCurrentModule();
2202+
if (SemaRef.CurContext->isTranslationUnit()) {
2203+
/// Global module fragment can only be declared in the beginning of
2204+
/// the file. CurrentModule should be null in this case.
2205+
if (!CurrentModule) {
2206+
// module;
2207+
Builder.AddTypedTextChunk("module");
2208+
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
2209+
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
2210+
Results.AddResult(Result(Builder.TakeString()));
2211+
}
2212+
2213+
/// Named module should be declared in the beginning of the file,
2214+
/// or after the global module fragment.
2215+
if (!CurrentModule ||
2216+
CurrentModule->Kind == Module::ExplicitGlobalModuleFragment ||
2217+
CurrentModule->Kind == Module::ImplicitGlobalModuleFragment) {
2218+
// export module;
2219+
// module name;
2220+
Builder.AddTypedTextChunk("module");
2221+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2222+
Builder.AddPlaceholderChunk("name");
2223+
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
2224+
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
2225+
Results.AddResult(Result(Builder.TakeString()));
2226+
}
2227+
2228+
/// Import can occur in non module file or after the named module
2229+
/// declaration.
2230+
if (!CurrentModule ||
2231+
CurrentModule->Kind == Module::ModuleInterfaceUnit ||
2232+
CurrentModule->Kind == Module::ModulePartitionInterface) {
2233+
// import name;
2234+
Builder.AddTypedTextChunk("import");
2235+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2236+
Builder.AddPlaceholderChunk("name");
2237+
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
2238+
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
2239+
Results.AddResult(Result(Builder.TakeString()));
2240+
}
2241+
2242+
if (CurrentModule &&
2243+
(CurrentModule->Kind == Module::ModuleInterfaceUnit ||
2244+
CurrentModule->Kind == Module::ModulePartitionInterface)) {
2245+
// module: private;
2246+
Builder.AddTypedTextChunk("module");
2247+
Builder.AddChunk(CodeCompletionString::CK_Colon);
2248+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2249+
Builder.AddTypedTextChunk("private");
2250+
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
2251+
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
2252+
Results.AddResult(Result(Builder.TakeString()));
2253+
}
2254+
}
2255+
2256+
// export
2257+
if (!CurrentModule ||
2258+
CurrentModule->Kind != Module::ModuleKind::PrivateModuleFragment)
2259+
Results.AddResult(Result("export", CodeCompletionResult::RK_Keyword));
2260+
}
21892261
}
21902262

21912263
if (SemaRef.getLangOpts().ObjC)
@@ -2253,6 +2325,11 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
22532325
[[fallthrough]];
22542326

22552327
case SemaCodeCompletion::PCC_Template:
2328+
if (SemaRef.getLangOpts().CPlusPlus20 &&
2329+
CCC == SemaCodeCompletion::PCC_Template)
2330+
Results.AddResult(Result("concept", CCP_Keyword));
2331+
[[fallthrough]];
2332+
22562333
case SemaCodeCompletion::PCC_MemberTemplate:
22572334
if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns()) {
22582335
// template < parameters >
@@ -2265,6 +2342,11 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
22652342
Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));
22662343
}
22672344

2345+
if (SemaRef.getLangOpts().CPlusPlus20 &&
2346+
(CCC == SemaCodeCompletion::PCC_Template ||
2347+
CCC == SemaCodeCompletion::PCC_MemberTemplate))
2348+
Results.AddResult(Result("requires", CCP_Keyword));
2349+
22682350
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
22692351
AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);
22702352
break;
@@ -2486,6 +2568,14 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
24862568
Builder.AddPlaceholderChunk("expression");
24872569
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
24882570
Results.AddResult(Result(Builder.TakeString()));
2571+
// "co_return expression ;" for coroutines(C++20).
2572+
if (SemaRef.getLangOpts().CPlusPlus20) {
2573+
Builder.AddTypedTextChunk("co_return");
2574+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2575+
Builder.AddPlaceholderChunk("expression");
2576+
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
2577+
Results.AddResult(Result(Builder.TakeString()));
2578+
}
24892579
// When boolean, also add 'return true;' and 'return false;'.
24902580
if (ReturnType->isBooleanType()) {
24912581
Builder.AddTypedTextChunk("return true");
@@ -2706,6 +2796,44 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
27062796
Builder.AddChunk(CodeCompletionString::CK_RightParen);
27072797
Results.AddResult(Result(Builder.TakeString()));
27082798
}
2799+
2800+
if (SemaRef.getLangOpts().CPlusPlus20) {
2801+
// co_await expression
2802+
Builder.AddTypedTextChunk("co_await");
2803+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2804+
Builder.AddPlaceholderChunk("expression");
2805+
Results.AddResult(Result(Builder.TakeString()));
2806+
2807+
// co_yield expression
2808+
Builder.AddTypedTextChunk("co_yield");
2809+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2810+
Builder.AddPlaceholderChunk("expression");
2811+
Results.AddResult(Result(Builder.TakeString()));
2812+
2813+
// requires (parameters) { requirements }
2814+
Builder.AddResultTypeChunk("bool");
2815+
Builder.AddTypedTextChunk("requires");
2816+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2817+
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
2818+
Builder.AddPlaceholderChunk("parameters");
2819+
Builder.AddChunk(CodeCompletionString::CK_RightParen);
2820+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2821+
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
2822+
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
2823+
Builder.AddPlaceholderChunk("requirements");
2824+
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
2825+
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
2826+
Results.AddResult(Result(Builder.TakeString()));
2827+
2828+
if (SemaRef.CurContext->isRequiresExprBody()) {
2829+
// requires expression ;
2830+
Builder.AddTypedTextChunk("requires");
2831+
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
2832+
Builder.AddPlaceholderChunk("expression");
2833+
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
2834+
Results.AddResult(Result(Builder.TakeString()));
2835+
}
2836+
}
27092837
}
27102838

27112839
if (SemaRef.getLangOpts().ObjC) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
module;
2+
3+
export module M;
4+
5+
export const char8_t x = 1;
6+
7+
template<typename T> requires true
8+
const int y = requires { typename T::type; requires T::value; };
9+
10+
class co_test {};
11+
12+
int f(){ co_test test; return 1; }
13+
14+
module: private;
15+
16+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:1:3 %s | FileCheck --check-prefix=CHECK-MODULE1 %s
17+
// CHECK-MODULE1: module;
18+
// CHECK-MODULE1: module <#name#>;
19+
20+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:3:11 %s | FileCheck --check-prefix=CHECK-MODULE2 %s
21+
// CHECK-MODULE2: module <#name#>;
22+
23+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:14:3 %s | FileCheck --check-prefix=CHECK-MODULE3 %s
24+
// CHECK-MODULE3: module: private;
25+
26+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:3:3 %s | FileCheck --check-prefix=CHECK-EXPORT %s
27+
// CHECK-EXPORT: export
28+
29+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:5:11 %s | FileCheck --check-prefix=CHECK-CONST %s
30+
// CHECK-CONST: const
31+
// CHECK-CONST: consteval
32+
// CHECK-CONST: constexpr
33+
// CHECK-CONST: constinit
34+
35+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:5:19 %s | FileCheck --check-prefix=CHECK-CHAR %s
36+
// CHECK-CHAR: char8_t
37+
38+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:8:3 %s | FileCheck --check-prefix=CHECK-CONSTRAINT %s
39+
// CHECK-CONSTRAINT: concept
40+
// CHECK-CONSTRAINT: const
41+
// CHECK-CONSTRAINT: consteval
42+
// CHECK-CONSTRAINT: constexpr
43+
// CHECK-CONSTRAINT: constinit
44+
45+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:7:27 %s | FileCheck --check-prefix=CHECK-REQUIRES2 %s
46+
// CHECK-REQUIRES2: requires
47+
48+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:8:20 %s | FileCheck -check-prefix=CHECK-REQUIRE %s
49+
// CHECK-REQUIRE: [#bool#]requires (<#parameters#>) {
50+
// CHECK-REQUIRE: <#requirements#>
51+
// CHECK-REQUIRE: }
52+
53+
// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:12:13 %s | FileCheck --check-prefix=CHECK-COROUTINE %s
54+
// CHECK-COROUTINE: co_await <#expression#>
55+
// CHECK-COROUTINE: co_return <#expression#>;
56+
// CHECK-COROUTINE: co_yield <#expression#>
57+

0 commit comments

Comments
 (0)