[clang-tools-extra] [clang-tidy] Add a fully custom message to `bugprone-unsafe-functions` (PR #162443)
DonĂ¡t Nagy via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 18 06:28:20 PST 2025
https://github.com/NagyDonat updated https://github.com/llvm/llvm-project/pull/162443
>From 147e1a82a3a07f23dee8d1f36185fd477004371d Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 8 Oct 2025 08:48:30 +0000
Subject: [PATCH 1/7] [clang-tidy] Add a fully custom message to
`bugprone-unsafe-functions`
In some cases, such as when recommending the compiler option _FORTIFY_SOURCE, the current custom message format is clunky.
Now, when the reason starts with `>`, the replacement string is omitted., so only the Reason is shown.
---
.../clang-tidy/bugprone/UnsafeFunctionsCheck.cpp | 8 +++++++-
clang-tools-extra/docs/ReleaseNotes.rst | 5 +++++
.../docs/clang-tidy/checks/bugprone/unsafe-functions.rst | 7 ++++++-
.../checkers/bugprone/unsafe-functions-custom.c | 6 +++---
4 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
index 0399af2a673f4..d24b4998b8bd7 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
@@ -304,11 +304,17 @@ void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
StringRef Reason =
Entry.Reason.empty() ? "is marked as unsafe" : Entry.Reason.c_str();
- if (Entry.Replacement.empty()) {
+ // Omit the replacement, when a fully-custom reason is given.
+ if (Reason.consume_front(">")) {
+ diag(SourceExpr->getExprLoc(), "function %0 %1")
+ << FuncDecl << Reason.trim() << SourceExpr->getSourceRange();
+ // Do not recommend a replacement when it is not present.
+ } else if (Entry.Replacement.empty()) {
diag(SourceExpr->getExprLoc(),
"function %0 %1; it should not be used")
<< FuncDecl << Reason << Entry.Replacement
<< SourceExpr->getSourceRange();
+ // Otherwise, emit the replacement.
} else {
diag(SourceExpr->getExprLoc(),
"function %0 %1; '%2' should be used instead")
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a94dd9737468c..a4059bdd711e0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -314,6 +314,11 @@ Changes in existing checks
<clang-tidy/checks/bugprone/unhandled-self-assignment>` check by adding
an additional matcher that generalizes the copy-and-swap idiom pattern
detection.
+
+- Improved :doc:`bugprone-unsafe-functions
+ <clang-tidy/checks/bugprone/unsafe-functions>` check by omitting the custom
+ replacement string, when the Reason starts with the character `>` in the
+ `CustomFunctions` option.
- Improved :doc:`cppcoreguidelines-init-variables
<clang-tidy/checks/cppcoreguidelines/init-variables>` check by fixing the
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
index 317db9c5564e2..af6d59fe5c0b4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
@@ -98,7 +98,9 @@ The `reason` is optional and is used to provide additional information about the
reasoning behind the replacement. The default reason is `is marked as unsafe`.
If `replacement` is empty, the text `it should not be used` will be shown
-instead of the suggestion for a replacement.
+instead of the suggestion for a replacement. If the `reason` starts with the
+character `>`, the replacement message is disabled, to allow better control over
+the suggestions.
As an example, the configuration `^original$, replacement, is deprecated;`
will produce the following diagnostic message.
@@ -114,6 +116,9 @@ qualified name (i.e. ``std::original``), otherwise the regex is matched against
If the regular expression starts with `::` (or `^::`), it is matched against the
fully qualified name (``::std::original``).
+A similar diagnostic message can be printed with the cofiguration
+`^original$,,> is deprecated, 'replacement' should be used instead`.
+
.. note::
Fully qualified names can contain template parameters on certain C++ classes, but not on C++ functions.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c
index 7fd71ec2f2e7b..7eaf015f06aa2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy -check-suffix=NON-STRICT-REGEX %s bugprone-unsafe-functions %t --\
-// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '::name_match,replacement,is a qualname match;^::prefix_match,,is matched on qualname prefix'}}"
+// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: \"::name_match,,>is a qualname match, but with a fully 'custom' message;^::prefix_match,,is matched on qualname prefix\"}}"
// RUN: %check_clang_tidy -check-suffix=STRICT-REGEX %s bugprone-unsafe-functions %t --\
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '^name_match$,replacement,is matched on function name only;^::prefix_match$,,is a full qualname match'}}"
@@ -11,14 +11,14 @@ void prefix_match_regex();
void f1() {
name_match();
- // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match' is a qualname match; 'replacement' should be used instead
+ // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match' is a qualname match, but with a fully 'custom' message
// CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'name_match' is matched on function name only; 'replacement' should be used instead
prefix_match();
// CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match' is matched on qualname prefix; it should not be used
// CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'prefix_match' is a full qualname match; it should not be used
name_match_regex();
- // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match_regex' is a qualname match; 'replacement' should be used instead
+ // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match_regex' is a qualname match, but with a fully 'custom' message
// no-warning STRICT-REGEX
prefix_match_regex();
>From e3f16b5f3a605a388e254085fc232b598e8689cc Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Thu, 16 Oct 2025 08:54:12 +0000
Subject: [PATCH 2/7] Fix typo in release notes
---
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a4059bdd711e0..cbd0340fafdec 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -317,7 +317,7 @@ Changes in existing checks
- Improved :doc:`bugprone-unsafe-functions
<clang-tidy/checks/bugprone/unsafe-functions>` check by omitting the custom
- replacement string, when the Reason starts with the character `>` in the
+ replacement string, when the reason starts with the character `>` in the
`CustomFunctions` option.
- Improved :doc:`cppcoreguidelines-init-variables
>From 28c034981877efdec251109530f8bfdf3802956c Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Thu, 30 Oct 2025 13:29:13 +0000
Subject: [PATCH 3/7] Rework docs and add potentially breaking change
---
clang-tools-extra/docs/ReleaseNotes.rst | 11 +++-
.../checks/bugprone/unsafe-functions.rst | 59 +++++++++++++------
2 files changed, 49 insertions(+), 21 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index cbd0340fafdec..86be462775417 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -69,6 +69,11 @@ Potentially Breaking Changes
- `CharTypdefsToIgnore` to `CharTypedefsToIgnore` in
:doc:`bugprone-signed-char-misuse
<clang-tidy/checks/bugprone/signed-char-misuse>`
+
+- Modified the custom message format of :doc:`bugprone-unsafe-functions
+ <clang-tidy/checks/bugprone/unsafe-functions>` by hiding the default suffix
+ when the reason starts with the character `>` in the `CustomFunctions` option.
+ The warning locations are not changed, but the message is different.
Improvements to clangd
----------------------
@@ -316,9 +321,9 @@ Changes in existing checks
detection.
- Improved :doc:`bugprone-unsafe-functions
- <clang-tidy/checks/bugprone/unsafe-functions>` check by omitting the custom
- replacement string, when the reason starts with the character `>` in the
- `CustomFunctions` option.
+ <clang-tidy/checks/bugprone/unsafe-functions>` check by hiding the default
+ suffix when the reason starts with the character `>` in the `CustomFunctions`
+ option.
- Improved :doc:`cppcoreguidelines-init-variables
<clang-tidy/checks/cppcoreguidelines/init-variables>` check by fixing the
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
index af6d59fe5c0b4..cdaed56442813 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
@@ -80,8 +80,8 @@ including any system headers.
Custom functions
----------------
-The option :option:`CustomFunctions` allows the user to define custom functions to be
-checked. The format is the following, without newlines:
+The option :option:`CustomFunctions` allows the user to define custom functions
+to be checked. The format is the following, without newlines:
.. code::
@@ -97,38 +97,61 @@ The functions are matched using POSIX extended regular expressions.
The `reason` is optional and is used to provide additional information about the
reasoning behind the replacement. The default reason is `is marked as unsafe`.
-If `replacement` is empty, the text `it should not be used` will be shown
-instead of the suggestion for a replacement. If the `reason` starts with the
-character `>`, the replacement message is disabled, to allow better control over
-the suggestions.
+If `replacement` is empty, the default text `it should not be used` will be
+shown instead of the suggestion for a replacement.
-As an example, the configuration `^original$, replacement, is deprecated;`
-will produce the following diagnostic message.
+If the `reason` starts with the character `>`, the reason becomes fully custom.
+The default suffix is disabled even if a `replacement` is present, and only the
+reason message is shown after the matched function, to allow better control over
+the suggestions. The starting `>` character and the preceding spaces are trimmed
+from the message.
+
+As an example, the following configuration matches only the function `original`
+in the default namespace. A similar diagnostic can also be printed using a fully
+custom reason.
.. code:: c
+
+ // bugprone-unsafe-functions.CustomFunctions:
+ // ^original$, replacement, is deprecated;
+ // Using the fully custom message syntax:
+ // ^original$,,> is deprecated, 'replacement' should be used instead;
- original(); // warning: function 'original' is deprecated; 'replacement' should be used instead.
+ original(); // warning: function 'original' is deprecated; 'replacement' should be used instead
::std::original(); // no-warning
original_function(); // no-warning
If the regular expression contains the character `:`, it is matched against the
-qualified name (i.e. ``std::original``), otherwise the regex is matched against the unqualified name (``original``).
-If the regular expression starts with `::` (or `^::`), it is matched against the
-fully qualified name (``::std::original``).
+qualified name (i.e. ``std::original``), otherwise the regex is matched against
+the unqualified name (``original``). If the regular expression starts with `::`
+(or `^::`), it is matched against the fully qualified name
+(``::std::original``).
+
+One of the use cases for fully custom messages is suggesting compiler options
+and warning flags:
+
+.. code:: c
+
+ // bugprone-unsafe-functions.CustomFunctions:
+ // ^memcpy$,,>is recommended to have compiler hardening using '_FORTIFY_SOURCE';
+ // ^printf$,,>is recommended to have the '-Werror=format-security' compiler warning flag;
+
+ memcpy(dest, src, 999'999); // warning: function 'memcpy' is recommended to have compiler hardening using '_FORTIFY_SOURCE'
+ printf(raw_str); // warning: function 'printf' is recommended to have the '-Werror=format-security' compiler warning flag
-A similar diagnostic message can be printed with the cofiguration
-`^original$,,> is deprecated, 'replacement' should be used instead`.
+The
.. note::
- Fully qualified names can contain template parameters on certain C++ classes, but not on C++ functions.
- Type aliases are resolved before matching.
+ Fully qualified names can contain template parameters on certain C++ classes,
+ but not on C++ functions. Type aliases are resolved before matching.
As an example, the member function ``open`` in the class ``std::ifstream``
has a fully qualified name of ``::std::basic_ifstream<char>::open``.
- The example could also be matched with the regex ``::std::basic_ifstream<[^>]*>::open``, which matches all potential
- template parameters, but does not match nested template classes.
+ The example could also be matched with the regex
+ ``::std::basic_ifstream<[^>]*>::open``, which matches all potential template
+ parameters, but does not match nested template classes.
Options
-------
>From cc018985b95bb75886edab897c106092a7a94de1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.nagy at ericsson.com>
Date: Tue, 18 Nov 2025 14:50:15 +0100
Subject: [PATCH 4/7] Tweak the entry in the release notes
---
clang-tools-extra/docs/ReleaseNotes.rst | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 86be462775417..371722825effa 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -71,9 +71,11 @@ Potentially Breaking Changes
<clang-tidy/checks/bugprone/signed-char-misuse>`
- Modified the custom message format of :doc:`bugprone-unsafe-functions
- <clang-tidy/checks/bugprone/unsafe-functions>` by hiding the default suffix
- when the reason starts with the character `>` in the `CustomFunctions` option.
- The warning locations are not changed, but the message is different.
+ <clang-tidy/checks/bugprone/unsafe-functions>` by assigning a special meaning
+ to the character ``>`` at the start of the value of the option
+ ``CustomFunctions``. If the option value starts with ``>``, then the
+ replacement suggestion part of the message (which would be included by
+ default) is omitted. (This does not change the warning locations.)
Improvements to clangd
----------------------
>From a2d6810098d8646278f90dbc55899e935af0a19b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.nagy at ericsson.com>
Date: Tue, 18 Nov 2025 14:51:01 +0100
Subject: [PATCH 5/7] Fix formatting of code fragments, tweak a sentence
---
.../checks/bugprone/unsafe-functions.rst | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
index cdaed56442813..c931229c6afb7 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
@@ -94,19 +94,19 @@ to be checked. The format is the following, without newlines:
The functions are matched using POSIX extended regular expressions.
*(Note: The regular expressions do not support negative* ``(?!)`` *matches.)*
-The `reason` is optional and is used to provide additional information about the
-reasoning behind the replacement. The default reason is `is marked as unsafe`.
+The ``reason`` is optional and is used to provide additional information about the
+reasoning behind the replacement. The default reason is ``is marked as unsafe``.
-If `replacement` is empty, the default text `it should not be used` will be
+If ``replacement`` is empty, the default text ``it should not be used`` will be
shown instead of the suggestion for a replacement.
-If the `reason` starts with the character `>`, the reason becomes fully custom.
-The default suffix is disabled even if a `replacement` is present, and only the
+If the ``reason`` starts with the character ``>``, the reason becomes fully custom.
+The default suffix is disabled even if a ``replacement`` is present, and only the
reason message is shown after the matched function, to allow better control over
-the suggestions. The starting `>` character and the preceding spaces are trimmed
-from the message.
+the suggestions. (The starting ``>`` and whitespace directly after it are
+trimmed from the message.)
-As an example, the following configuration matches only the function `original`
+As an example, the following configuration matches only the function ``original``
in the default namespace. A similar diagnostic can also be printed using a fully
custom reason.
@@ -121,10 +121,10 @@ custom reason.
::std::original(); // no-warning
original_function(); // no-warning
-If the regular expression contains the character `:`, it is matched against the
+If the regular expression contains the character ``:``, it is matched against the
qualified name (i.e. ``std::original``), otherwise the regex is matched against
-the unqualified name (``original``). If the regular expression starts with `::`
-(or `^::`), it is matched against the fully qualified name
+the unqualified name (``original``). If the regular expression starts with ``::``
+(or ``^::``), it is matched against the fully qualified name
(``::std::original``).
One of the use cases for fully custom messages is suggesting compiler options
>From 3e7ee176656f3d2e9c4dba50055a95fcdbee3d24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.nagy at ericsson.com>
Date: Tue, 18 Nov 2025 15:15:07 +0100
Subject: [PATCH 6/7] Remove dangling 'The' from the documentation
---
.../docs/clang-tidy/checks/bugprone/unsafe-functions.rst | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
index 35b451fc749ba..cb7ea415c54b2 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst
@@ -141,8 +141,6 @@ and warning flags:
memcpy(dest, src, 999'999); // warning: function 'memcpy' is recommended to have compiler hardening using '_FORTIFY_SOURCE'
printf(raw_str); // warning: function 'printf' is recommended to have the '-Werror=format-security' compiler warning flag
-The
-
.. note::
Fully qualified names can contain template parameters on certain C++ classes,
>From b71ef18fb5455a6c63a5b951f412f7d88c20a132 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.nagy at ericsson.com>
Date: Tue, 18 Nov 2025 15:27:59 +0100
Subject: [PATCH 7/7] Allow Reason.consume_front()
---
clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
index c1a8c08654cf2..67d0931003c54 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
@@ -301,7 +301,7 @@ void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
if (Custom) {
for (const auto &Entry : CustomFunctions) {
if (Entry.Pattern.match(*FuncDecl)) {
- const StringRef Reason =
+ StringRef Reason =
Entry.Reason.empty() ? "is marked as unsafe" : Entry.Reason.c_str();
// Omit the replacement, when a fully-custom reason is given.
More information about the cfe-commits
mailing list