[clang-tools-extra] [clang-tidy] Add misc-shadowed-namespace-function check (PR #168406)
Denis Mikhailov via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 17 09:21:48 PST 2025
https://github.com/denzor200 created https://github.com/llvm/llvm-project/pull/168406
Implementation of this check was mostly generated by DeepSeek.
I've tested it on llvm codebase with `-DLLVM_ENABLE_PROJECTS="bolt;clang;clang-tools-extra;compiler-rt;cross-project-tests;libc;libclc;lld;lldb;mlir;openmp;polly"`
It provided 6 warnings with fixit hints.
See [11.log](https://github.com/user-attachments/files/23588696/11.log) based on trunk https://github.com/llvm/llvm-project/commit/070f3310ccfd040271aae982f36c008f2c34e11d
Closes https://github.com/llvm/llvm-project/issues/6739
>From b7d665bf49d20faf9bb22f782503391dcc361cab Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 16 Nov 2025 23:56:06 +0300
Subject: [PATCH 01/16] Implementation template from DeepSeek
---
.../clang-tidy/misc/CMakeLists.txt | 1 +
.../clang-tidy/misc/MiscTidyModule.cpp | 3 +
.../misc/ShadowedNamespaceFunctionCheck.cpp | 131 ++++++++++++++++++
.../misc/ShadowedNamespaceFunctionCheck.h | 39 ++++++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
.../docs/clang-tidy/checks/list.rst | 2 +
.../misc/shadowed-namespace-function.rst | 6 +
.../misc/shadowed-namespace-function.cpp | 13 ++
8 files changed, 200 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index 6214ee92927f2..d18af237283ff 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -34,6 +34,7 @@ add_clang_library(clangTidyMiscModule STATIC
NonPrivateMemberVariablesInClassesCheck.cpp
OverrideWithDifferentVisibilityCheck.cpp
RedundantExpressionCheck.cpp
+ ShadowedNamespaceFunctionCheck.cpp
StaticAssertCheck.cpp
ThrowByValueCatchByReferenceCheck.cpp
UnconventionalAssignOperatorCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 347fa2a82e43c..2706fe647fe14 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -24,6 +24,7 @@
#include "NonPrivateMemberVariablesInClassesCheck.h"
#include "OverrideWithDifferentVisibilityCheck.h"
#include "RedundantExpressionCheck.h"
+#include "ShadowedNamespaceFunctionCheck.h"
#include "StaticAssertCheck.h"
#include "ThrowByValueCatchByReferenceCheck.h"
#include "UnconventionalAssignOperatorCheck.h"
@@ -65,6 +66,8 @@ class MiscModule : public ClangTidyModule {
"misc-non-private-member-variables-in-classes");
CheckFactories.registerCheck<RedundantExpressionCheck>(
"misc-redundant-expression");
+ CheckFactories.registerCheck<ShadowedNamespaceFunctionCheck>(
+ "misc-shadowed-namespace-function");
CheckFactories.registerCheck<StaticAssertCheck>("misc-static-assert");
CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
"misc-throw-by-value-catch-by-reference");
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
new file mode 100644
index 0000000000000..d9fcfccfb85fb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -0,0 +1,131 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ShadowedNamespaceFunctionCheck.h"
+#include "../utils/FixItHintUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::tidy;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void ShadowedNamespaceFunctionCheck::registerMatchers(MatchFinder *Finder) {
+ // Simple matcher for all function definitions
+ Finder->addMatcher(
+ functionDecl(
+ isDefinition()
+ ).bind("func"),
+ this
+ );
+}
+
+void ShadowedNamespaceFunctionCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+
+ if (!Func || !Result.SourceManager)
+ return;
+
+ // Skip if not in global namespace
+ const DeclContext *DC = Func->getDeclContext();
+ if (!DC->isTranslationUnit())
+ return;
+
+ // Skip templates, static functions, main, etc.
+ if (Func->isTemplated() || Func->isStatic() ||
+ Func->getName() == "main" || Func->isImplicit())
+ return;
+
+ std::string FuncName = Func->getNameAsString();
+ if (FuncName.empty())
+ return;
+
+ ASTContext *Context = Result.Context;
+
+ // Look for functions with the same name in namespaces
+ const FunctionDecl *ShadowedFunc = nullptr;
+ const NamespaceDecl *ShadowedNamespace = nullptr;
+
+ // Traverse all declarations in the translation unit
+ for (const auto *Decl : Context->getTranslationUnitDecl()->decls()) {
+ if (const auto *NS = dyn_cast<NamespaceDecl>(Decl)) {
+ findShadowedInNamespace(NS, Func, FuncName, ShadowedFunc, ShadowedNamespace);
+ if (ShadowedFunc) break;
+ }
+ }
+
+ if (!ShadowedFunc || !ShadowedNamespace)
+ return;
+
+ // Generate warning message
+ std::string NamespaceName = ShadowedNamespace->getNameAsString();
+ auto Diag = diag(Func->getLocation(),
+ "free function %0 shadows %1::%2")
+ << Func->getDeclName()
+ << NamespaceName
+ << ShadowedFunc->getDeclName();
+
+ // Generate fixit hint to add namespace qualification
+ SourceLocation NameLoc = Func->getLocation();
+ if (NameLoc.isValid()) {
+ std::string Fix = NamespaceName + "::";
+ Diag << FixItHint::CreateInsertion(NameLoc, Fix);
+ }
+
+ // Note: Also show where the shadowed function is declared
+ diag(ShadowedFunc->getLocation(),
+ "function %0 declared here", DiagnosticIDs::Note)
+ << ShadowedFunc->getDeclName();
+}
+
+void ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
+ const NamespaceDecl *NS,
+ const FunctionDecl *GlobalFunc,
+ const std::string &GlobalFuncName,
+ const FunctionDecl *&ShadowedFunc,
+ const NamespaceDecl *&ShadowedNamespace) {
+
+ // Skip anonymous namespaces
+ if (NS->isAnonymousNamespace())
+ return;
+
+ for (const auto *Decl : NS->decls()) {
+ // Check nested namespaces
+ if (const auto *NestedNS = dyn_cast<NamespaceDecl>(Decl)) {
+ findShadowedInNamespace(NestedNS, GlobalFunc, GlobalFuncName,
+ ShadowedFunc, ShadowedNamespace);
+ if (ShadowedFunc) return;
+ }
+
+ // Check functions
+ if (const auto *Func = dyn_cast<FunctionDecl>(Decl)) {
+ // Skip if it's the same function, templates, or definitions
+ if (Func == GlobalFunc || Func->isTemplated() ||
+ Func->isThisDeclarationADefinition())
+ continue;
+
+ if (Func->getNameAsString() == GlobalFuncName) {
+ ShadowedFunc = Func;
+ ShadowedNamespace = NS;
+ return;
+ }
+ }
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
new file mode 100644
index 0000000000000..e3383f6f06332
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::misc {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/misc/shadowed-namespace-function.html
+class ShadowedNamespaceFunctionCheck : public ClangTidyCheck {
+public:
+ ShadowedNamespaceFunctionCheck(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:
+ void findShadowedInNamespace(const NamespaceDecl *NS,
+ const FunctionDecl *GlobalFunc,
+ const std::string &GlobalFuncName,
+ const FunctionDecl *&ShadowedFunc,
+ const NamespaceDecl *&ShadowedNamespace);
+};
+
+} // namespace clang::tidy::misc
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 666865cfb2fcd..33a6919c2f9c8 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -226,6 +226,11 @@ New checks
Finds virtual function overrides with different visibility than the function
in the base class.
+- New :doc:`misc-shadowed-namespace-function
+ <clang-tidy/checks/misc/shadowed-namespace-function>` check.
+
+ FIXME: Write a short description.
+
- New :doc:`readability-redundant-parentheses
<clang-tidy/checks/readability/redundant-parentheses>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index e2875604af72b..4e8b752968e38 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -277,6 +277,8 @@ Clang-Tidy Checks
:doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
:doc:`misc-override-with-different-visibility <misc/override-with-different-visibility>`,
:doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
+ :doc:`misc-shadowed-namespace-function <misc/shadowed-namespace-function>`, "Yes"
+ :doc:`misc-shadowed-namespace-function <misc/shadowed-namespace-function>`, "Yes"
:doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
:doc:`misc-unconventional-assign-operator <misc/unconventional-assign-operator>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
new file mode 100644
index 0000000000000..46367e56563cc
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - misc-shadowed-namespace-function
+
+misc-shadowed-namespace-function
+================================
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp
new file mode 100644
index 0000000000000..9f7af24cb4240
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+void f1();
+namespace foo {
+ void f0();
+ void f1();
+}
+void f0() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f0' shadows foo::f0 [misc-shadowed-namespace-function]
+// CHECK-FIXES: void foo::f0() {}
+void f1() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f1' shadows foo::f1 [misc-shadowed-namespace-function]
+// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes
>From e9de03d1438e7bfd59a6b89c7695421ea74c9583 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 16 Nov 2025 23:56:19 +0300
Subject: [PATCH 02/16] fix unit-test
---
.../clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp | 6 +++---
.../checkers/misc/shadowed-namespace-function.cpp | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index d9fcfccfb85fb..b006c5ef44763 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -72,14 +72,14 @@ void ShadowedNamespaceFunctionCheck::check(
// Generate warning message
std::string NamespaceName = ShadowedNamespace->getNameAsString();
auto Diag = diag(Func->getLocation(),
- "free function %0 shadows %1::%2")
+ "free function %0 shadows '%1::%2'")
<< Func->getDeclName()
<< NamespaceName
- << ShadowedFunc->getDeclName();
+ << ShadowedFunc->getDeclName().getAsString();
// Generate fixit hint to add namespace qualification
SourceLocation NameLoc = Func->getLocation();
- if (NameLoc.isValid()) {
+ if (NameLoc.isValid() && !Func->getPreviousDecl()) {
std::string Fix = NamespaceName + "::";
Diag << FixItHint::CreateInsertion(NameLoc, Fix);
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp
index 9f7af24cb4240..920556cca0381 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function.cpp
@@ -6,8 +6,8 @@ namespace foo {
void f1();
}
void f0() {}
-// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f0' shadows foo::f0 [misc-shadowed-namespace-function]
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f0' shadows 'foo::f0' [misc-shadowed-namespace-function]
// CHECK-FIXES: void foo::f0() {}
void f1() {}
-// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f1' shadows foo::f1 [misc-shadowed-namespace-function]
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f1' shadows 'foo::f1' [misc-shadowed-namespace-function]
// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes
>From 199ecec95322a37b95d8138bdd3df296241a34e4 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 00:03:28 +0300
Subject: [PATCH 03/16] Docs written by DeepSeek
---
.../misc/shadowed-namespace-function.rst | 42 ++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
index 46367e56563cc..b31455cfa0c31 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
@@ -3,4 +3,44 @@
misc-shadowed-namespace-function
================================
-FIXME: Describe what patterns does the check detect and why. Give examples.
+Detects free functions in the global namespace that shadow functions declared
+in other namespaces. This check helps prevent accidental shadowing of namespace
+functions, which can lead to confusion about which function is being called and
+potential linking errors.
+
+Examples
+--------
+
+.. code-block:: c++
+
+ namespace utils {
+ void process();
+ void calculate();
+ }
+
+ // Warning: free function shadows utils::process
+ void process() {}
+
+ // No warning - static function
+ static void calculate() {}
+
+The check will suggest adding the appropriate namespace qualification:
+
+.. code-block:: diff
+
+ - void process() {}
+ + void utils::process() {}
+
+Options
+-------
+
+None
+
+Limitations
+-----------
+
+- Does not warn about functions in anonymous namespaces
+- Does not warn about template functions
+- Does not warn about static functions or member functions
+- Does not warn about the ``main`` function
+- Only considers functions declared before the global definition
>From 8018941598da61c57338f80407b8fa39ded3a923 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 00:11:33 +0300
Subject: [PATCH 04/16] short description by DeepSeek
---
.../clang-tidy/misc/ShadowedNamespaceFunctionCheck.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
index e3383f6f06332..61f4cf8ed1c49 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
@@ -13,7 +13,7 @@
namespace clang::tidy::misc {
-/// FIXME: Write a short description.
+/// Detects free functions in global namespace that shadow functions from other namespaces.
///
/// For the user-facing documentation see:
/// https://clang.llvm.org/extra/clang-tidy/checks/misc/shadowed-namespace-function.html
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 33a6919c2f9c8..a1482d89b6042 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -229,7 +229,7 @@ New checks
- New :doc:`misc-shadowed-namespace-function
<clang-tidy/checks/misc/shadowed-namespace-function>` check.
- FIXME: Write a short description.
+ Detects free functions in global namespace that shadow functions from other namespaces.
- New :doc:`readability-redundant-parentheses
<clang-tidy/checks/readability/redundant-parentheses>` check.
>From 320f6c765fe6288d2956d4b4498edf2d2d76b93f Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 00:12:49 +0300
Subject: [PATCH 05/16] fix list.rst
---
clang-tools-extra/docs/clang-tidy/checks/list.rst | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 4e8b752968e38..473d82033758f 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -278,7 +278,6 @@ Clang-Tidy Checks
:doc:`misc-override-with-different-visibility <misc/override-with-different-visibility>`,
:doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
:doc:`misc-shadowed-namespace-function <misc/shadowed-namespace-function>`, "Yes"
- :doc:`misc-shadowed-namespace-function <misc/shadowed-namespace-function>`, "Yes"
:doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
:doc:`misc-unconventional-assign-operator <misc/unconventional-assign-operator>`,
>From 5994fc0d21f12fd6bdb629409329599eb2974165 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 00:45:46 +0300
Subject: [PATCH 06/16] more tests && fix the doc
---
.../misc/ShadowedNamespaceFunctionCheck.cpp | 2 +-
.../checks/misc/shadowed-namespace-function.rst | 1 -
...owed-namespace-function-anonymous-namespace.cpp | 11 +++++++++++
.../misc/shadowed-namespace-function-nested.cpp | 13 +++++++++++++
.../misc/shadowed-namespace-function-static.cpp | 9 +++++++++
.../misc/shadowed-namespace-function-template.cpp | 14 ++++++++++++++
6 files changed, 48 insertions(+), 2 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-anonymous-namespace.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-nested.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-static.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index b006c5ef44763..b0324ab79aab5 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -70,7 +70,7 @@ void ShadowedNamespaceFunctionCheck::check(
return;
// Generate warning message
- std::string NamespaceName = ShadowedNamespace->getNameAsString();
+ std::string NamespaceName = ShadowedNamespace->getQualifiedNameAsString();
auto Diag = diag(Func->getLocation(),
"free function %0 shadows '%1::%2'")
<< Func->getDeclName()
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
index b31455cfa0c31..b82317fd0a748 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
@@ -43,4 +43,3 @@ Limitations
- Does not warn about template functions
- Does not warn about static functions or member functions
- Does not warn about the ``main`` function
-- Only considers functions declared before the global definition
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-anonymous-namespace.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-anonymous-namespace.cpp
new file mode 100644
index 0000000000000..1689843464ae1
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-anonymous-namespace.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+namespace { void f1(); }
+namespace foo {
+ void f0();
+ void f1();
+}
+namespace {
+void f0() {}
+void f1() {}
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-nested.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-nested.cpp
new file mode 100644
index 0000000000000..41b130624bbaa
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-nested.cpp
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+void f1();
+namespace foo::foo2::foo3 {
+ void f0();
+ void f1();
+}
+void f0() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f0' shadows 'foo::foo2::foo3::f0' [misc-shadowed-namespace-function]
+// CHECK-FIXES: void foo::foo2::foo3::f0() {}
+void f1() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f1' shadows 'foo::foo2::foo3::f1' [misc-shadowed-namespace-function]
+// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-static.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-static.cpp
new file mode 100644
index 0000000000000..d1371c044d112
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-static.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+static void f1();
+namespace foo {
+ void f0();
+ void f1();
+}
+static void f0() {}
+static void f1() {}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp
new file mode 100644
index 0000000000000..48924fcdb932d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp
@@ -0,0 +1,14 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+template<typename T>
+void f1();
+namespace foo {
+ template<typename T>
+ void f0();
+ template<typename T>
+ void f1();
+}
+template<typename T>
+void f0() {}
+template<typename T>
+void f1() {}
>From 4112759aea418b33204f8f19f571657c1f53ffdf Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 00:53:00 +0300
Subject: [PATCH 07/16] fix invalid fixit for correctly defined function
---
.../misc/ShadowedNamespaceFunctionCheck.cpp | 3 +++
.../misc/shadowed-namespace-function-good.cpp | 9 +++++++++
.../misc/shadowed-namespace-function-good2.cpp | 11 +++++++++++
3 files changed, 23 insertions(+)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good2.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index b0324ab79aab5..ca095771c477a 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -69,6 +69,9 @@ void ShadowedNamespaceFunctionCheck::check(
if (!ShadowedFunc || !ShadowedNamespace)
return;
+ if (ShadowedFunc->getDefinition())
+ return;
+
// Generate warning message
std::string NamespaceName = ShadowedNamespace->getQualifiedNameAsString();
auto Diag = diag(Func->getLocation(),
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good.cpp
new file mode 100644
index 0000000000000..17abae5e943b6
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+void f1();
+namespace foo {
+ void f0() {}
+ void f1() {}
+}
+void f0() {}
+void f1() {}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good2.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good2.cpp
new file mode 100644
index 0000000000000..b3218afa60e9d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good2.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+void f1();
+namespace foo {
+ void f0();
+ void f1();
+}
+void foo::f0() {}
+void foo::f1() {}
+void f0() {}
+void f1() {}
>From 89029b766d465aeda8bcdc21a6b092bf73239630 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 00:57:41 +0300
Subject: [PATCH 08/16] more unit-test
---
.../checkers/misc/shadowed-namespace-function-main.cpp | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-main.cpp
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-main.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-main.cpp
new file mode 100644
index 0000000000000..4321486ba7101
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-main.cpp
@@ -0,0 +1,6 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+namespace foo {
+ int main();
+}
+int main() {}
>From 34dc72a0bd3a34bed5b55703f189550599b4ac0d Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 01:48:47 +0300
Subject: [PATCH 09/16] refactoring
---
.../misc/ShadowedNamespaceFunctionCheck.cpp | 33 +++++++++----------
.../misc/ShadowedNamespaceFunctionCheck.h | 10 +++---
2 files changed, 20 insertions(+), 23 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index ca095771c477a..669d6793e23cd 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -45,14 +45,14 @@ void ShadowedNamespaceFunctionCheck::check(
// Skip templates, static functions, main, etc.
if (Func->isTemplated() || Func->isStatic() ||
- Func->getName() == "main" || Func->isImplicit())
+ Func->isMain() || Func->isImplicit())
return;
- std::string FuncName = Func->getNameAsString();
+ const std::string FuncName = Func->getNameAsString();
if (FuncName.empty())
return;
- ASTContext *Context = Result.Context;
+ const ASTContext *Context = Result.Context;
// Look for functions with the same name in namespaces
const FunctionDecl *ShadowedFunc = nullptr;
@@ -61,7 +61,7 @@ void ShadowedNamespaceFunctionCheck::check(
// Traverse all declarations in the translation unit
for (const auto *Decl : Context->getTranslationUnitDecl()->decls()) {
if (const auto *NS = dyn_cast<NamespaceDecl>(Decl)) {
- findShadowedInNamespace(NS, Func, FuncName, ShadowedFunc, ShadowedNamespace);
+ std::tie(ShadowedFunc, ShadowedNamespace) = findShadowedInNamespace(NS, Func, FuncName);
if (ShadowedFunc) break;
}
}
@@ -73,7 +73,7 @@ void ShadowedNamespaceFunctionCheck::check(
return;
// Generate warning message
- std::string NamespaceName = ShadowedNamespace->getQualifiedNameAsString();
+ const std::string NamespaceName = ShadowedNamespace->getQualifiedNameAsString();
auto Diag = diag(Func->getLocation(),
"free function %0 shadows '%1::%2'")
<< Func->getDeclName()
@@ -81,9 +81,9 @@ void ShadowedNamespaceFunctionCheck::check(
<< ShadowedFunc->getDeclName().getAsString();
// Generate fixit hint to add namespace qualification
- SourceLocation NameLoc = Func->getLocation();
+ const SourceLocation NameLoc = Func->getLocation();
if (NameLoc.isValid() && !Func->getPreviousDecl()) {
- std::string Fix = NamespaceName + "::";
+ const std::string Fix = NamespaceName + "::";
Diag << FixItHint::CreateInsertion(NameLoc, Fix);
}
@@ -93,23 +93,21 @@ void ShadowedNamespaceFunctionCheck::check(
<< ShadowedFunc->getDeclName();
}
-void ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
+std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
const NamespaceDecl *NS,
const FunctionDecl *GlobalFunc,
- const std::string &GlobalFuncName,
- const FunctionDecl *&ShadowedFunc,
- const NamespaceDecl *&ShadowedNamespace) {
+ const std::string &GlobalFuncName) {
// Skip anonymous namespaces
if (NS->isAnonymousNamespace())
- return;
+ return {nullptr, nullptr};
for (const auto *Decl : NS->decls()) {
// Check nested namespaces
if (const auto *NestedNS = dyn_cast<NamespaceDecl>(Decl)) {
- findShadowedInNamespace(NestedNS, GlobalFunc, GlobalFuncName,
- ShadowedFunc, ShadowedNamespace);
- if (ShadowedFunc) return;
+ auto [ShadowedFunc, ShadowedNamespace] = findShadowedInNamespace(NestedNS, GlobalFunc, GlobalFuncName);
+ if (ShadowedFunc)
+ return {ShadowedFunc, ShadowedNamespace};
}
// Check functions
@@ -120,12 +118,11 @@ void ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
continue;
if (Func->getNameAsString() == GlobalFuncName) {
- ShadowedFunc = Func;
- ShadowedNamespace = NS;
- return;
+ return {Func, NS};
}
}
}
+ return {nullptr, nullptr};
}
} // namespace misc
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
index 61f4cf8ed1c49..594ab73dc18ab 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H
#include "../ClangTidyCheck.h"
+#include <tuple>
namespace clang::tidy::misc {
@@ -27,11 +28,10 @@ class ShadowedNamespaceFunctionCheck : public ClangTidyCheck {
return LangOpts.CPlusPlus;
}
private:
- void findShadowedInNamespace(const NamespaceDecl *NS,
- const FunctionDecl *GlobalFunc,
- const std::string &GlobalFuncName,
- const FunctionDecl *&ShadowedFunc,
- const NamespaceDecl *&ShadowedNamespace);
+ std::pair<const FunctionDecl *, const NamespaceDecl *>
+ findShadowedInNamespace(const NamespaceDecl *NS,
+ const FunctionDecl *GlobalFunc,
+ const std::string &GlobalFuncName);
};
} // namespace clang::tidy::misc
>From a2490841477c7c494801617c41818e4c800b1439 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 03:07:56 +0300
Subject: [PATCH 10/16] Fix FP
---
.../misc/ShadowedNamespaceFunctionCheck.cpp | 17 +++++++++++++++--
.../checks/misc/shadowed-namespace-function.rst | 1 +
.../misc/shadowed-namespace-function-good3.cpp | 9 +++++++++
.../misc/shadowed-namespace-function-good4.cpp | 9 +++++++++
.../misc/shadowed-namespace-function-using.cpp | 17 +++++++++++++++++
.../shadowed-namespace-function-variadic.cpp | 9 +++++++++
6 files changed, 60 insertions(+), 2 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good3.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good4.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-using.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index 669d6793e23cd..9633bf6c3353f 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -12,6 +12,7 @@
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace clang::ast_matchers;
@@ -21,6 +22,18 @@ namespace clang {
namespace tidy {
namespace misc {
+static bool hasSameParameters(const FunctionDecl *Func1, const FunctionDecl *Func2) {
+ if (Func1->param_size() != Func2->param_size())
+ return false;
+
+ return llvm::all_of_zip(
+ Func1->parameters(), Func2->parameters(),
+ [](const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
+ return Param1->getType().getCanonicalType() ==
+ Param2->getType().getCanonicalType();
+ });
+}
+
void ShadowedNamespaceFunctionCheck::registerMatchers(MatchFinder *Finder) {
// Simple matcher for all function definitions
Finder->addMatcher(
@@ -45,7 +58,7 @@ void ShadowedNamespaceFunctionCheck::check(
// Skip templates, static functions, main, etc.
if (Func->isTemplated() || Func->isStatic() ||
- Func->isMain() || Func->isImplicit())
+ Func->isMain() || Func->isImplicit() || Func->isVariadic())
return;
const std::string FuncName = Func->getNameAsString();
@@ -117,7 +130,7 @@ std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunction
Func->isThisDeclarationADefinition())
continue;
- if (Func->getNameAsString() == GlobalFuncName) {
+ if (Func->getNameAsString() == GlobalFuncName && !Func->isVariadic() && hasSameParameters(Func, GlobalFunc) && Func->getReturnType().getCanonicalType() == GlobalFunc->getReturnType().getCanonicalType()) {
return {Func, NS};
}
}
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
index b82317fd0a748..04755b21dbd87 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
@@ -42,4 +42,5 @@ Limitations
- Does not warn about functions in anonymous namespaces
- Does not warn about template functions
- Does not warn about static functions or member functions
+- Does not warn about variadic functions
- Does not warn about the ``main`` function
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good3.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good3.cpp
new file mode 100644
index 0000000000000..998f0ff472b69
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good3.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+void f1(int);
+namespace foo {
+ void f0(short);
+ void f1(unsigned);
+}
+void f0(char) {}
+void f1(int) {}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good4.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good4.cpp
new file mode 100644
index 0000000000000..d6fb377edf586
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-good4.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+int f1();
+namespace foo {
+ char f0();
+ unsigned f1();
+}
+short f0() { return {}; }
+int f1() { return {}; }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-using.cpp
new file mode 100644
index 0000000000000..42222e3ba9032
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-using.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+using my_int = int;
+using my_short = short;
+using my_short2 = short;
+
+my_int f1(my_short2);
+namespace foo {
+ int f0(short);
+ int f1(short);
+}
+my_int f0(my_short) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: free function 'f0' shadows 'foo::f0' [misc-shadowed-namespace-function]
+// CHECK-FIXES: my_int foo::f0(my_short) {}
+my_int f1(my_short) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: free function 'f1' shadows 'foo::f1' [misc-shadowed-namespace-function]
+// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp
new file mode 100644
index 0000000000000..794c1cb629df5
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+void f1(...);
+namespace foo {
+ void f0(...);
+ void f1(...);
+}
+void f0(...) {}
+void f1(...) {}
>From b1ffd923b596ddf480e9892b0e0f7bd1dd6fa422 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 03:12:34 +0300
Subject: [PATCH 11/16] more unit-tests
---
.../misc/shadowed-namespace-function-macro.cpp | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-macro.cpp
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-macro.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-macro.cpp
new file mode 100644
index 0000000000000..540ae9112a21b
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-macro.cpp
@@ -0,0 +1,16 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+#define VOID_F0 void f0
+#define VOID_F1_BRACES_BODY void f1() {}
+
+void f1();
+namespace foo {
+ void f0();
+ void f1();
+}
+VOID_F0() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: free function 'f0' shadows 'foo::f0' [misc-shadowed-namespace-function]
+// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes
+VOID_F1_BRACES_BODY
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: free function 'f1' shadows 'foo::f1' [misc-shadowed-namespace-function]
+// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes
>From 1589ed566dd0a105982f62aeecfca9393aad8f55 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 03:16:31 +0300
Subject: [PATCH 12/16] lint
---
.../clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index 9633bf6c3353f..ea5f03f342b78 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -9,18 +9,16 @@
#include "ShadowedNamespaceFunctionCheck.h"
#include "../utils/FixItHintUtils.h"
#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tidy;
-namespace clang {
-namespace tidy {
-namespace misc {
+namespace clang::tidy::misc {
static bool hasSameParameters(const FunctionDecl *Func1, const FunctionDecl *Func2) {
if (Func1->param_size() != Func2->param_size())
@@ -138,7 +136,5 @@ std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunction
return {nullptr, nullptr};
}
-} // namespace misc
-} // namespace tidy
-} // namespace clang
+} // namespace clang::tidy::misc
>From 3b36a438b1a42e3c76b0e5305dbdc22fc2c5b4d1 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 03:17:09 +0300
Subject: [PATCH 13/16] format
---
.../misc/ShadowedNamespaceFunctionCheck.cpp | 54 +++++++++----------
.../misc/ShadowedNamespaceFunctionCheck.h | 4 +-
2 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
index ea5f03f342b78..0dd9ad0de357f 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.cpp
@@ -20,7 +20,8 @@ using namespace clang::tidy;
namespace clang::tidy::misc {
-static bool hasSameParameters(const FunctionDecl *Func1, const FunctionDecl *Func2) {
+static bool hasSameParameters(const FunctionDecl *Func1,
+ const FunctionDecl *Func2) {
if (Func1->param_size() != Func2->param_size())
return false;
@@ -34,18 +35,13 @@ static bool hasSameParameters(const FunctionDecl *Func1, const FunctionDecl *Fun
void ShadowedNamespaceFunctionCheck::registerMatchers(MatchFinder *Finder) {
// Simple matcher for all function definitions
- Finder->addMatcher(
- functionDecl(
- isDefinition()
- ).bind("func"),
- this
- );
+ Finder->addMatcher(functionDecl(isDefinition()).bind("func"), this);
}
void ShadowedNamespaceFunctionCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
-
+
if (!Func || !Result.SourceManager)
return;
@@ -55,8 +51,8 @@ void ShadowedNamespaceFunctionCheck::check(
return;
// Skip templates, static functions, main, etc.
- if (Func->isTemplated() || Func->isStatic() ||
- Func->isMain() || Func->isImplicit() || Func->isVariadic())
+ if (Func->isTemplated() || Func->isStatic() || Func->isMain() ||
+ Func->isImplicit() || Func->isVariadic())
return;
const std::string FuncName = Func->getNameAsString();
@@ -72,8 +68,10 @@ void ShadowedNamespaceFunctionCheck::check(
// Traverse all declarations in the translation unit
for (const auto *Decl : Context->getTranslationUnitDecl()->decls()) {
if (const auto *NS = dyn_cast<NamespaceDecl>(Decl)) {
- std::tie(ShadowedFunc, ShadowedNamespace) = findShadowedInNamespace(NS, Func, FuncName);
- if (ShadowedFunc) break;
+ std::tie(ShadowedFunc, ShadowedNamespace) =
+ findShadowedInNamespace(NS, Func, FuncName);
+ if (ShadowedFunc)
+ break;
}
}
@@ -84,11 +82,10 @@ void ShadowedNamespaceFunctionCheck::check(
return;
// Generate warning message
- const std::string NamespaceName = ShadowedNamespace->getQualifiedNameAsString();
- auto Diag = diag(Func->getLocation(),
- "free function %0 shadows '%1::%2'")
- << Func->getDeclName()
- << NamespaceName
+ const std::string NamespaceName =
+ ShadowedNamespace->getQualifiedNameAsString();
+ auto Diag = diag(Func->getLocation(), "free function %0 shadows '%1::%2'")
+ << Func->getDeclName() << NamespaceName
<< ShadowedFunc->getDeclName().getAsString();
// Generate fixit hint to add namespace qualification
@@ -99,16 +96,16 @@ void ShadowedNamespaceFunctionCheck::check(
}
// Note: Also show where the shadowed function is declared
- diag(ShadowedFunc->getLocation(),
- "function %0 declared here", DiagnosticIDs::Note)
+ diag(ShadowedFunc->getLocation(), "function %0 declared here",
+ DiagnosticIDs::Note)
<< ShadowedFunc->getDeclName();
}
-std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
- const NamespaceDecl *NS,
- const FunctionDecl *GlobalFunc,
+std::pair<const FunctionDecl *, const NamespaceDecl *>
+ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
+ const NamespaceDecl *NS, const FunctionDecl *GlobalFunc,
const std::string &GlobalFuncName) {
-
+
// Skip anonymous namespaces
if (NS->isAnonymousNamespace())
return {nullptr, nullptr};
@@ -116,7 +113,8 @@ std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunction
for (const auto *Decl : NS->decls()) {
// Check nested namespaces
if (const auto *NestedNS = dyn_cast<NamespaceDecl>(Decl)) {
- auto [ShadowedFunc, ShadowedNamespace] = findShadowedInNamespace(NestedNS, GlobalFunc, GlobalFuncName);
+ auto [ShadowedFunc, ShadowedNamespace] =
+ findShadowedInNamespace(NestedNS, GlobalFunc, GlobalFuncName);
if (ShadowedFunc)
return {ShadowedFunc, ShadowedNamespace};
}
@@ -124,11 +122,14 @@ std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunction
// Check functions
if (const auto *Func = dyn_cast<FunctionDecl>(Decl)) {
// Skip if it's the same function, templates, or definitions
- if (Func == GlobalFunc || Func->isTemplated() ||
+ if (Func == GlobalFunc || Func->isTemplated() ||
Func->isThisDeclarationADefinition())
continue;
- if (Func->getNameAsString() == GlobalFuncName && !Func->isVariadic() && hasSameParameters(Func, GlobalFunc) && Func->getReturnType().getCanonicalType() == GlobalFunc->getReturnType().getCanonicalType()) {
+ if (Func->getNameAsString() == GlobalFuncName && !Func->isVariadic() &&
+ hasSameParameters(Func, GlobalFunc) &&
+ Func->getReturnType().getCanonicalType() ==
+ GlobalFunc->getReturnType().getCanonicalType()) {
return {Func, NS};
}
}
@@ -137,4 +138,3 @@ std::pair<const FunctionDecl *, const NamespaceDecl *> ShadowedNamespaceFunction
}
} // namespace clang::tidy::misc
-
diff --git a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
index 594ab73dc18ab..8ee09272fffed 100644
--- a/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/ShadowedNamespaceFunctionCheck.h
@@ -14,7 +14,8 @@
namespace clang::tidy::misc {
-/// Detects free functions in global namespace that shadow functions from other namespaces.
+/// Detects free functions in global namespace that shadow functions from other
+/// namespaces.
///
/// For the user-facing documentation see:
/// https://clang.llvm.org/extra/clang-tidy/checks/misc/shadowed-namespace-function.html
@@ -27,6 +28,7 @@ class ShadowedNamespaceFunctionCheck : public ClangTidyCheck {
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
+
private:
std::pair<const FunctionDecl *, const NamespaceDecl *>
findShadowedInNamespace(const NamespaceDecl *NS,
>From 1f7748d4eb7146bee27e16f1258d71d000e79a59 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 19:13:43 +0300
Subject: [PATCH 14/16] friend
---
.../misc/shadowed-namespace-function.rst | 30 ++++++++++++++-----
.../shadowed-namespace-function-friend.cpp | 16 ++++++++++
2 files changed, 39 insertions(+), 7 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-friend.cpp
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
index 04755b21dbd87..c14251000d29c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
@@ -31,16 +31,32 @@ The check will suggest adding the appropriate namespace qualification:
- void process() {}
+ void utils::process() {}
-Options
--------
-
-None
+The check will not warn about:
+- Static functions or member functions;
+- Functions in anonymous namespaces;
+- The ``main`` function.
Limitations
-----------
-- Does not warn about functions in anonymous namespaces
+- Does not warn about friend functions:
+
+.. code-block:: c++
+
+ namespace llvm::gsym {
+ struct MergedFunctionsInfo {
+ friend bool operator==(const llvm::gsym::MergedFunctionsInfo &LHS,
+ const llvm::gsym::MergedFunctionsInfo &RHS);
+ };
+ }
+
+ using namespace llvm::gsym;
+
+ bool operator==(const MergedFunctionsInfo &LHS, // no warning in this version
+ const MergedFunctionsInfo &RHS) {
+ return LHS.MergedFunctions == RHS.MergedFunctions;
+ }
+
- Does not warn about template functions
-- Does not warn about static functions or member functions
- Does not warn about variadic functions
-- Does not warn about the ``main`` function
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-friend.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-friend.cpp
new file mode 100644
index 0000000000000..f70474987922d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-friend.cpp
@@ -0,0 +1,16 @@
+// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
+
+
+namespace foo { struct A; }
+void f1(foo::A);
+
+namespace foo {
+ struct A{
+ friend void f0(A);
+ friend void f1(A);
+ };
+}
+
+// FIXME: provide warning without fixit in these two cases
+void f0(foo::A) {}
+void f1(foo::A) {}
>From d6bdb398bde17319da8b7455c96b6709319f41f3 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 19:16:45 +0300
Subject: [PATCH 15/16] fix doc
---
.../clang-tidy/checks/misc/shadowed-namespace-function.rst | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
index c14251000d29c..628a6ef190430 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/shadowed-namespace-function.rst
@@ -32,6 +32,7 @@ The check will suggest adding the appropriate namespace qualification:
+ void utils::process() {}
The check will not warn about:
+
- Static functions or member functions;
- Functions in anonymous namespaces;
- The ``main`` function.
@@ -45,8 +46,8 @@ Limitations
namespace llvm::gsym {
struct MergedFunctionsInfo {
- friend bool operator==(const llvm::gsym::MergedFunctionsInfo &LHS,
- const llvm::gsym::MergedFunctionsInfo &RHS);
+ friend bool operator==(const MergedFunctionsInfo &LHS,
+ const MergedFunctionsInfo &RHS);
};
}
>From 51eac24d050f6b26f3b963584ca260ec77e6e7fc Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 17 Nov 2025 19:22:47 +0300
Subject: [PATCH 16/16] important TODOs for future versions of check
---
.../checkers/misc/shadowed-namespace-function-template.cpp | 3 +++
.../checkers/misc/shadowed-namespace-function-variadic.cpp | 3 +++
2 files changed, 6 insertions(+)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp
index 48924fcdb932d..ad99e524b0207 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-template.cpp
@@ -8,6 +8,9 @@ namespace foo {
template<typename T>
void f1();
}
+
+// FIXME: provide warning in these two cases
+// FIXME: provide fixit for f0
template<typename T>
void f0() {}
template<typename T>
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp
index 794c1cb629df5..cd470d28551c3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/shadowed-namespace-function-variadic.cpp
@@ -5,5 +5,8 @@ namespace foo {
void f0(...);
void f1(...);
}
+
+// FIXME: warning in these two cases??
+// FIXME: fixit for f0??
void f0(...) {}
void f1(...) {}
More information about the cfe-commits
mailing list