-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[Sema][clangd] add noexcept to override functions during code completion #75937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clangd Author: Sirui Mu (Lancern) ChangesIf a virtual function is declared with Full diff: https://github.com/llvm/llvm-project/pull/75937.diff 2 Files Affected:
diff --git a/clang-tools-extra/clangd/test/completion-override-except-spec.test b/clang-tools-extra/clangd/test/completion-override-except-spec.test
new file mode 100644
index 00000000000000..19c7f84bc679d8
--- /dev/null
+++ b/clang-tools-extra/clangd/test/completion-override-except-spec.test
@@ -0,0 +1,69 @@
+# RUN: clangd -lit-test < %s | FileCheck %s
+# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct Base {\n virtual void virt_method() noexcept = 0;\n};\n\nstruct Derived : Base {\n virt_\n};"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":5,"character":6}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "filterText": "virt_method() noexcept override",
+# CHECK-NEXT: "insertText": "void virt_method() noexcept override",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 2,
+# CHECK-NEXT: "label": " void virt_method() noexcept override",
+# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
+# CHECK-NEXT: "sortText": "{{.*}}virt_method() noexcept override",
+# CHECK-NEXT: "textEdit": {
+# CHECK-NEXT: "newText": "void virt_method() noexcept override",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 6,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 2,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp","version":2},"contentChanges":[{"text":"struct Base {\n virtual void virt_method() = 0;\n};\n\nstruct Derived : Base {\n virt_\n};"}]}}
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":5,"character":6}}}
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "filterText": "virt_method() override",
+# CHECK-NEXT: "insertText": "void virt_method() override",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 2,
+# CHECK-NEXT: "label": " void virt_method() override",
+# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
+# CHECK-NEXT: "sortText": "{{.*}}virt_method() override",
+# CHECK-NEXT: "textEdit": {
+# CHECK-NEXT: "newText": "void virt_method() override",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 6,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 2,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index c44be0df9b0a85..516936311a278d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/HeaderSearch.h"
@@ -3292,6 +3293,25 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));
}
+static void
+AddFunctionExceptSpecToCompletionString(CodeCompletionBuilder &Result,
+ const FunctionDecl *Function) {
+ const auto *Proto = Function->getType()->getAs<FunctionProtoType>();
+ if (!Proto)
+ return;
+
+ auto ExceptInfo = Proto->getExceptionSpecInfo();
+ switch (ExceptInfo.Type) {
+ case EST_BasicNoexcept:
+ case EST_NoexceptTrue:
+ Result.AddInformativeChunk(" noexcept");
+ break;
+
+ default:
+ break;
+ }
+}
+
/// Add the name of the given declaration
static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
const NamedDecl *ND,
@@ -3560,6 +3580,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
AddFunctionParameterChunks(PP, Policy, Function, Result);
Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
+ AddFunctionExceptSpecToCompletionString(Result, Function);
};
if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
@@ -3642,6 +3663,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
AddFunctionParameterChunks(PP, Policy, Function, Result);
Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
+ AddFunctionExceptSpecToCompletionString(Result, Function);
return Result.TakeString();
}
|
@llvm/pr-subscribers-clang Author: Sirui Mu (Lancern) ChangesIf a virtual function is declared with Full diff: https://github.com/llvm/llvm-project/pull/75937.diff 2 Files Affected:
diff --git a/clang-tools-extra/clangd/test/completion-override-except-spec.test b/clang-tools-extra/clangd/test/completion-override-except-spec.test
new file mode 100644
index 00000000000000..19c7f84bc679d8
--- /dev/null
+++ b/clang-tools-extra/clangd/test/completion-override-except-spec.test
@@ -0,0 +1,69 @@
+# RUN: clangd -lit-test < %s | FileCheck %s
+# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct Base {\n virtual void virt_method() noexcept = 0;\n};\n\nstruct Derived : Base {\n virt_\n};"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":5,"character":6}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "filterText": "virt_method() noexcept override",
+# CHECK-NEXT: "insertText": "void virt_method() noexcept override",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 2,
+# CHECK-NEXT: "label": " void virt_method() noexcept override",
+# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
+# CHECK-NEXT: "sortText": "{{.*}}virt_method() noexcept override",
+# CHECK-NEXT: "textEdit": {
+# CHECK-NEXT: "newText": "void virt_method() noexcept override",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 6,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 2,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp","version":2},"contentChanges":[{"text":"struct Base {\n virtual void virt_method() = 0;\n};\n\nstruct Derived : Base {\n virt_\n};"}]}}
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":5,"character":6}}}
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "filterText": "virt_method() override",
+# CHECK-NEXT: "insertText": "void virt_method() override",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 2,
+# CHECK-NEXT: "label": " void virt_method() override",
+# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
+# CHECK-NEXT: "sortText": "{{.*}}virt_method() override",
+# CHECK-NEXT: "textEdit": {
+# CHECK-NEXT: "newText": "void virt_method() override",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 6,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 2,
+# CHECK-NEXT: "line": 5
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index c44be0df9b0a85..516936311a278d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/HeaderSearch.h"
@@ -3292,6 +3293,25 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));
}
+static void
+AddFunctionExceptSpecToCompletionString(CodeCompletionBuilder &Result,
+ const FunctionDecl *Function) {
+ const auto *Proto = Function->getType()->getAs<FunctionProtoType>();
+ if (!Proto)
+ return;
+
+ auto ExceptInfo = Proto->getExceptionSpecInfo();
+ switch (ExceptInfo.Type) {
+ case EST_BasicNoexcept:
+ case EST_NoexceptTrue:
+ Result.AddInformativeChunk(" noexcept");
+ break;
+
+ default:
+ break;
+ }
+}
+
/// Add the name of the given declaration
static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
const NamedDecl *ND,
@@ -3560,6 +3580,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
AddFunctionParameterChunks(PP, Policy, Function, Result);
Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
+ AddFunctionExceptSpecToCompletionString(Result, Function);
};
if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
@@ -3642,6 +3663,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
AddFunctionParameterChunks(PP, Policy, Function, Result);
Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
+ AddFunctionExceptSpecToCompletionString(Result, Function);
return Result.TakeString();
}
|
Thanks for the patch. For the test, it would be better to write it in this format rather than using clangd. |
In addition to Nathan’s advice, I have a question about the commit message
I didn't see anything reflecting this condition; are you still working on this patch? Would you mind adding a WIP prefix to the title before everything is ready? Thank you! |
No, this is not a WIP. I primarily changed the Yes, I'm not explicitly testing if we're overriding a virtual function in the base. I understand the |
Thanks for your helpful review. I'll move the test to clang/test/CodeCompletion/overrides.cpp. |
The place you're patching is not only specific to "completing override functions", but handles all completion strings involving function declarations. |
Bonus: It appears that neither gcc nor clang implements a provision change from CWG1351,
giving errors on the following code. struct B {
virtual void h() noexcept = delete;
};
struct D: B {
void h() = delete; // Should be OK
};
int main() {
D();
} |
OK. I'll move the changes to the
Good catch. Maybe this deserves a new issue for clang Sema? |
Sounds reasonable to me. Feel free to put up a PR / issue for this if you are interested. |
Hi Younan. FYI, I have opened a new PR that addresses this problem. See #76248. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
c40dbbb
to
8924617
Compare
Ping. Does this PR still get a chance to be merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Lancern, thanks for the reminder and sorry for the long delay here.
The patch looks good to me, thanks! The only thing I notice is that there area number of unrelated formatting changes; if it's not too much trouble, it would be nice to remove those.
8924617
to
36f970d
Compare
I have removed the unrelated formatting changes. Will land later if the CI is green. |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/20116 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/195/builds/11073 Here is the relevant piece of the build log for the reference
|
…ion (llvm#75937) If a virtual function is declared with `noexcept`, functions that override this function in the derived classes must be declared with `noexcept` as well. This PR updates code completion in clang Sema. It adds `noexcept` specifier to override functions in the code completion result if the functions override a `noexcept` virtual function.
…ion (llvm#75937) If a virtual function is declared with `noexcept`, functions that override this function in the derived classes must be declared with `noexcept` as well. This PR updates code completion in clang Sema. It adds `noexcept` specifier to override functions in the code completion result if the functions override a `noexcept` virtual function.
If a virtual function is declared with
noexcept
, functions that override this function in the derived classes must be declared withnoexcept
as well. This PR updates code completion in clang Sema. It addsnoexcept
specifier to override functions in the code completion result if the functions override anoexcept
virtual function.