[clang-tools-extra] [clang-tidy] Add bugprone-custom-errno-declaration check (PR #213015)
Csaba Zeitvogel via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 15 03:58:10 PDT 2026
https://github.com/zeitcsabi updated https://github.com/llvm/llvm-project/pull/213015
>From 71afa5ceb5275897e9fadd35757c6863b336ef52 Mon Sep 17 00:00:00 2001
From: Csaba Zeitvogel <qtaq9s at inf.elte.hu>
Date: Thu, 30 Jul 2026 14:45:34 +0200
Subject: [PATCH 1/5] [clang-tidy] Add cerrno check to bugprone
This simple check is based on the cerrno portion of MSC38-C.
---
.../bugprone/BugproneTidyModule.cpp | 3 ++
.../clang-tidy/bugprone/CMakeLists.txt | 1 +
.../clang-tidy/bugprone/CerrnoCheck.cpp | 38 +++++++++++++++++++
.../clang-tidy/bugprone/CerrnoCheck.h | 35 +++++++++++++++++
.../clang-tidy/checks/bugprone/cerrno.rst | 17 +++++++++
.../clang-tidy/checkers/bugprone/cerrno.cpp | 25 ++++++++++++
6 files changed, 119 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 3aa39d10ceb5dc..54f0e7345ff97e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -18,6 +18,7 @@
#include "BranchCloneCheck.h"
#include "CapturingThisInMemberVariableCheck.h"
#include "CastingThroughVoidCheck.h"
+#include "CerrnoCheck.h"
#include "ChainedComparisonCheck.h"
#include "CommandProcessorCheck.h"
#include "ComparePointerToMemberVirtualFunctionCheck.h"
@@ -144,6 +145,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-capturing-this-in-member-variable");
CheckFactories.registerCheck<CastingThroughVoidCheck>(
"bugprone-casting-through-void");
+ CheckFactories.registerCheck<CerrnoCheck>(
+ "bugprone-cerrno");
CheckFactories.registerCheck<ChainedComparisonCheck>(
"bugprone-chained-comparison");
CheckFactories.registerCheck<CommandProcessorCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 43e85b1407f21a..6345e61b3b1266 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -15,6 +15,7 @@ add_clang_library(clangTidyBugproneModule STATIC
BugproneTidyModule.cpp
CapturingThisInMemberVariableCheck.cpp
CastingThroughVoidCheck.cpp
+ CerrnoCheck.cpp
ChainedComparisonCheck.cpp
CommandProcessorCheck.cpp
ComparePointerToMemberVirtualFunctionCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp
new file mode 100644
index 00000000000000..8dbb6856620843
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "CerrnoCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+void CerrnoCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(varDecl(hasType(asString("int")), hasName("errno"), hasExternalFormalLinkage()).bind("errnoDecl"), this);
+}
+
+void CerrnoCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("errnoDecl"); // NULL?
+ const SourceManager &SM = *Result.SourceManager;
+ const auto Location = MatchedDecl->getLocation();
+ const auto FileID = SM.getFileID(Location);
+
+ unsigned Line = SM.getSpellingLineNumber(MatchedDecl->getBeginLoc());
+
+ const auto Diag = diag(Location, "errno declaration detected, include cerrno instead")
+ << FixItHint::CreateRemoval(CharSourceRange::getCharRange(SM.translateLineCol(FileID, Line, 1), SM.translateLineCol(FileID, Line + 1, 1)));
+
+ if (alreadyInserted)
+ return;
+
+ Diag << FixItHint::CreateInsertion(SM.getLocForStartOfFile(FileID), "#include <cerrno>\n");
+ alreadyInserted = true;
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h b/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h
new file mode 100644
index 00000000000000..7517acd28a49f5
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BUGPRONE_CERRNOCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CERRNOCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Warns if you declare an extern int variable named 'errno'.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/cerrno.html
+class CerrnoCheck : public ClangTidyCheck {
+public:
+ CerrnoCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+private:
+ bool alreadyInserted = false;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CERRNOCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst
new file mode 100644
index 00000000000000..73ec1c76901af4
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - bugprone-cerrno
+
+bugprone-cerrno
+===============
+
+Warns if you declare an ``extern int`` variable named ``errno`` instead of including ``<cerrno>``.
+It is able to fix the problem by removing the line of the declaration and inserting ``#include <cerrno>``
+at the top of the file.
+
+For further reading, see `the page of SEI CERT C Coding Standard
+<https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/rules/miscellaneous-msc/msc38-c/>`_.
+
+Example:
+
+.. code-block:: c++
+
+ extern int errno;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp
new file mode 100644
index 00000000000000..40109d31aa26ba
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s bugprone-cerrno %t
+
+namespace cerrno_test_0 {
+ extern int errno;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-cerrno]
+ // CHECK-FIXES: {{^}}{{$}}
+} // namespace cerrno_test_0
+
+namespace cerrno_test_1 {
+ extern "C" int errno;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: errno declaration detected, include cerrno instead [bugprone-cerrno]
+ // CHECK-FIXES: {{^}}{{$}}
+} // namespace cerrno_test_1
+
+namespace cerrno_test_2 { // all cases should be ignored in this namespace
+ extern bool errno;
+
+ void foo(int errno) {}
+
+ int fooo()
+ {
+ int errno = 0;
+ return errno;
+ }
+} // namespace cerrno_test_2
>From aef551217e80fcd85dee17d41b41867583e4ff75 Mon Sep 17 00:00:00 2001
From: Csaba Zeitvogel <qtaq9s at inf.elte.hu>
Date: Sat, 1 Aug 2026 14:24:09 +0200
Subject: [PATCH 2/5] Apply requested changes
The check has been renamed, the documentation has been converted to Markdown format, etc.
---
.../clang-tidy/bugprone/BugproneTidyModule.cpp | 6 +++---
.../clang-tidy/bugprone/CMakeLists.txt | 2 +-
...heck.cpp => CustomErrnoDeclarationCheck.cpp} | 6 +++---
...rnoCheck.h => CustomErrnoDeclarationCheck.h} | 12 ++++++------
.../docs/clang-tidy/checks/bugprone/cerrno.rst | 17 -----------------
.../checks/bugprone/custom-errno-declaration.md | 14 ++++++++++++++
...{cerrno.cpp => custom-errno-declaration.cpp} | 6 +++---
7 files changed, 30 insertions(+), 33 deletions(-)
rename clang-tools-extra/clang-tidy/bugprone/{CerrnoCheck.cpp => CustomErrnoDeclarationCheck.cpp} (87%)
rename clang-tools-extra/clang-tidy/bugprone/{CerrnoCheck.h => CustomErrnoDeclarationCheck.h} (66%)
delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/custom-errno-declaration.md
rename clang-tools-extra/test/clang-tidy/checkers/bugprone/{cerrno.cpp => custom-errno-declaration.cpp} (73%)
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 54f0e7345ff97e..e550433ddacd25 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -18,7 +18,7 @@
#include "BranchCloneCheck.h"
#include "CapturingThisInMemberVariableCheck.h"
#include "CastingThroughVoidCheck.h"
-#include "CerrnoCheck.h"
+#include "CustomErrnoDeclarationCheck.h"
#include "ChainedComparisonCheck.h"
#include "CommandProcessorCheck.h"
#include "ComparePointerToMemberVirtualFunctionCheck.h"
@@ -145,8 +145,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-capturing-this-in-member-variable");
CheckFactories.registerCheck<CastingThroughVoidCheck>(
"bugprone-casting-through-void");
- CheckFactories.registerCheck<CerrnoCheck>(
- "bugprone-cerrno");
+ CheckFactories.registerCheck<CustomErrnoDeclarationCheck>(
+ "bugprone-custom-errno-declaration");
CheckFactories.registerCheck<ChainedComparisonCheck>(
"bugprone-chained-comparison");
CheckFactories.registerCheck<CommandProcessorCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 6345e61b3b1266..8cf6e6f86cd369 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -15,7 +15,7 @@ add_clang_library(clangTidyBugproneModule STATIC
BugproneTidyModule.cpp
CapturingThisInMemberVariableCheck.cpp
CastingThroughVoidCheck.cpp
- CerrnoCheck.cpp
+ CustomErrnoDeclarationCheck.cpp
ChainedComparisonCheck.cpp
CommandProcessorCheck.cpp
ComparePointerToMemberVirtualFunctionCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
similarity index 87%
rename from clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp
rename to clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
index 8dbb6856620843..e3b6e8f51bb3bc 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
@@ -6,18 +6,18 @@
//
//===----------------------------------------------------------------------===//
-#include "CerrnoCheck.h"
+#include "CustomErrnoDeclarationCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
-void CerrnoCheck::registerMatchers(MatchFinder *Finder) {
+void CustomErrnoDeclarationCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(varDecl(hasType(asString("int")), hasName("errno"), hasExternalFormalLinkage()).bind("errnoDecl"), this);
}
-void CerrnoCheck::check(const MatchFinder::MatchResult &Result) {
+void CustomErrnoDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("errnoDecl"); // NULL?
const SourceManager &SM = *Result.SourceManager;
const auto Location = MatchedDecl->getLocation();
diff --git a/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h
similarity index 66%
rename from clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h
rename to clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h
index 7517acd28a49f5..a1e16d412db49b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CerrnoCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CERRNOCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CERRNOCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CUSTOMERRNODECLARATIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CUSTOMERRNODECLARATIONCHECK_H
#include "../ClangTidyCheck.h"
@@ -16,10 +16,10 @@ namespace clang::tidy::bugprone {
/// Warns if you declare an extern int variable named 'errno'.
///
/// For the user-facing documentation see:
-/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/cerrno.html
-class CerrnoCheck : public ClangTidyCheck {
+/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/custom-errno-declaration.html
+class CustomErrnoDeclarationCheck : public ClangTidyCheck {
public:
- CerrnoCheck(StringRef Name, ClangTidyContext *Context)
+ CustomErrnoDeclarationCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -32,4 +32,4 @@ class CerrnoCheck : public ClangTidyCheck {
} // namespace clang::tidy::bugprone
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CERRNOCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CUSTOMERRNODECLARATIONCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst
deleted file mode 100644
index 73ec1c76901af4..00000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/cerrno.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-.. title:: clang-tidy - bugprone-cerrno
-
-bugprone-cerrno
-===============
-
-Warns if you declare an ``extern int`` variable named ``errno`` instead of including ``<cerrno>``.
-It is able to fix the problem by removing the line of the declaration and inserting ``#include <cerrno>``
-at the top of the file.
-
-For further reading, see `the page of SEI CERT C Coding Standard
-<https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/rules/miscellaneous-msc/msc38-c/>`_.
-
-Example:
-
-.. code-block:: c++
-
- extern int errno;
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/custom-errno-declaration.md b/clang-tools-extra/docs/clang-tidy/checks/bugprone/custom-errno-declaration.md
new file mode 100644
index 00000000000000..2fd9f51a566885
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/custom-errno-declaration.md
@@ -0,0 +1,14 @@
+# bugprone-custom-errno-declaration
+
+Finds custom declarations of `extern int` variable named `errno`.
+It is able to fix the problem by removing the line of the declaration and inserting `#include <cerrno>`
+at the top of the file.
+
+For further reading, see [the page of SEI CERT C Coding Standard]
+(https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/rules/miscellaneous-msc/msc38-c/).
+
+Example:
+
+```cpp
+extern int errno;
+```
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
similarity index 73%
rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
index 40109d31aa26ba..0d87784e4d2527 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cerrno.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
@@ -1,14 +1,14 @@
-// RUN: %check_clang_tidy %s bugprone-cerrno %t
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t
namespace cerrno_test_0 {
extern int errno;
- // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-cerrno]
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
// CHECK-FIXES: {{^}}{{$}}
} // namespace cerrno_test_0
namespace cerrno_test_1 {
extern "C" int errno;
- // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: errno declaration detected, include cerrno instead [bugprone-cerrno]
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
// CHECK-FIXES: {{^}}{{$}}
} // namespace cerrno_test_1
>From db3e3bb86ae4d3d3dfad48e606e8a3bf5d1deb7a Mon Sep 17 00:00:00 2001
From: Csaba Zeitvogel <qtaq9s at inf.elte.hu>
Date: Thu, 6 Aug 2026 20:30:08 +0200
Subject: [PATCH 3/5] Apply requested changes
Main changes:
- use of IncludeInserter
- add support for C Language
- add new tests
---
.../bugprone/CustomErrnoDeclarationCheck.cpp | 22 +++++++++++--------
.../bugprone/CustomErrnoDeclarationCheck.h | 9 ++++----
.../custom-errno-declaration-double-decl.c | 5 +++++
.../custom-errno-declaration-ignore.c | 13 +++++++++++
.../bugprone/custom-errno-declaration.c | 5 +++++
.../bugprone/custom-errno-declaration.cpp | 18 ++++++++++-----
6 files changed, 53 insertions(+), 19 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-double-decl.c
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-ignore.c
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.c
diff --git a/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
index e3b6e8f51bb3bc..c7493c86cfef8a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
@@ -13,26 +13,30 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
+CustomErrnoDeclarationCheck::CustomErrnoDeclarationCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ Inserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM), areDiagsSelfContained()) {}
+
+void CustomErrnoDeclarationCheck::registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
+ Inserter.registerPreprocessor(PP);
+}
+
void CustomErrnoDeclarationCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(varDecl(hasType(asString("int")), hasName("errno"), hasExternalFormalLinkage()).bind("errnoDecl"), this);
}
void CustomErrnoDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
- const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("errnoDecl"); // NULL?
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("errnoDecl");
const SourceManager &SM = *Result.SourceManager;
const auto Location = MatchedDecl->getLocation();
const auto FileID = SM.getFileID(Location);
unsigned Line = SM.getSpellingLineNumber(MatchedDecl->getBeginLoc());
+ StringRef Header = Result.Context->getLangOpts().CPlusPlus ? "<cerrno>" : "<errno.h>";
- const auto Diag = diag(Location, "errno declaration detected, include cerrno instead")
- << FixItHint::CreateRemoval(CharSourceRange::getCharRange(SM.translateLineCol(FileID, Line, 1), SM.translateLineCol(FileID, Line + 1, 1)));
-
- if (alreadyInserted)
- return;
-
- Diag << FixItHint::CreateInsertion(SM.getLocForStartOfFile(FileID), "#include <cerrno>\n");
- alreadyInserted = true;
+ diag(Location, "errno declaration detected, include cerrno instead")
+ << FixItHint::CreateRemoval(CharSourceRange::getCharRange(SM.translateLineCol(FileID, Line, 1), SM.translateLineCol(FileID, Line + 1, 1)))
+ << Inserter.createIncludeInsertion(FileID, Header);
}
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h
index a1e16d412db49b..74690d22e36021 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CUSTOMERRNODECLARATIONCHECK_H
#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
namespace clang::tidy::bugprone {
@@ -19,15 +20,15 @@ namespace clang::tidy::bugprone {
/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/custom-errno-declaration.html
class CustomErrnoDeclarationCheck : public ClangTidyCheck {
public:
- CustomErrnoDeclarationCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context) {}
+ CustomErrnoDeclarationCheck(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 {
- return LangOpts.CPlusPlus;
+ return !LangOpts.ObjC;
}
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override;
private:
- bool alreadyInserted = false;
+ utils::IncludeInserter Inserter;
};
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-double-decl.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-double-decl.c
new file mode 100644
index 00000000000000..7a75be79ab9565
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-double-decl.c
@@ -0,0 +1,5 @@
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t
+
+extern int errno, preserved;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+// CHECK-FIXES: {{^}}{{$}}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-ignore.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-ignore.c
new file mode 100644
index 00000000000000..f601df6609babd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-ignore.c
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t
+
+// all cases should be ignored in this file
+
+extern int *errno;
+
+void foo(int errno) {}
+
+int fooo()
+{
+ int errno = 0;
+ return errno;
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.c
new file mode 100644
index 00000000000000..c20bded904c4ca
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.c
@@ -0,0 +1,5 @@
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t
+
+extern int errno;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+// CHECK-FIXES: {{^}}{{$}}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
index 0d87784e4d2527..f8325d131ab399 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
@@ -1,18 +1,24 @@
// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t
-namespace cerrno_test_0 {
+namespace errno_test_0 {
extern int errno;
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
// CHECK-FIXES: {{^}}{{$}}
-} // namespace cerrno_test_0
+} // namespace errno_test_0
-namespace cerrno_test_1 {
+namespace errno_test_1 {
extern "C" int errno;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
// CHECK-FIXES: {{^}}{{$}}
-} // namespace cerrno_test_1
+} // namespace errno_test_1
-namespace cerrno_test_2 { // all cases should be ignored in this namespace
+namespace errno_test_2 {
+ extern int errno, preserved;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+ // CHECK-FIXES: {{^}}{{$}}
+} // namespace errno_test_2
+
+namespace errno_test_3 { // all cases should be ignored in this namespace
extern bool errno;
void foo(int errno) {}
@@ -22,4 +28,4 @@ namespace cerrno_test_2 { // all cases should be ignored in this namespace
int errno = 0;
return errno;
}
-} // namespace cerrno_test_2
+} // namespace errno_test_3
>From 905aae6239d9886542b9bd4e245d13bad2ef75f2 Mon Sep 17 00:00:00 2001
From: Csaba Zeitvogel <qtaq9s at inf.elte.hu>
Date: Thu, 27 Aug 2026 11:35:15 +0200
Subject: [PATCH 4/5] Add support for fixed-width integer types
---
.../bugprone/CustomErrnoDeclarationCheck.cpp | 2 +-
.../Inputs/custom-errno-declaration/stdint.h | 15 ++++++++++++++
.../bugprone/custom-errno-declaration-int16.c | 7 +++++++
.../bugprone/custom-errno-declaration-int32.c | 7 +++++++
.../bugprone/custom-errno-declaration.cpp | 20 ++++++++++++++++---
5 files changed, 47 insertions(+), 4 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/custom-errno-declaration/stdint.h
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int16.c
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int32.c
diff --git a/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
index c7493c86cfef8a..5c01ee5fe6e5d1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CustomErrnoDeclarationCheck.cpp
@@ -22,7 +22,7 @@ void CustomErrnoDeclarationCheck::registerPPCallbacks(const SourceManager &SM, P
}
void CustomErrnoDeclarationCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(varDecl(hasType(asString("int")), hasName("errno"), hasExternalFormalLinkage()).bind("errnoDecl"), this);
+ Finder->addMatcher(varDecl(anyOf(hasType(asString("int")), hasType(asString("int32_t")), hasType(asString("int16_t"))), hasName("errno"), hasExternalFormalLinkage()).bind("errnoDecl"), this);
}
void CustomErrnoDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/custom-errno-declaration/stdint.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/custom-errno-declaration/stdint.h
new file mode 100644
index 00000000000000..0c3f44d657b036
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/custom-errno-declaration/stdint.h
@@ -0,0 +1,15 @@
+//===--- stdint.h - Mock header for tests ---------------------------------===//
+//
+// 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_TEST_CLANG_TIDY_CHECKERS_BUGPRONE_INPUTS_CUSTOMERRNODECLARATION_STDINT
+#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_BUGPRONE_INPUTS_CUSTOMERRNODECLARATION_STDINT
+
+typedef int int16_t;
+typedef int int32_t;
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_BUGPRONE_INPUTS_CUSTOMERRNODECLARATION_STDINT
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int16.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int16.c
new file mode 100644
index 00000000000000..efe62f1431f7d9
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int16.c
@@ -0,0 +1,7 @@
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t -- -- -I %S/Inputs/custom-errno-declaration
+
+#include <stdint.h>
+
+extern int16_t errno;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+// CHECK-FIXES: {{^}}{{$}}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int32.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int32.c
new file mode 100644
index 00000000000000..5872d105185414
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration-int32.c
@@ -0,0 +1,7 @@
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t -- -- -I %S/Inputs/custom-errno-declaration
+
+#include <stdint.h>
+
+extern int32_t errno;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+// CHECK-FIXES: {{^}}{{$}}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
index f8325d131ab399..d239d39b3012bc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/custom-errno-declaration.cpp
@@ -1,4 +1,6 @@
-// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t
+// RUN: %check_clang_tidy %s bugprone-custom-errno-declaration %t -- -- -I %S/Inputs/custom-errno-declaration
+
+#include <stdint.h>
namespace errno_test_0 {
extern int errno;
@@ -18,7 +20,19 @@ namespace errno_test_2 {
// CHECK-FIXES: {{^}}{{$}}
} // namespace errno_test_2
-namespace errno_test_3 { // all cases should be ignored in this namespace
+namespace errno_test_3 {
+ extern int32_t errno;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+ // CHECK-FIXES: {{^}}{{$}}
+} // namespace errno_test_3
+
+namespace errno_test_4 {
+ extern int16_t errno;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: errno declaration detected, include cerrno instead [bugprone-custom-errno-declaration]
+ // CHECK-FIXES: {{^}}{{$}}
+} // namespace errno_test_4
+
+namespace errno_test_5 { // all cases should be ignored in this namespace
extern bool errno;
void foo(int errno) {}
@@ -28,4 +42,4 @@ namespace errno_test_3 { // all cases should be ignored in this namespace
int errno = 0;
return errno;
}
-} // namespace errno_test_3
+} // namespace errno_test_5
>From b6dfa1152abdb1de4803dbeb0ce2b6227a14b27c Mon Sep 17 00:00:00 2001
From: Csaba Zeitvogel <qtaq9s at inf.elte.hu>
Date: Tue, 15 Sep 2026 12:57:02 +0200
Subject: [PATCH 5/5] Update check list after rebase
---
clang-tools-extra/docs/clang-tidy/checks/list.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index ea6f13365e2068..7ac942153b2e43 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -92,6 +92,7 @@ readability/*
| {doc}`bugprone-copy-constructor-init <bugprone/copy-constructor-init>` | Yes |
| {doc}`bugprone-copy-constructor-mutates-argument <bugprone/copy-constructor-mutates-argument>` | |
| {doc}`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>` | Yes |
+| {doc}`bugprone-custom-errno-declaration <bugprone/custom-errno-declaration>` | Yes |
| {doc}`bugprone-dangling-handle <bugprone/dangling-handle>` | |
| {doc}`bugprone-default-operator-new-on-overaligned-type <bugprone/default-operator-new-on-overaligned-type>` | |
| {doc}`bugprone-derived-method-shadowing-base-method <bugprone/derived-method-shadowing-base-method>` | |
More information about the cfe-commits
mailing list