[clang] [Sema][clangd] add noexcept to override functions during code completion (PR #75937)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 12 07:44:28 PDT 2025
https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/75937
>From 8924617e16a035730c4c33f17c726dd5e5bb5f00 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Tue, 19 Dec 2023 22:24:23 +0800
Subject: [PATCH] [clangd][Sema] add noexcept to override functions during code
completion
---
clang/lib/Sema/SemaCodeComplete.cpp | 77 ++++++++++++++++---------
clang/test/CodeCompletion/overrides.cpp | 14 +++++
2 files changed, 64 insertions(+), 27 deletions(-)
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index f9f7c192f19d2..e206425bf1c9d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -26,6 +26,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"
@@ -184,7 +185,7 @@ class ResultBuilder {
/// Overloaded C++ member functions found by SemaLookup.
/// Used to determine when one overload is dominated by another.
- llvm::DenseMap<std::pair<DeclContext *, /*Name*/uintptr_t>, ShadowMapEntry>
+ llvm::DenseMap<std::pair<DeclContext *, /*Name=*/uintptr_t>, ShadowMapEntry>
OverloadMap;
/// If we're potentially referring to a C++ member function, the set
@@ -1432,16 +1433,16 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
}
// Detect cases where a ref-qualified method cannot be invoked.
switch (Method->getRefQualifier()) {
- case RQ_LValue:
- if (ObjectKind != VK_LValue && !MethodQuals.hasConst())
- return;
- break;
- case RQ_RValue:
- if (ObjectKind == VK_LValue)
- return;
- break;
- case RQ_None:
- break;
+ case RQ_LValue:
+ if (ObjectKind != VK_LValue && !MethodQuals.hasConst())
+ return;
+ break;
+ case RQ_RValue:
+ if (ObjectKind == VK_LValue)
+ return;
+ break;
+ case RQ_None:
+ break;
}
/// Check whether this dominates another overloaded method, which should
@@ -1490,9 +1491,7 @@ void ResultBuilder::AddResult(Result R) {
void ResultBuilder::EnterNewScope() { ShadowMaps.emplace_back(); }
/// Exit from the current scope.
-void ResultBuilder::ExitScope() {
- ShadowMaps.pop_back();
-}
+void ResultBuilder::ExitScope() { ShadowMaps.pop_back(); }
/// Determines whether this given declaration will be found by
/// ordinary name lookup.
@@ -2557,7 +2556,8 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,
ReturnType = Method->getReturnType();
else if (SemaRef.getCurBlock() &&
!SemaRef.getCurBlock()->ReturnType.isNull())
- ReturnType = SemaRef.getCurBlock()->ReturnType;;
+ ReturnType = SemaRef.getCurBlock()->ReturnType;
+ ;
if (ReturnType.isNull() || ReturnType->isVoidType()) {
Builder.AddTypedTextChunk("return");
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
@@ -3427,6 +3427,25 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));
}
+static void
+AddFunctionExceptSpecToCompletionString(std::string &NameAndSignature,
+ 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:
+ NameAndSignature += " noexcept";
+ break;
+
+ default:
+ break;
+ }
+}
+
/// Add the name of the given declaration
static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
const NamedDecl *ND,
@@ -3642,6 +3661,13 @@ CodeCompletionResult::createCodeCompletionStringForOverride(
std::string NameAndSignature;
// For overrides all chunks go into the result, none are informative.
printOverrideString(*CCS, BeforeName, NameAndSignature);
+
+ // If the virtual function is declared with "noexcept", add it in the result
+ // code completion string.
+ const auto *VirtualFunc = dyn_cast<FunctionDecl>(Declaration);
+ assert(VirtualFunc && "overridden decl must be a function");
+ AddFunctionExceptSpecToCompletionString(NameAndSignature, VirtualFunc);
+
NameAndSignature += " override";
Result.AddTextChunk(Result.getAllocator().CopyString(BeforeName));
@@ -4886,7 +4912,8 @@ static void AddEnumerators(ResultBuilder &Results, ASTContext &Context,
EnumDecl *Enum, DeclContext *CurContext,
const CoveredEnumerators &Enumerators) {
NestedNameSpecifier *Qualifier = Enumerators.SuggestedQualifier;
- if (Context.getLangOpts().CPlusPlus && !Qualifier && Enumerators.Seen.empty()) {
+ if (Context.getLangOpts().CPlusPlus && !Qualifier &&
+ Enumerators.Seen.empty()) {
// If there are no prior enumerators in C++, check whether we have to
// qualify the names of the enumerators that we suggest, because they
// may not be visible in this scope.
@@ -5292,8 +5319,7 @@ AddObjCProperties(const CodeCompletionContext &CCContext,
AllowNullaryMethods, CurContext, AddedProperties,
Results, IsBaseExprStatement, IsClassProperty,
/*InOriginalClass*/ false);
- } else if (const auto *Category =
- dyn_cast<ObjCCategoryDecl>(Container)) {
+ } else if (const auto *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
// Look through protocols.
for (auto *P : Category->protocols())
AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,
@@ -6159,8 +6185,7 @@ void SemaCodeCompletion::CodeCompleteCase(Scope *S) {
Expr *CaseVal = Case->getLHS()->IgnoreParenCasts();
if (auto *DRE = dyn_cast<DeclRefExpr>(CaseVal))
- if (auto *Enumerator =
- dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ if (auto *Enumerator = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
// We look into the AST of the case statement to determine which
// enumerator was named. Alternatively, we could compute the value of
// the integral constant expression, then compare it against the
@@ -8480,11 +8505,10 @@ void SemaCodeCompletion::CodeCompleteObjCInstanceMessage(
return;
RecExpr = Conv.get();
}
- QualType ReceiverType = RecExpr
- ? RecExpr->getType()
- : Super ? Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(Super))
- : Context.getObjCIdType();
+ QualType ReceiverType = RecExpr ? RecExpr->getType()
+ : Super ? Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(Super))
+ : Context.getObjCIdType();
// If we're messaging an expression with type "id" or "Class", check
// whether we know something special about the receiver that allows
@@ -10356,8 +10380,7 @@ void SemaCodeCompletion::CodeCompleteIncludedFile(llvm::StringRef Dir,
};
// Helper: scans IncludeDir for nice files, and adds results for each.
- auto AddFilesFromIncludeDir = [&](StringRef IncludeDir,
- bool IsSystem,
+ auto AddFilesFromIncludeDir = [&](StringRef IncludeDir, bool IsSystem,
DirectoryLookup::LookupType_t LookupType) {
llvm::SmallString<128> Dir = IncludeDir;
if (!NativeRelDir.empty()) {
diff --git a/clang/test/CodeCompletion/overrides.cpp b/clang/test/CodeCompletion/overrides.cpp
index 7f330904eede9..0a12973f846b7 100644
--- a/clang/test/CodeCompletion/overrides.cpp
+++ b/clang/test/CodeCompletion/overrides.cpp
@@ -41,3 +41,17 @@ void func() {
// Runs completion at empty line on line 37.
// RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-5):1 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}}
+
+class NoexceptBase {
+ public:
+ virtual void method() noexcept;
+};
+
+class NoexceptDerived : public NoexceptBase {
+ public:
+ met;
+};
+
+// Runs completion at met^ on line 52.
+// RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-4):6 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: COMPLETION: Pattern : void method() noexcept override{{$}}
More information about the cfe-commits
mailing list