[clang-tools-extra] [clang-tidy] Adds readability-redundant-const check (PR #189733)
Berkay Sahin via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 5 10:25:51 PDT 2026
https://github.com/berkaysahiin updated https://github.com/llvm/llvm-project/pull/189733
>From 8343df89f949fa30c75cbdd09130b08649577dee Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Tue, 31 Mar 2026 22:20:46 +0300
Subject: [PATCH 01/13] [clang-tidy] Adds readability-redundant-const check
---
.../clang-tidy/readability/CMakeLists.txt | 1 +
.../readability/ReadabilityTidyModule.cpp | 3 +
.../readability/RedundantConstCheck.cpp | 106 ++++++++++++
.../readability/RedundantConstCheck.h | 31 ++++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../checks/readability/redundant-const.rst | 49 ++++++
.../checkers/readability/redundant-const.cpp | 156 ++++++++++++++++++
8 files changed, 352 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantConstCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 686e7c19d650b..95fb26b1fa7ac 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -41,6 +41,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
ReadabilityTidyModule.cpp
RedundantAccessSpecifiersCheck.cpp
RedundantCastingCheck.cpp
+ RedundantConstCheck.cpp
RedundantControlFlowCheck.cpp
RedundantDeclarationCheck.cpp
RedundantFunctionPtrDereferenceCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 8e9e00b23c84a..090bc073cab93 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -42,6 +42,7 @@
#include "QualifiedAutoCheck.h"
#include "RedundantAccessSpecifiersCheck.h"
#include "RedundantCastingCheck.h"
+#include "RedundantConstCheck.h"
#include "RedundantControlFlowCheck.h"
#include "RedundantDeclarationCheck.h"
#include "RedundantFunctionPtrDereferenceCheck.h"
@@ -141,6 +142,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-redundant-access-specifiers");
CheckFactories.registerCheck<RedundantCastingCheck>(
"readability-redundant-casting");
+ CheckFactories.registerCheck<RedundantConstCheck>(
+ "readability-redundant-const");
CheckFactories.registerCheck<RedundantFunctionPtrDereferenceCheck>(
"readability-redundant-function-ptr-dereference");
CheckFactories.registerCheck<RedundantMemberInitCheck>(
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
new file mode 100644
index 0000000000000..1956f9a78e495
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantConstCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include <optional>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
+ varTemplateDecl;
+
+static std::optional<Token>
+findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
+ const SourceManager &SM = *Result.SourceManager;
+
+ const SourceLocation NameBeginLoc = VD->getQualifier()
+ ? VD->getQualifierLoc().getBeginLoc()
+ : VD->getLocation();
+
+ const bool IsPointer = VD->getType()->isPointerType() ||
+ VD->getType()->isNullPtrType() ||
+ VD->getType()->isMemberPointerType();
+
+ const auto ConstSearchStartLoc = [&]() -> std::optional<SourceLocation> {
+ if (!IsPointer)
+ return VD->getBeginLoc();
+
+ SourceLocation StarLoc = utils::lexer::findPreviousTokenKind(
+ NameBeginLoc, SM, Result.Context->getLangOpts(), tok::star);
+
+ if (StarLoc.isValid())
+ return StarLoc;
+
+ // We know it is a pointer but cannot find the start token.
+ // This can happen when either type is aliased or `auto` was used.
+ // e.g: constexpr const auto const str = "hello";
+ // In cases like this, clang analyzer already warns about the use of const
+ // as duplicate, so we can safely ignore these cases.
+
+ return std::nullopt;
+ }();
+
+ if (!ConstSearchStartLoc || !ConstSearchStartLoc->isValid())
+ return std::nullopt;
+
+ const CharSourceRange FileRange = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(*ConstSearchStartLoc, NameBeginLoc), SM,
+ Result.Context->getLangOpts());
+
+ if (!FileRange.isValid())
+ return std::nullopt;
+
+ return utils::lexer::getQualifyingToken(tok::kw_const, FileRange,
+ *Result.Context, SM);
+}
+
+RedundantConstCheck::RedundantConstCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+void RedundantConstCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ varDecl(isConstexpr(), unless(anyOf(hasAncestor(varTemplateDecl()),
+ hasType(referenceType()))))
+ .bind("var_decl"),
+ this);
+}
+
+void RedundantConstCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var_decl");
+
+ // Since we cannot tell the difference between `constexpr const` and
+ // `constexpr` from the AST only, if we cannot find the actual `const` token,
+ // we cannot do anything
+ const std::optional<Token> Tok = findConstToRemove(VD, Result);
+ if (!Tok)
+ return;
+
+ const auto ConstRange =
+ CharSourceRange::getCharRange(Tok->getLocation(), Tok->getEndLoc());
+ diag(Tok->getLocation(),
+ "redundant 'const' in constexpr variable declaration")
+ << ConstRange << FixItHint::CreateRemoval(ConstRange);
+}
+
+bool RedundantConstCheck::isLanguageVersionSupported(
+ const LangOptions &LangOpts) const {
+ return LangOpts.CPlusPlus11;
+}
+
+std::optional<TraversalKind>
+RedundantConstCheck::getCheckTraversalKind() const {
+ return TK_IgnoreUnlessSpelledInSource;
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.h
new file mode 100644
index 0000000000000..882fe4f036f03
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.h
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCONSTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCONSTCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Detects redundant `const` specifiers on variable declarations.
+//
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-const.html
+class RedundantConstCheck : public ClangTidyCheck {
+public:
+ RedundantConstCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+ std::optional<TraversalKind> getCheckTraversalKind() const override;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCONSTCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 97b2ffdd9557b..3312beebcff55 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -163,6 +163,11 @@ New checks
Finds redundant identity type aliases that re-expose a qualified name and can
be replaced with a ``using`` declaration.
+- New :doc:`readability-redundant-const
+ <clang-tidy/checks/readability/redundant-const>` check.
+
+ Detects redundant ``const`` specifiers on variable declarations.
+
- New :doc:`readability-trailing-comma
<clang-tidy/checks/readability/trailing-comma>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index ceab1e9414951..427babef23c9b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -410,6 +410,7 @@ Clang-Tidy Checks
:doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
:doc:`readability-redundant-access-specifiers <readability/redundant-access-specifiers>`, "Yes"
:doc:`readability-redundant-casting <readability/redundant-casting>`, "Yes"
+ :doc:`readability-redundant-const <readability/redundant-const>`, "Yes"
:doc:`readability-redundant-control-flow <readability/redundant-control-flow>`, "Yes"
:doc:`readability-redundant-declaration <readability/redundant-declaration>`, "Yes"
:doc:`readability-redundant-function-ptr-dereference <readability/redundant-function-ptr-dereference>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
new file mode 100644
index 0000000000000..ed6957f21e312
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - readability-redundant-const
+
+readability-redundant-const
+=============================
+
+Detects redundant ``const`` specifiers on variable declarations.
+
+Examples:
+
+.. code-block:: c++
+
+ // Finds:
+ constexpr const int var = {}; // redundant use of `const`
+ // replaced by:
+ constexpr int var = {};
+
+ // Finds:
+ constexpr const int arr[] = {}; // redundant use of `const`
+ // replaced by:
+ constexpr int arr[] = {};
+
+In the examples above, use of ``const`` is redundant since ``constexpr``
+variables are implicitly ``const``.
+
+The check also analyzes pointers:
+
+.. code-block:: c++
+
+ // Finds:
+ constexpr int* const ptr = nullptr; // redundant use of `const`
+ // replaced by:
+ constexpr int* ptr = nullptr;
+
+ // Finds:
+ constexpr int (*const func)(int) = nullptr; // redundant use of `const`
+ // replaced by:
+ constexpr int (*func)(int) = nullptr;
+
+ // Finds:
+ constexpr const char* const greet = "hi"; // redundant use of `const`
+ // replaced by:
+ constexpr const char* greet = "hi";
+
+ // Note that `constexpr` only makes the pointer const but not the pointee.
+ // Thus, this usage is *not* redundant.
+ constexpr const char* ok = "ok"; // OK
+
+
+Requires C++11 or above.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
new file mode 100644
index 0000000000000..6a49e9837b414
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
@@ -0,0 +1,156 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-redundant-const %t --
+
+struct Foo {};
+
+// Simple allowed usages, nothing to warn
+constexpr int n1 = 10;
+const int n2 = 20;
+constexpr Foo n3 = {};
+
+constexpr const int p1 = 10;
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr int p1 = 10;
+
+const constexpr int p2 = 20;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr int p2 = 20;
+
+static const constexpr int p3 = 20;
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: static constexpr int p3 = 20;
+
+constexpr const Foo p4 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr Foo p4 = {};
+
+// Since constexpr makes only the pointer const, this usage is not redundant.
+constexpr const char* n4 = "hello";
+
+constexpr const char* const n5 = "hello";
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr const char* n5 = "hello";
+
+// Since T might be a pointer type, we don't warn on this.
+template<typename T>
+const constexpr T n6 = {};
+
+constexpr const int* n7 = n6<int*>;
+
+const constexpr double p5 = n6<double>;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr double p5 = n6<double>;
+
+constexpr const int* const p6 = n6<int*>;
+// CHECK-MESSAGES: [[@LINE-1]]:22: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr const int* p6 = n6<int*>;
+
+void f() {
+ constexpr Foo n1 = {};
+ const Foo n2 = {};
+
+ const constexpr Foo p1 = {};
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-FIXES: constexpr Foo p1 = {};
+
+ static const constexpr Foo p2 = {};
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-FIXES: static constexpr Foo p2 = {};
+}
+
+struct Config {
+ static const constexpr bool p = false;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-FIXES: static constexpr bool p = false;
+};
+
+template <typename T>
+class Templated {
+ static const constexpr int size = 10;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-FIXES: static constexpr int size = 10;
+ int data[size];
+};
+
+constexpr Templated<int> b{};
+
+template <int N>
+struct Templated2 {
+ static const constexpr int size = N;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-FIXES: static constexpr int size = N;
+ int data[size];
+};
+
+static constexpr int n8[] = {0, 1, 4, 9, 16};
+
+constexpr const int p7[] = {0, 1, 4, 9, 16};
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr int p7[] = {0, 1, 4, 9, 16};
+
+constexpr int square(int n) { return n * n; }
+
+const constexpr int p8 = square(10);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr int p8 = square(10);
+
+constexpr int n9 = square(5);
+
+constexpr Foo** n10 = nullptr;
+
+constexpr Foo* const* n11 = nullptr;
+
+constexpr Foo* const* const p9 = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr Foo* const* p9 = nullptr;
+
+constexpr const Foo* const* const p10 = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:29: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr const Foo* const* p10 = nullptr;
+
+constexpr const int (*n12)[10] = nullptr;
+
+constexpr const int (*const p11)[10] = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr const int (*p11)[10] = nullptr;
+
+constexpr int (*n13)(int) = nullptr;
+
+constexpr int (*const p12)(int) = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr int (*p12)(int) = nullptr;
+
+struct Bar {
+ int x, y;
+ int sum() { return x + y; }
+};
+
+// Pointer to data member
+constexpr const int Bar::*n14 = &Bar::x;
+
+// Pointer to data member
+constexpr const int Bar::* const p13 = &Bar::x;
+// CHECK-MESSAGES: [[@LINE-1]]:28: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr const int Bar::* p13 = &Bar::x;
+
+// Pointer to member function
+constexpr int (Bar::*n15)() = &Bar::sum;
+
+// Pointer to member function
+constexpr int (Bar::* const p14)() = &Bar::sum;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: constexpr int (Bar::* p14)() = &Bar::sum;
+
+#define CONSTEXPR constexpr
+
+CONSTEXPR Foo n16 = {};
+
+CONSTEXPR const Foo p15 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: CONSTEXPR Foo p15 = {};
+
+const CONSTEXPR Foo p16 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-FIXES: CONSTEXPR Foo p16 = {};
+
+// OK for references
+constexpr const Foo& n17 = p15;
>From 26d9a50843e015ec17b6d5aaadb62b18142d58b6 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Tue, 31 Mar 2026 22:56:39 +0300
Subject: [PATCH 02/13] [clang-tidy] fix linter
---
.../clang-tidy/readability/RedundantConstCheck.cpp | 4 ++--
clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index 1956f9a78e495..421143db7b2b7 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -17,7 +17,7 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
static const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
- varTemplateDecl;
+ VarTemplateDecl;
static std::optional<Token>
findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
@@ -70,7 +70,7 @@ RedundantConstCheck::RedundantConstCheck(StringRef Name,
void RedundantConstCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
- varDecl(isConstexpr(), unless(anyOf(hasAncestor(varTemplateDecl()),
+ varDecl(isConstexpr(), unless(anyOf(hasAncestor(VarTemplateDecl()),
hasType(referenceType()))))
.bind("var_decl"),
this);
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3312beebcff55..96b962eec54c6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -157,17 +157,17 @@ New checks
Suggests insertion of ``std::move(...)`` to turn copy assignment operator
calls into move assignment ones, when deemed valid and profitable.
+- New :doc:`readability-redundant-const
+ <clang-tidy/checks/readability/redundant-const>` check.
+
+ Detects redundant ``const`` specifiers on variable declarations.
+
- New :doc:`readability-redundant-qualified-alias
<clang-tidy/checks/readability/redundant-qualified-alias>` check.
Finds redundant identity type aliases that re-expose a qualified name and can
be replaced with a ``using`` declaration.
-- New :doc:`readability-redundant-const
- <clang-tidy/checks/readability/redundant-const>` check.
-
- Detects redundant ``const`` specifiers on variable declarations.
-
- New :doc:`readability-trailing-comma
<clang-tidy/checks/readability/trailing-comma>` check.
>From 0f544a905ed0b861d9efb9d2f5a271ff1b5decef Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Wed, 1 Apr 2026 20:07:16 +0300
Subject: [PATCH 03/13] Update
clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../docs/clang-tidy/checks/readability/redundant-const.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
index ed6957f21e312..c33c0f5cd155b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
@@ -1,7 +1,7 @@
.. title:: clang-tidy - readability-redundant-const
readability-redundant-const
-=============================
+===========================
Detects redundant ``const`` specifiers on variable declarations.
>From 5030149d16eac48351d41400d4a2cf863404a13e Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Fri, 3 Apr 2026 23:09:08 +0300
Subject: [PATCH 04/13] Update
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
Co-authored-by: Victor Chernyakin <chernyakin.victor.j at outlook.com>
---
.../test/clang-tidy/checkers/readability/redundant-const.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
index 6a49e9837b414..6a749b8f02161 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s readability-redundant-const %t --
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-redundant-const %t
struct Foo {};
>From b69400b2d6e69c6f7e36b447f84bc950ab3f27e1 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Fri, 3 Apr 2026 23:10:18 +0300
Subject: [PATCH 05/13] Update docs to avoid confusion
Co-authored-by: Victor Chernyakin <chernyakin.victor.j at outlook.com>
---
.../docs/clang-tidy/checks/readability/redundant-const.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
index c33c0f5cd155b..a8c265488d057 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
@@ -10,9 +10,9 @@ Examples:
.. code-block:: c++
// Finds:
- constexpr const int var = {}; // redundant use of `const`
+ constexpr const int var = 10; // redundant use of `const`
// replaced by:
- constexpr int var = {};
+ constexpr int var = 10;
// Finds:
constexpr const int arr[] = {}; // redundant use of `const`
>From 72c618b0868d34b96033296343568434ee0f2bf5 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Fri, 3 Apr 2026 23:26:05 +0300
Subject: [PATCH 06/13] Simplifies const search logic
Co-authored-by: Victor Chernyakin <chernyakin.victor.j at outlook.com>
---
.../readability/RedundantConstCheck.cpp | 28 +++++++------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index 421143db7b2b7..f7cc78cf7f19f 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -31,26 +31,18 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
VD->getType()->isNullPtrType() ||
VD->getType()->isMemberPointerType();
- const auto ConstSearchStartLoc = [&]() -> std::optional<SourceLocation> {
- if (!IsPointer)
- return VD->getBeginLoc();
-
- SourceLocation StarLoc = utils::lexer::findPreviousTokenKind(
+ // If the 'findPreviousTokenKind' below fails,
+ // we know it is a pointer but cannot find the start token.
+ // This can happen when either type is aliased or `auto` was used.
+ // e.g: constexpr const auto const str = "hello";
+ // In cases like this, clang analyzer already warns about the use of const
+ // as duplicate, so we can safely ignore these cases.
+ const SourceLocation ConstSearchStartLoc = !IsPointer
+ ? VD->getBeginLoc()
+ : utils::lexer::findPreviousTokenKind(
NameBeginLoc, SM, Result.Context->getLangOpts(), tok::star);
- if (StarLoc.isValid())
- return StarLoc;
-
- // We know it is a pointer but cannot find the start token.
- // This can happen when either type is aliased or `auto` was used.
- // e.g: constexpr const auto const str = "hello";
- // In cases like this, clang analyzer already warns about the use of const
- // as duplicate, so we can safely ignore these cases.
-
- return std::nullopt;
- }();
-
- if (!ConstSearchStartLoc || !ConstSearchStartLoc->isValid())
+ if (ConstSearchStartLoc.isInvalid())
return std::nullopt;
const CharSourceRange FileRange = Lexer::makeFileCharRange(
>From 3da91747a6f59db5ae8c5d8f797320f185be3e85 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Fri, 3 Apr 2026 23:45:08 +0300
Subject: [PATCH 07/13] Fix linter issues
---
.../clang-tidy/readability/RedundantConstCheck.cpp | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index f7cc78cf7f19f..b14f4a2f6e329 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -37,10 +37,11 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
// e.g: constexpr const auto const str = "hello";
// In cases like this, clang analyzer already warns about the use of const
// as duplicate, so we can safely ignore these cases.
- const SourceLocation ConstSearchStartLoc = !IsPointer
- ? VD->getBeginLoc()
- : utils::lexer::findPreviousTokenKind(
- NameBeginLoc, SM, Result.Context->getLangOpts(), tok::star);
+ const SourceLocation ConstSearchStartLoc =
+ !IsPointer
+ ? VD->getBeginLoc()
+ : utils::lexer::findPreviousTokenKind(
+ NameBeginLoc, SM, Result.Context->getLangOpts(), tok::star);
if (ConstSearchStartLoc.isInvalid())
return std::nullopt;
>From 9855bc6ba6dd3d1db15548f6f52feb591f67c178 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Sat, 4 Apr 2026 00:17:41 +0300
Subject: [PATCH 08/13] Fix compile
---
.../clang-tidy/readability/RedundantConstCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index b14f4a2f6e329..8449d32d191ca 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -47,7 +47,7 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
return std::nullopt;
const CharSourceRange FileRange = Lexer::makeFileCharRange(
- CharSourceRange::getCharRange(*ConstSearchStartLoc, NameBeginLoc), SM,
+ CharSourceRange::getCharRange(ConstSearchStartLoc, NameBeginLoc), SM,
Result.Context->getLangOpts());
if (!FileRange.isValid())
>From 2754e16f2ba35bd261e14e5b9384a06ad7dc2b09 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Sat, 4 Apr 2026 19:21:35 +0300
Subject: [PATCH 09/13] Address PR comments
- C23 support
- Warn on template variable decls
- Update warning message
---
.../readability/RedundantConstCheck.cpp | 13 ++---
.../checks/readability/redundant-const.rst | 2 +-
.../checkers/readability/redundant-const.c | 23 +++++++++
.../checkers/readability/redundant-const.cpp | 47 ++++++++++---------
4 files changed, 52 insertions(+), 33 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index 8449d32d191ca..cd59accdab541 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -16,9 +16,6 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
-static const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
- VarTemplateDecl;
-
static std::optional<Token>
findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
const SourceManager &SM = *Result.SourceManager;
@@ -35,7 +32,7 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
// we know it is a pointer but cannot find the start token.
// This can happen when either type is aliased or `auto` was used.
// e.g: constexpr const auto const str = "hello";
- // In cases like this, clang analyzer already warns about the use of const
+ // In cases like this, Clang already warns about the use of const
// as duplicate, so we can safely ignore these cases.
const SourceLocation ConstSearchStartLoc =
!IsPointer
@@ -63,9 +60,7 @@ RedundantConstCheck::RedundantConstCheck(StringRef Name,
void RedundantConstCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
- varDecl(isConstexpr(), unless(anyOf(hasAncestor(VarTemplateDecl()),
- hasType(referenceType()))))
- .bind("var_decl"),
+ varDecl(isConstexpr(), unless(hasType(referenceType()))).bind("var_decl"),
this);
}
@@ -82,13 +77,13 @@ void RedundantConstCheck::check(const MatchFinder::MatchResult &Result) {
const auto ConstRange =
CharSourceRange::getCharRange(Tok->getLocation(), Tok->getEndLoc());
diag(Tok->getLocation(),
- "redundant 'const' in constexpr variable declaration")
+ "redundant use of `const`; `constexpr` already implies `const`.")
<< ConstRange << FixItHint::CreateRemoval(ConstRange);
}
bool RedundantConstCheck::isLanguageVersionSupported(
const LangOptions &LangOpts) const {
- return LangOpts.CPlusPlus11;
+ return LangOpts.CPlusPlus11 || LangOpts.C23;
}
std::optional<TraversalKind>
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
index a8c265488d057..c434ca28ffb07 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-const.rst
@@ -46,4 +46,4 @@ The check also analyzes pointers:
constexpr const char* ok = "ok"; // OK
-Requires C++11 or above.
+Requires C++11 or C23.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
new file mode 100644
index 0000000000000..1aa1835c8b55d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy -std=c23-or-later %s readability-redundant-const %t
+
+const int n1 = 20;
+
+// C23 constexpr
+constexpr const int p1 = 10;
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-FIXES: constexpr int p1 = 10;
+
+const constexpr int p2 = 20;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-FIXES: constexpr int p2 = 20;
+
+static const constexpr int p3 = 20;
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-FIXES: static constexpr int p3 = 20;
+
+// Since constexpr makes only the pointer const, this usage is not redundant.
+constexpr const char *n2 = 0;
+
+constexpr const char *const p4 = 0;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-FIXES: constexpr const char *p4 = 0;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
index 6a749b8f02161..fcdee5b02f8a9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
@@ -8,40 +8,41 @@ const int n2 = 20;
constexpr Foo n3 = {};
constexpr const int p1 = 10;
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int p1 = 10;
const constexpr int p2 = 20;
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int p2 = 20;
static const constexpr int p3 = 20;
-// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: static constexpr int p3 = 20;
constexpr const Foo p4 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr Foo p4 = {};
// Since constexpr makes only the pointer const, this usage is not redundant.
constexpr const char* n4 = "hello";
constexpr const char* const n5 = "hello";
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr const char* n5 = "hello";
-// Since T might be a pointer type, we don't warn on this.
template<typename T>
const constexpr T n6 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-FIXES: constexpr T n6 = {};
constexpr const int* n7 = n6<int*>;
const constexpr double p5 = n6<double>;
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr double p5 = n6<double>;
constexpr const int* const p6 = n6<int*>;
-// CHECK-MESSAGES: [[@LINE-1]]:22: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:22: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr const int* p6 = n6<int*>;
void f() {
@@ -49,24 +50,24 @@ void f() {
const Foo n2 = {};
const constexpr Foo p1 = {};
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr Foo p1 = {};
static const constexpr Foo p2 = {};
- // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: static constexpr Foo p2 = {};
}
struct Config {
static const constexpr bool p = false;
- // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: static constexpr bool p = false;
};
template <typename T>
class Templated {
static const constexpr int size = 10;
- // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: static constexpr int size = 10;
int data[size];
};
@@ -76,7 +77,7 @@ constexpr Templated<int> b{};
template <int N>
struct Templated2 {
static const constexpr int size = N;
- // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant 'const' in constexpr variable declaration
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: static constexpr int size = N;
int data[size];
};
@@ -84,13 +85,13 @@ struct Templated2 {
static constexpr int n8[] = {0, 1, 4, 9, 16};
constexpr const int p7[] = {0, 1, 4, 9, 16};
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int p7[] = {0, 1, 4, 9, 16};
constexpr int square(int n) { return n * n; }
const constexpr int p8 = square(10);
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int p8 = square(10);
constexpr int n9 = square(5);
@@ -100,23 +101,23 @@ constexpr Foo** n10 = nullptr;
constexpr Foo* const* n11 = nullptr;
constexpr Foo* const* const p9 = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr Foo* const* p9 = nullptr;
constexpr const Foo* const* const p10 = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:29: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:29: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr const Foo* const* p10 = nullptr;
constexpr const int (*n12)[10] = nullptr;
constexpr const int (*const p11)[10] = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr const int (*p11)[10] = nullptr;
constexpr int (*n13)(int) = nullptr;
constexpr int (*const p12)(int) = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int (*p12)(int) = nullptr;
struct Bar {
@@ -129,7 +130,7 @@ constexpr const int Bar::*n14 = &Bar::x;
// Pointer to data member
constexpr const int Bar::* const p13 = &Bar::x;
-// CHECK-MESSAGES: [[@LINE-1]]:28: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:28: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr const int Bar::* p13 = &Bar::x;
// Pointer to member function
@@ -137,7 +138,7 @@ constexpr int (Bar::*n15)() = &Bar::sum;
// Pointer to member function
constexpr int (Bar::* const p14)() = &Bar::sum;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int (Bar::* p14)() = &Bar::sum;
#define CONSTEXPR constexpr
@@ -145,11 +146,11 @@ constexpr int (Bar::* const p14)() = &Bar::sum;
CONSTEXPR Foo n16 = {};
CONSTEXPR const Foo p15 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: CONSTEXPR Foo p15 = {};
const CONSTEXPR Foo p16 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant 'const' in constexpr variable declaration
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: CONSTEXPR Foo p16 = {};
// OK for references
>From e61d425fb247989c9e9e84086b3fe2642ea53cc8 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Sat, 4 Apr 2026 22:44:16 +0300
Subject: [PATCH 10/13] Prefer IsInvalid over !IsValid
Co-authored-by: Victor Chernyakin <chernyakin.victor.j at outlook.com>
---
.../clang-tidy/readability/RedundantConstCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index cd59accdab541..f6310caad8b71 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -47,7 +47,7 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
CharSourceRange::getCharRange(ConstSearchStartLoc, NameBeginLoc), SM,
Result.Context->getLangOpts());
- if (!FileRange.isValid())
+ if (FileRange.isInvalid())
return std::nullopt;
return utils::lexer::getQualifyingToken(tok::kw_const, FileRange,
>From afc21ff8e249a067bd8e518862354caa3ff747b9 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Sun, 5 Apr 2026 14:55:06 +0300
Subject: [PATCH 11/13] Update
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
Co-authored-by: Baranov Victor <bar.victor.2002 at gmail.com>
---
.../test/clang-tidy/checkers/readability/redundant-const.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
index 1aa1835c8b55d..fa47c44c11c7f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
@@ -2,7 +2,6 @@
const int n1 = 20;
-// C23 constexpr
constexpr const int p1 = 10;
// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
// CHECK-FIXES: constexpr int p1 = 10;
>From 7d422aa27c88ac7f59570ba406a6aaf238384cb2 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Sun, 5 Apr 2026 20:13:50 +0300
Subject: [PATCH 12/13] [clang-tidy] Address PR comments
- No need to specially handle nullptr
- Simplify diag
- Format warning message properly
- Add more tests
---
.../readability/RedundantConstCheck.cpp | 20 ++-
.../checkers/readability/redundant-const.c | 8 +-
.../checkers/readability/redundant-const.cpp | 130 ++++++++++--------
3 files changed, 88 insertions(+), 70 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index f6310caad8b71..fba08286d354f 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -24,9 +24,8 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
? VD->getQualifierLoc().getBeginLoc()
: VD->getLocation();
- const bool IsPointer = VD->getType()->isPointerType() ||
- VD->getType()->isNullPtrType() ||
- VD->getType()->isMemberPointerType();
+ const bool IsPointer =
+ VD->getType()->isPointerType() || VD->getType()->isMemberPointerType();
// If the 'findPreviousTokenKind' below fails,
// we know it is a pointer but cannot find the start token.
@@ -43,6 +42,15 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
if (ConstSearchStartLoc.isInvalid())
return std::nullopt;
+ const SourceLocation PrevSemi = utils::lexer::findPreviousAnyTokenKind(
+ NameBeginLoc, SM, Result.Context->getLangOpts(), tok::semi);
+
+ // Verify that there is no semicolon between ConstSearchStartLoc and
+ // NameBeginLoc This is to limit search area for our variable decl only
+ if (!PrevSemi.isInvalid() &&
+ SM.isBeforeInTranslationUnit(ConstSearchStartLoc, PrevSemi))
+ return std::nullopt;
+
const CharSourceRange FileRange = Lexer::makeFileCharRange(
CharSourceRange::getCharRange(ConstSearchStartLoc, NameBeginLoc), SM,
Result.Context->getLangOpts());
@@ -74,11 +82,9 @@ void RedundantConstCheck::check(const MatchFinder::MatchResult &Result) {
if (!Tok)
return;
- const auto ConstRange =
- CharSourceRange::getCharRange(Tok->getLocation(), Tok->getEndLoc());
diag(Tok->getLocation(),
- "redundant use of `const`; `constexpr` already implies `const`.")
- << ConstRange << FixItHint::CreateRemoval(ConstRange);
+ "redundant use of 'const'; 'constexpr' already implies 'const'")
+ << FixItHint::CreateRemoval(Tok->getLocation());
}
bool RedundantConstCheck::isLanguageVersionSupported(
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
index 1aa1835c8b55d..f21ca9cdf2c51 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.c
@@ -4,20 +4,20 @@ const int n1 = 20;
// C23 constexpr
constexpr const int p1 = 10;
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr int p1 = 10;
const constexpr int p2 = 20;
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr int p2 = 20;
static const constexpr int p3 = 20;
-// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: static constexpr int p3 = 20;
// Since constexpr makes only the pointer const, this usage is not redundant.
constexpr const char *n2 = 0;
constexpr const char *const p4 = 0;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr const char *p4 = 0;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
index fcdee5b02f8a9..86f6a915fa8ee 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-const.cpp
@@ -2,97 +2,98 @@
struct Foo {};
-// Simple allowed usages, nothing to warn
constexpr int n1 = 10;
const int n2 = 20;
constexpr Foo n3 = {};
constexpr const int p1 = 10;
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr int p1 = 10;
const constexpr int p2 = 20;
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr int p2 = 20;
static const constexpr int p3 = 20;
-// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: static constexpr int p3 = 20;
constexpr const Foo p4 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr Foo p4 = {};
// Since constexpr makes only the pointer const, this usage is not redundant.
constexpr const char* n4 = "hello";
-constexpr const char* const n5 = "hello";
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr const char* n5 = "hello";
+constexpr const auto n5 = "hello";
+
+constexpr const char* const p5 = "hello";
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr const char* p5 = "hello";
template<typename T>
-const constexpr T n6 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr T n6 = {};
+const constexpr T p6 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr T p6 = {};
-constexpr const int* n7 = n6<int*>;
+constexpr const int* n6 = p6<int*>;
-const constexpr double p5 = n6<double>;
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr double p5 = n6<double>;
+const constexpr double p7 = p6<double>;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr double p7 = p6<double>;
-constexpr const int* const p6 = n6<int*>;
-// CHECK-MESSAGES: [[@LINE-1]]:22: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr const int* p6 = n6<int*>;
+constexpr const int* const p8 = p6<int*>;
+// CHECK-MESSAGES: [[@LINE-1]]:22: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr const int* p8 = p6<int*>;
void f() {
constexpr Foo n1 = {};
const Foo n2 = {};
const constexpr Foo p1 = {};
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant use of `const`; `constexpr` already implies `const`.
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: constexpr Foo p1 = {};
static const constexpr Foo p2 = {};
- // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant use of `const`; `constexpr` already implies `const`.
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: static constexpr Foo p2 = {};
}
struct Config {
static const constexpr bool p = false;
- // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of `const`; `constexpr` already implies `const`.
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: static constexpr bool p = false;
};
template <typename T>
class Templated {
static const constexpr int size = 10;
- // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of `const`; `constexpr` already implies `const`.
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: static constexpr int size = 10;
int data[size];
};
-constexpr Templated<int> b{};
+constexpr Templated<int> n7{};
template <int N>
struct Templated2 {
static const constexpr int size = N;
- // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of `const`; `constexpr` already implies `const`.
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant use of 'const'; 'constexpr' already implies 'const'
// CHECK-FIXES: static constexpr int size = N;
int data[size];
};
static constexpr int n8[] = {0, 1, 4, 9, 16};
-constexpr const int p7[] = {0, 1, 4, 9, 16};
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr int p7[] = {0, 1, 4, 9, 16};
+constexpr const int p9[] = {0, 1, 4, 9, 16};
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr int p9[] = {0, 1, 4, 9, 16};
constexpr int square(int n) { return n * n; }
-const constexpr int p8 = square(10);
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr int p8 = square(10);
+const constexpr int p10 = square(10);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr int p10 = square(10);
constexpr int n9 = square(5);
@@ -100,58 +101,69 @@ constexpr Foo** n10 = nullptr;
constexpr Foo* const* n11 = nullptr;
-constexpr Foo* const* const p9 = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr Foo* const* p9 = nullptr;
+constexpr Foo* const* const p11 = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr Foo* const* p11 = nullptr;
-constexpr const Foo* const* const p10 = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:29: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr const Foo* const* p10 = nullptr;
+constexpr const Foo* const* const p12 = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:29: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr const Foo* const* p12 = nullptr;
constexpr const int (*n12)[10] = nullptr;
-constexpr const int (*const p11)[10] = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr const int (*p11)[10] = nullptr;
+constexpr const int (*const p13)[10] = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr const int (*p13)[10] = nullptr;
constexpr int (*n13)(int) = nullptr;
-constexpr int (*const p12)(int) = nullptr;
-// CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr int (*p12)(int) = nullptr;
+constexpr int (*const p14)(int) = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr int (*p14)(int) = nullptr;
struct Bar {
int x, y;
int sum() { return x + y; }
};
-// Pointer to data member
constexpr const int Bar::*n14 = &Bar::x;
-// Pointer to data member
-constexpr const int Bar::* const p13 = &Bar::x;
-// CHECK-MESSAGES: [[@LINE-1]]:28: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr const int Bar::* p13 = &Bar::x;
+constexpr const int Bar::* const p15 = &Bar::x;
+// CHECK-MESSAGES: [[@LINE-1]]:28: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr const int Bar::* p15 = &Bar::x;
-// Pointer to member function
constexpr int (Bar::*n15)() = &Bar::sum;
-// Pointer to member function
-constexpr int (Bar::* const p14)() = &Bar::sum;
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: constexpr int (Bar::* p14)() = &Bar::sum;
+constexpr int (Bar::* const p16)() = &Bar::sum;
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr int (Bar::* p16)() = &Bar::sum;
#define CONSTEXPR constexpr
+#define CONST const
CONSTEXPR Foo n16 = {};
-CONSTEXPR const Foo p15 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: CONSTEXPR Foo p15 = {};
+CONSTEXPR const Foo p17 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: CONSTEXPR Foo p17 = {};
+
+const CONSTEXPR Foo p18 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: CONSTEXPR Foo p18 = {};
+
+CONST constexpr Foo n17 = {};
+constexpr CONST Foo n18 = {};
-const CONSTEXPR Foo p16 = {};
-// CHECK-MESSAGES: [[@LINE-1]]:1: warning: redundant use of `const`; `constexpr` already implies `const`.
-// CHECK-FIXES: CONSTEXPR Foo p16 = {};
+const Foo* n20 = nullptr;
// OK for references
-constexpr const Foo& n17 = p15;
+constexpr const Foo& n19 = p18;
+constexpr const Foo*& n21 = n20;
+
+constexpr const decltype(nullptr) p19 = nullptr;
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr decltype(nullptr) p19 = nullptr;
+
+constexpr const decltype(0) p20 = {};
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: redundant use of 'const'; 'constexpr' already implies 'const'
+// CHECK-FIXES: constexpr decltype(0) p20 = {};
>From 4a547d86f0dc24cff454dcd4a72e9f39fecf82e1 Mon Sep 17 00:00:00 2001
From: Berkay Sahin <berkaysahindev at gmail.com>
Date: Sun, 5 Apr 2026 20:25:30 +0300
Subject: [PATCH 13/13] [clang-tidy] Add missing period
---
.../clang-tidy/readability/RedundantConstCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
index fba08286d354f..4f3a16c98d1ff 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantConstCheck.cpp
@@ -46,7 +46,7 @@ findConstToRemove(const VarDecl *VD, const MatchFinder::MatchResult &Result) {
NameBeginLoc, SM, Result.Context->getLangOpts(), tok::semi);
// Verify that there is no semicolon between ConstSearchStartLoc and
- // NameBeginLoc This is to limit search area for our variable decl only
+ // NameBeginLoc. This is to limit search area for our variable decl only
if (!PrevSemi.isInvalid() &&
SM.isBeforeInTranslationUnit(ConstSearchStartLoc, PrevSemi))
return std::nullopt;
More information about the cfe-commits
mailing list