Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ Hover
Code completion
^^^^^^^^^^^^^^^

- Added completion for C++20 keywords.

Code actions
^^^^^^^^^^^^

Expand Down
107 changes: 107 additions & 0 deletions clang/lib/Sema/SemaCodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1836,6 +1836,10 @@ 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));

Expand Down Expand Up @@ -1888,6 +1892,10 @@ AddStorageSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
Results.AddResult(Result("constexpr"));
Results.AddResult(Result("thread_local"));
}

if (LangOpts.CPlusPlus20) {
Results.AddResult(Result("constinit"));
}
}

static void
Expand All @@ -1911,6 +1919,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:
Expand Down Expand Up @@ -2186,6 +2197,45 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
} else {
Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));
}

if (SemaRef.getLangOpts().CPlusPlus20 &&
SemaRef.getLangOpts().CPlusPlusModules) {
// export
Results.AddResult(Result("export", CodeCompletionResult::RK_Keyword));

if (SemaRef.CurContext->isTranslationUnit()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we restrict that using getCurrentModule()->Kind @ChuanqiXu9 ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can't do it here. Since we don't the kind of the current module before we see module declarations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, exactly.
If we haven't see module;, we should propose module; and export module
If we have seen module; - we should not propose it again
If we have seem export module, we should not propose import

Copy link
Contributor Author

@16bit-ykiko 16bit-ykiko Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I push a new commit and try to make completion for module related keywords more context-sensitive.

And found something strange: https://godbolt.org/z/YM9dhEKKe

module;

export module M;
         ^

If I try to run code completion at ^, only get a compiler error.

<source>:3:1: error: export declaration can only be used within a module purview
    3 | export mo<U+0000>dule M;

The error shouldn't occur, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only happens during completion so there is probably a bug with that https://godbolt.org/z/7M8EPodoP

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made some modification to ParseExportDeclaration to fix the problem.

// module;
Builder.AddTypedTextChunk("module");
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Results.AddResult(Result(Builder.TakeString()));

// 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()));

// 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 module;
Builder.AddTypedTextChunk("import");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("module");
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Results.AddResult(Result(Builder.TakeString()));
}
}
}

if (SemaRef.getLangOpts().ObjC)
Expand Down Expand Up @@ -2253,6 +2303,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 >
Expand All @@ -2265,6 +2320,12 @@ 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;
Expand Down Expand Up @@ -2486,6 +2547,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");
Expand Down Expand Up @@ -2706,6 +2775,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) {
Expand Down
35 changes: 35 additions & 0 deletions clang/test/CodeCompletion/keywords-cxx20.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const char8_t x = 1;

template<typename T> requires true
const int y = requires { typename T::type; requires T::value; };

int f(){ co_await 1; }

// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:1:3 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
// CHECK-TOP-LEVEL: const
// CHECK-TOP-LEVEL: consteval
// CHECK-TOP-LEVEL: constexpr
// CHECK-TOP-LEVEL: constinit

// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:1:12 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
// CHECK-TOP-LEVEL: char8_t

// RUN: %clang-cc1 -std=c++20 -code-completion-at=%s:4:3 %s | FileCheck --check-prefix=CHECK-REQUIRES %s
// CHECK-REQUIRES: concept
// CHECK-REQUIRES: const
// CHECK-REQUIRES: consteval
// CHECK-REQUIRES: constexpr
// CHECK-REQUIRES: constinit

// RUN: %clang-cc1 -std=c++20 -code-completion-at=%s:3:27 %s | FileCheck --check-prefix=CHECK-REQUIRES %s
// CHECK-REQUIRES: requires

// RUN: %clang-cc1 -std=c++20 -code-completion-at=%s:4:20 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1-NEXT: COMPLETION: Pattern: [#bool#]requires (<#parameters#>) {
// CHECK-CC1-NEXT: <#requirements#>
// CHECK-CC1-NEXT: }

// RUN: %clang-cc1 -std=c++20 -code-completion-at=%s:6:13 %s | FileCheck --check-prefix=CHECK-COAWAIT %s
// CHECK-COAWAIT: Pattern : co_await <#expression#>
// CHECK-COAWAIT: Pattern : co_return <#expression#>;
// CHECK-COAWAIT: Pattern : co_yield <#expression#>