[clang] [clang-tools-extra] [llvm] Add code completion for C++20 keywords. (PR #107982)

via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 12 03:35:55 PDT 2024


https://github.com/16bit-ykiko updated https://github.com/llvm/llvm-project/pull/107982

>From fedea9e4fd57b618fe341e0c30982bff0f098c52 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Tue, 10 Sep 2024 14:59:10 +0800
Subject: [PATCH 01/16] add co_return, co_await, co_yield, consteval,
 constinit, concept, requires, char8_t.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 61 +++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 88d4732c7d5c6a..d8f6b1dada942a 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1837,6 +1837,11 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
       Builder.AddChunk(CodeCompletionString::CK_RightParen);
       Results.AddResult(Result(Builder.TakeString()));
     }
+
+    if(LangOpts.CPlusPlus20){
+      Results.AddResult(Result("char8_t", CCP_Type));
+      Results.AddResult(Result("concept", CCP_Keyword));
+    }
   } else
     Results.AddResult(Result("__auto_type", CCP_Type));
 
@@ -1889,6 +1894,10 @@ AddStorageSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
     Results.AddResult(Result("constexpr"));
     Results.AddResult(Result("thread_local"));
   }
+
+  if (LangOpts.CPlusPlus20) {
+    Results.AddResult(Result("constinit"));
+  }
 }
 
 static void
@@ -1912,6 +1921,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:
@@ -2487,6 +2499,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");
@@ -2707,6 +2727,47 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
         Builder.AddChunk(CodeCompletionString::CK_RightParen);
         Results.AddResult(Result(Builder.TakeString()));
       }
+
+      if (SemaRef.getLangOpts().CPlusPlus20) {
+        // co_await expression
+        Builder.AddResultTypeChunk("");
+        Builder.AddTypedTextChunk("co_await");
+        Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+        Builder.AddPlaceholderChunk("expression");
+        Results.AddResult(Result(Builder.TakeString()));
+
+        // co_yield expression
+        Builder.AddResultTypeChunk("");
+        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(llvm::isa<clang::RequiresExprBodyDecl>(SemaRef.CurContext)){
+          // requires expression ;
+          Builder.AddResultTypeChunk("");
+          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) {

>From 36a0db2b827baaabe17c5cd7b576802be586c69c Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Tue, 10 Sep 2024 15:50:04 +0800
Subject: [PATCH 02/16] make concept and requires more sensitive to context.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index d8f6b1dada942a..4647d65430b8c3 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1840,7 +1840,6 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
 
     if(LangOpts.CPlusPlus20){
       Results.AddResult(Result("char8_t", CCP_Type));
-      Results.AddResult(Result("concept", CCP_Keyword));
     }
   } else
     Results.AddResult(Result("__auto_type", CCP_Type));
@@ -2266,6 +2265,10 @@ 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 >
@@ -2278,6 +2281,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;

>From 326892aa58340be0de3085a6d2bf3cc886a4b0f2 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Tue, 10 Sep 2024 16:50:34 +0800
Subject: [PATCH 03/16] format.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 4647d65430b8c3..1c815d170cdfb0 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1838,7 +1838,7 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
       Results.AddResult(Result(Builder.TakeString()));
     }
 
-    if(LangOpts.CPlusPlus20){
+    if (LangOpts.CPlusPlus20) {
       Results.AddResult(Result("char8_t", CCP_Type));
     }
   } else
@@ -2265,8 +2265,9 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
     [[fallthrough]];
 
   case SemaCodeCompletion::PCC_Template:
-    if (SemaRef.getLangOpts().CPlusPlus20 && CCC == SemaCodeCompletion::PCC_Template)
-        Results.AddResult(Result("concept", CCP_Keyword));
+    if (SemaRef.getLangOpts().CPlusPlus20 && 
+        CCC == SemaCodeCompletion::PCC_Template)
+      Results.AddResult(Result("concept", CCP_Keyword));
     [[fallthrough]];
 
   case SemaCodeCompletion::PCC_MemberTemplate:
@@ -2282,7 +2283,8 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
     }
 
     if(SemaRef.getLangOpts().CPlusPlus20 && 
-      (CCC == SemaCodeCompletion::PCC_Template || CCC == SemaCodeCompletion::PCC_MemberTemplate)) {
+      (CCC == SemaCodeCompletion::PCC_Template || 
+       CCC == SemaCodeCompletion::PCC_MemberTemplate)) {
       Results.AddResult(Result("requires", CCP_Keyword));
     }
 
@@ -2738,14 +2740,12 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
 
       if (SemaRef.getLangOpts().CPlusPlus20) {
         // co_await expression
-        Builder.AddResultTypeChunk("");
         Builder.AddTypedTextChunk("co_await");
         Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
         Builder.AddPlaceholderChunk("expression");
         Results.AddResult(Result(Builder.TakeString()));
 
         // co_yield expression
-        Builder.AddResultTypeChunk("");
         Builder.AddTypedTextChunk("co_yield");
         Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
         Builder.AddPlaceholderChunk("expression");
@@ -2766,9 +2766,8 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
         Builder.AddChunk(CodeCompletionString::CK_RightBrace);
         Results.AddResult(Result(Builder.TakeString()));
 
-        if(llvm::isa<clang::RequiresExprBodyDecl>(SemaRef.CurContext)){
+        if (llvm::isa<clang::RequiresExprBodyDecl>(SemaRef.CurContext)) {
           // requires expression ;
-          Builder.AddResultTypeChunk("");
           Builder.AddTypedTextChunk("requires");
           Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
           Builder.AddPlaceholderChunk("expression");

>From c8e555f7454a913346fa90dec213e2a26f70a1ba Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Tue, 10 Sep 2024 17:13:56 +0800
Subject: [PATCH 04/16] format and add test.

---
 clang/lib/Sema/SemaCodeComplete.cpp          |  8 ++---
 clang/test/CodeCompletion/keywords-cxx20.cpp | 35 ++++++++++++++++++++
 2 files changed, 39 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/CodeCompletion/keywords-cxx20.cpp

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 1c815d170cdfb0..710287e8ce5e5c 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -2265,7 +2265,7 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
     [[fallthrough]];
 
   case SemaCodeCompletion::PCC_Template:
-    if (SemaRef.getLangOpts().CPlusPlus20 && 
+    if (SemaRef.getLangOpts().CPlusPlus20 &&
         CCC == SemaCodeCompletion::PCC_Template)
       Results.AddResult(Result("concept", CCP_Keyword));
     [[fallthrough]];
@@ -2282,9 +2282,9 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
       Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));
     }
 
-    if(SemaRef.getLangOpts().CPlusPlus20 && 
-      (CCC == SemaCodeCompletion::PCC_Template || 
-       CCC == SemaCodeCompletion::PCC_MemberTemplate)) {
+    if (SemaRef.getLangOpts().CPlusPlus20 &&
+        (CCC == SemaCodeCompletion::PCC_Template ||
+         CCC == SemaCodeCompletion::PCC_MemberTemplate)) {
       Results.AddResult(Result("requires", CCP_Keyword));
     }
 
diff --git a/clang/test/CodeCompletion/keywords-cxx20.cpp b/clang/test/CodeCompletion/keywords-cxx20.cpp
new file mode 100644
index 00000000000000..6cc236388437cc
--- /dev/null
+++ b/clang/test/CodeCompletion/keywords-cxx20.cpp
@@ -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#>
\ No newline at end of file

>From 0375e5281c0748fd4903f091568909ef49aafc08 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Tue, 10 Sep 2024 17:22:28 +0800
Subject: [PATCH 05/16] fix.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 710287e8ce5e5c..9194e91a370b31 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -2766,7 +2766,7 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
         Builder.AddChunk(CodeCompletionString::CK_RightBrace);
         Results.AddResult(Result(Builder.TakeString()));
 
-        if (llvm::isa<clang::RequiresExprBodyDecl>(SemaRef.CurContext)) {
+        if (SemaRef.CurContext->isRequiresExprBody()) {
           // requires expression ;
           Builder.AddTypedTextChunk("requires");
           Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);

>From d9c641342db0b714604281681309233ee321f877 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Tue, 10 Sep 2024 18:19:26 +0800
Subject: [PATCH 06/16] add newline in eof.

---
 clang/test/CodeCompletion/keywords-cxx20.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CodeCompletion/keywords-cxx20.cpp b/clang/test/CodeCompletion/keywords-cxx20.cpp
index 6cc236388437cc..c968e289a5d943 100644
--- a/clang/test/CodeCompletion/keywords-cxx20.cpp
+++ b/clang/test/CodeCompletion/keywords-cxx20.cpp
@@ -32,4 +32,4 @@ int f(){ co_await 1; }
 // 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#>
\ No newline at end of file
+// CHECK-COAWAIT: Pattern : co_yield <#expression#>

>From 37647823895b29914a27ba93321b3fbd4200cb11 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Mon, 23 Sep 2024 22:53:18 +0800
Subject: [PATCH 07/16] add module keyword and Char8.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 41 ++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 9194e91a370b31..0b558b79218800 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1838,7 +1838,7 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
       Results.AddResult(Result(Builder.TakeString()));
     }
 
-    if (LangOpts.CPlusPlus20) {
+    if (LangOpts.Char8 || LangOpts.CPlusPlus20) {
       Results.AddResult(Result("char8_t", CCP_Type));
     }
   } else
@@ -2198,6 +2198,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()) {
+          // 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)

>From 2d7f4761605c620e1e841a395f836392212f7ddf Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Thu, 10 Oct 2024 22:26:58 +0800
Subject: [PATCH 08/16] Update ReleaseNote.

---
 clang-tools-extra/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3f7bcde1eb3014..f1243cf731d85e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -71,6 +71,8 @@ Hover
 Code completion
 ^^^^^^^^^^^^^^^
 
+- Added completion for C++20 keywords.
+
 Code actions
 ^^^^^^^^^^^^
 

>From d48932797aecc43f8f5578094bd3a020e223ff68 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Fri, 11 Oct 2024 14:24:27 +0800
Subject: [PATCH 09/16] Remove extra braces.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index bc1fdfd0fdaaf9..7e7649ab2991e8 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1837,9 +1837,8 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
       Results.AddResult(Result(Builder.TakeString()));
     }
 
-    if (LangOpts.Char8 || LangOpts.CPlusPlus20) {
+    if (LangOpts.Char8 || LangOpts.CPlusPlus20)
       Results.AddResult(Result("char8_t", CCP_Type));
-    }
   } else
     Results.AddResult(Result("__auto_type", CCP_Type));
 
@@ -1893,9 +1892,8 @@ AddStorageSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,
     Results.AddResult(Result("thread_local"));
   }
 
-  if (LangOpts.CPlusPlus20) {
+  if (LangOpts.CPlusPlus20)
     Results.AddResult(Result("constinit"));
-  }
 }
 
 static void

>From 5cc6a8f5a36d3e797375d7b227cfeed68093a3c0 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Fri, 11 Oct 2024 15:03:13 +0800
Subject: [PATCH 10/16] Update test file.

---
 clang/test/CodeCompletion/keywords-cxx20.cpp | 61 ++++++++++++--------
 1 file changed, 38 insertions(+), 23 deletions(-)

diff --git a/clang/test/CodeCompletion/keywords-cxx20.cpp b/clang/test/CodeCompletion/keywords-cxx20.cpp
index c968e289a5d943..1f98128c65c5e0 100644
--- a/clang/test/CodeCompletion/keywords-cxx20.cpp
+++ b/clang/test/CodeCompletion/keywords-cxx20.cpp
@@ -1,35 +1,50 @@
+module;
+
+export module M;
+
 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; }
+class co_test {};
+
+int f(){ co_test test; return 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:3 %s | FileCheck --check-prefix=CHECK-MODULE %s
+// CHECK-MODULE: module;
+// CHECK-MODULE: module: private;
+// CHECK-MODULE: module <#name#>;
 
-// 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:3:3 %s | FileCheck --check-prefix=CHECK-EXPORT %s
+// CHECK-EXPORT: export
 
-// 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:5:3 %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:3:27 %s | FileCheck --check-prefix=CHECK-REQUIRES %s
+// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:5:12 %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-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: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#>
 
-// 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#>

>From 74b7c749705a62380a58746ead5f7a4cbff74fae Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Fri, 11 Oct 2024 15:51:44 +0800
Subject: [PATCH 11/16] Fix test.

---
 clang/test/CodeCompletion/keywords-cxx20.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeCompletion/keywords-cxx20.cpp b/clang/test/CodeCompletion/keywords-cxx20.cpp
index 1f98128c65c5e0..567949204970e0 100644
--- a/clang/test/CodeCompletion/keywords-cxx20.cpp
+++ b/clang/test/CodeCompletion/keywords-cxx20.cpp
@@ -35,8 +35,8 @@ int f(){ co_test test; return 1; }
 // CHECK-CONSTRAINT: constexpr
 // CHECK-CONSTRAINT: constinit
 
-// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:7:27 %s | FileCheck --check-prefix=CHECK-REQUIRES %s
-// CHECK-REQUIRES: requires
+// 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#>) {

>From cc758c5472967c5106fc345e97e4324385a38317 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Fri, 11 Oct 2024 17:52:08 +0800
Subject: [PATCH 12/16] Remove extra brace.

---
 clang/lib/Sema/SemaCodeComplete.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 7e7649ab2991e8..6bb388c6efacdc 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -2320,9 +2320,8 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
 
     if (SemaRef.getLangOpts().CPlusPlus20 &&
         (CCC == SemaCodeCompletion::PCC_Template ||
-         CCC == SemaCodeCompletion::PCC_MemberTemplate)) {
+         CCC == SemaCodeCompletion::PCC_MemberTemplate))
       Results.AddResult(Result("requires", CCP_Keyword));
-    }
 
     AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
     AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);

>From 15f6982f79fcace95637977ec3e86b1d8a150a98 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Fri, 11 Oct 2024 21:22:32 +0800
Subject: [PATCH 13/16] Make completion for module keyword more context
 sensitive.

---
 clang/lib/Sema/SemaCodeComplete.cpp          | 84 +++++++++++++-------
 clang/test/CodeCompletion/keywords-cxx20.cpp | 12 ++-
 2 files changed, 62 insertions(+), 34 deletions(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 6bb388c6efacdc..94883554f719f2 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -2198,41 +2198,65 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
 
       if (SemaRef.getLangOpts().CPlusPlus20 &&
           SemaRef.getLangOpts().CPlusPlusModules) {
-        // export
-        Results.AddResult(Result("export", CodeCompletionResult::RK_Keyword));
-
+        clang::Module *CurrentModule = SemaRef.getCurrentModule();
         if (SemaRef.CurContext->isTranslationUnit()) {
-          // module;
-          Builder.AddTypedTextChunk("module");
-          Builder.AddChunk(CodeCompletionString::CK_SemiColon);
-          Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
-          Results.AddResult(Result(Builder.TakeString()));
+          /// 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()));
+          }
 
-          // 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()));
+          /// 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()));
+          }
 
-          // 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()));
+          }
 
-          // 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 (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));
       }
     }
 
diff --git a/clang/test/CodeCompletion/keywords-cxx20.cpp b/clang/test/CodeCompletion/keywords-cxx20.cpp
index 567949204970e0..b8ffb6f618260f 100644
--- a/clang/test/CodeCompletion/keywords-cxx20.cpp
+++ b/clang/test/CodeCompletion/keywords-cxx20.cpp
@@ -11,10 +11,14 @@ class co_test {};
 
 int f(){ co_test test; return 1; }
 
-// RUN: %clang_cc1 -std=c++20 -code-completion-at=%s:1:3 %s | FileCheck --check-prefix=CHECK-MODULE %s
-// CHECK-MODULE: module;
-// CHECK-MODULE: module: private;
-// CHECK-MODULE: module <#name#>;
+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: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

>From b6218b6356cfaaddcc313d3b236b0f5666ec2c74 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Sat, 12 Oct 2024 18:25:01 +0800
Subject: [PATCH 14/16] Fix unexpected compiler error when code complete in
 `export mod^`.

---
 .clangd                                      |  2 ++
 clang/lib/Parse/ParseDeclCXX.cpp             | 12 ++++++++++++
 clang/test/CodeCompletion/keywords-cxx20.cpp |  9 ++++++---
 3 files changed, 20 insertions(+), 3 deletions(-)
 create mode 100644 .clangd

diff --git a/.clangd b/.clangd
new file mode 100644
index 00000000000000..7058e79de5e5ac
--- /dev/null
+++ b/.clangd
@@ -0,0 +1,2 @@
+CompileFlags:
+  Add: [-std=c++20]
\ No newline at end of file
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 6f0f5a0311bc18..caeadeb46c73ed 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -460,6 +460,18 @@ Decl *Parser::ParseExportDeclaration() {
   assert(Tok.is(tok::kw_export));
   SourceLocation ExportLoc = ConsumeToken();
 
+  if (Tok.is(tok::code_completion)) {
+    cutOffParsing();
+    SemaCodeCompletion::ParserCompletionContext PCC;
+    if (PP.isIncrementalProcessingEnabled()) {
+      PCC = SemaCodeCompletion::PCC_TopLevelOrExpression;
+    } else {
+      PCC = SemaCodeCompletion::PCC_Namespace;
+    };
+    Actions.CodeCompletion().CodeCompleteOrdinaryName(getCurScope(), PCC);
+    return nullptr;
+  }
+
   ParseScope ExportScope(this, Scope::DeclScope);
   Decl *ExportDecl = Actions.ActOnStartExportDecl(
       getCurScope(), ExportLoc,
diff --git a/clang/test/CodeCompletion/keywords-cxx20.cpp b/clang/test/CodeCompletion/keywords-cxx20.cpp
index b8ffb6f618260f..612c3c0045e394 100644
--- a/clang/test/CodeCompletion/keywords-cxx20.cpp
+++ b/clang/test/CodeCompletion/keywords-cxx20.cpp
@@ -2,7 +2,7 @@ module;
 
 export module M;
 
-const char8_t x = 1;
+export const char8_t x = 1;
 
 template<typename T> requires true
 const int y = requires { typename T::type; requires T::value; };
@@ -17,19 +17,22 @@ module: private;
 // 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:3 %s | FileCheck --check-prefix=CHECK-CONST %s
+// 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:12 %s | FileCheck --check-prefix=CHECK-CHAR %s
+// 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

>From 75bb471f087645f1262c1e297e400ca649118408 Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Sat, 12 Oct 2024 18:29:50 +0800
Subject: [PATCH 15/16] Remove `.clangd`.

---
 .clangd | 2 --
 1 file changed, 2 deletions(-)
 delete mode 100644 .clangd

diff --git a/.clangd b/.clangd
deleted file mode 100644
index 7058e79de5e5ac..00000000000000
--- a/.clangd
+++ /dev/null
@@ -1,2 +0,0 @@
-CompileFlags:
-  Add: [-std=c++20]
\ No newline at end of file

>From 68cd2926c6c0333dd8ee1fc9ac35ab492eedd59c Mon Sep 17 00:00:00 2001
From: ykiko <ykikoykikoykiko at gmail.com>
Date: Sat, 12 Oct 2024 18:35:34 +0800
Subject: [PATCH 16/16] Some format.

---
 clang/lib/Parse/ParseDeclCXX.cpp | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index caeadeb46c73ed..aa164a7260e0bc 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -462,13 +462,10 @@ Decl *Parser::ParseExportDeclaration() {
 
   if (Tok.is(tok::code_completion)) {
     cutOffParsing();
-    SemaCodeCompletion::ParserCompletionContext PCC;
-    if (PP.isIncrementalProcessingEnabled()) {
-      PCC = SemaCodeCompletion::PCC_TopLevelOrExpression;
-    } else {
-      PCC = SemaCodeCompletion::PCC_Namespace;
-    };
-    Actions.CodeCompletion().CodeCompleteOrdinaryName(getCurScope(), PCC);
+    Actions.CodeCompletion().CodeCompleteOrdinaryName(
+        getCurScope(), PP.isIncrementalProcessingEnabled()
+                           ? SemaCodeCompletion::PCC_TopLevelOrExpression
+                           : SemaCodeCompletion::PCC_Namespace);
     return nullptr;
   }
 



More information about the cfe-commits mailing list