Skip to content

Commit b7d665b

Browse files
committed
Implementation template from DeepSeek
1 parent 070f331 commit b7d665b

File tree

8 files changed

+200
-0
lines changed

8 files changed

+200
-0
lines changed

clang-tools-extra/clang-tidy/misc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_clang_library(clangTidyMiscModule STATIC
3434
NonPrivateMemberVariablesInClassesCheck.cpp
3535
OverrideWithDifferentVisibilityCheck.cpp
3636
RedundantExpressionCheck.cpp
37+
ShadowedNamespaceFunctionCheck.cpp
3738
StaticAssertCheck.cpp
3839
ThrowByValueCatchByReferenceCheck.cpp
3940
UnconventionalAssignOperatorCheck.cpp

clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "NonPrivateMemberVariablesInClassesCheck.h"
2525
#include "OverrideWithDifferentVisibilityCheck.h"
2626
#include "RedundantExpressionCheck.h"
27+
#include "ShadowedNamespaceFunctionCheck.h"
2728
#include "StaticAssertCheck.h"
2829
#include "ThrowByValueCatchByReferenceCheck.h"
2930
#include "UnconventionalAssignOperatorCheck.h"
@@ -65,6 +66,8 @@ class MiscModule : public ClangTidyModule {
6566
"misc-non-private-member-variables-in-classes");
6667
CheckFactories.registerCheck<RedundantExpressionCheck>(
6768
"misc-redundant-expression");
69+
CheckFactories.registerCheck<ShadowedNamespaceFunctionCheck>(
70+
"misc-shadowed-namespace-function");
6871
CheckFactories.registerCheck<StaticAssertCheck>("misc-static-assert");
6972
CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
7073
"misc-throw-by-value-catch-by-reference");
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "ShadowedNamespaceFunctionCheck.h"
10+
#include "../utils/FixItHintUtils.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
13+
#include "clang/AST/Decl.h"
14+
#include "clang/AST/DeclCXX.h"
15+
16+
using namespace clang;
17+
using namespace clang::ast_matchers;
18+
using namespace clang::tidy;
19+
20+
namespace clang {
21+
namespace tidy {
22+
namespace misc {
23+
24+
void ShadowedNamespaceFunctionCheck::registerMatchers(MatchFinder *Finder) {
25+
// Simple matcher for all function definitions
26+
Finder->addMatcher(
27+
functionDecl(
28+
isDefinition()
29+
).bind("func"),
30+
this
31+
);
32+
}
33+
34+
void ShadowedNamespaceFunctionCheck::check(
35+
const MatchFinder::MatchResult &Result) {
36+
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
37+
38+
if (!Func || !Result.SourceManager)
39+
return;
40+
41+
// Skip if not in global namespace
42+
const DeclContext *DC = Func->getDeclContext();
43+
if (!DC->isTranslationUnit())
44+
return;
45+
46+
// Skip templates, static functions, main, etc.
47+
if (Func->isTemplated() || Func->isStatic() ||
48+
Func->getName() == "main" || Func->isImplicit())
49+
return;
50+
51+
std::string FuncName = Func->getNameAsString();
52+
if (FuncName.empty())
53+
return;
54+
55+
ASTContext *Context = Result.Context;
56+
57+
// Look for functions with the same name in namespaces
58+
const FunctionDecl *ShadowedFunc = nullptr;
59+
const NamespaceDecl *ShadowedNamespace = nullptr;
60+
61+
// Traverse all declarations in the translation unit
62+
for (const auto *Decl : Context->getTranslationUnitDecl()->decls()) {
63+
if (const auto *NS = dyn_cast<NamespaceDecl>(Decl)) {
64+
findShadowedInNamespace(NS, Func, FuncName, ShadowedFunc, ShadowedNamespace);
65+
if (ShadowedFunc) break;
66+
}
67+
}
68+
69+
if (!ShadowedFunc || !ShadowedNamespace)
70+
return;
71+
72+
// Generate warning message
73+
std::string NamespaceName = ShadowedNamespace->getNameAsString();
74+
auto Diag = diag(Func->getLocation(),
75+
"free function %0 shadows %1::%2")
76+
<< Func->getDeclName()
77+
<< NamespaceName
78+
<< ShadowedFunc->getDeclName();
79+
80+
// Generate fixit hint to add namespace qualification
81+
SourceLocation NameLoc = Func->getLocation();
82+
if (NameLoc.isValid()) {
83+
std::string Fix = NamespaceName + "::";
84+
Diag << FixItHint::CreateInsertion(NameLoc, Fix);
85+
}
86+
87+
// Note: Also show where the shadowed function is declared
88+
diag(ShadowedFunc->getLocation(),
89+
"function %0 declared here", DiagnosticIDs::Note)
90+
<< ShadowedFunc->getDeclName();
91+
}
92+
93+
void ShadowedNamespaceFunctionCheck::findShadowedInNamespace(
94+
const NamespaceDecl *NS,
95+
const FunctionDecl *GlobalFunc,
96+
const std::string &GlobalFuncName,
97+
const FunctionDecl *&ShadowedFunc,
98+
const NamespaceDecl *&ShadowedNamespace) {
99+
100+
// Skip anonymous namespaces
101+
if (NS->isAnonymousNamespace())
102+
return;
103+
104+
for (const auto *Decl : NS->decls()) {
105+
// Check nested namespaces
106+
if (const auto *NestedNS = dyn_cast<NamespaceDecl>(Decl)) {
107+
findShadowedInNamespace(NestedNS, GlobalFunc, GlobalFuncName,
108+
ShadowedFunc, ShadowedNamespace);
109+
if (ShadowedFunc) return;
110+
}
111+
112+
// Check functions
113+
if (const auto *Func = dyn_cast<FunctionDecl>(Decl)) {
114+
// Skip if it's the same function, templates, or definitions
115+
if (Func == GlobalFunc || Func->isTemplated() ||
116+
Func->isThisDeclarationADefinition())
117+
continue;
118+
119+
if (Func->getNameAsString() == GlobalFuncName) {
120+
ShadowedFunc = Func;
121+
ShadowedNamespace = NS;
122+
return;
123+
}
124+
}
125+
}
126+
}
127+
128+
} // namespace misc
129+
} // namespace tidy
130+
} // namespace clang
131+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::misc {
15+
16+
/// FIXME: Write a short description.
17+
///
18+
/// For the user-facing documentation see:
19+
/// https://clang.llvm.org/extra/clang-tidy/checks/misc/shadowed-namespace-function.html
20+
class ShadowedNamespaceFunctionCheck : public ClangTidyCheck {
21+
public:
22+
ShadowedNamespaceFunctionCheck(StringRef Name, ClangTidyContext *Context)
23+
: ClangTidyCheck(Name, Context) {}
24+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
25+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
26+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
27+
return LangOpts.CPlusPlus;
28+
}
29+
private:
30+
void findShadowedInNamespace(const NamespaceDecl *NS,
31+
const FunctionDecl *GlobalFunc,
32+
const std::string &GlobalFuncName,
33+
const FunctionDecl *&ShadowedFunc,
34+
const NamespaceDecl *&ShadowedNamespace);
35+
};
36+
37+
} // namespace clang::tidy::misc
38+
39+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SHADOWEDNAMESPACEFUNCTIONCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ New checks
226226
Finds virtual function overrides with different visibility than the function
227227
in the base class.
228228

229+
- New :doc:`misc-shadowed-namespace-function
230+
<clang-tidy/checks/misc/shadowed-namespace-function>` check.
231+
232+
FIXME: Write a short description.
233+
229234
- New :doc:`readability-redundant-parentheses
230235
<clang-tidy/checks/readability/redundant-parentheses>` check.
231236

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ Clang-Tidy Checks
277277
:doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
278278
:doc:`misc-override-with-different-visibility <misc/override-with-different-visibility>`,
279279
:doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
280+
:doc:`misc-shadowed-namespace-function <misc/shadowed-namespace-function>`, "Yes"
281+
:doc:`misc-shadowed-namespace-function <misc/shadowed-namespace-function>`, "Yes"
280282
:doc:`misc-static-assert <misc/static-assert>`, "Yes"
281283
:doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
282284
:doc:`misc-unconventional-assign-operator <misc/unconventional-assign-operator>`,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. title:: clang-tidy - misc-shadowed-namespace-function
2+
3+
misc-shadowed-namespace-function
4+
================================
5+
6+
FIXME: Describe what patterns does the check detect and why. Give examples.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %check_clang_tidy %s misc-shadowed-namespace-function %t
2+
3+
void f1();
4+
namespace foo {
5+
void f0();
6+
void f1();
7+
}
8+
void f0() {}
9+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f0' shadows foo::f0 [misc-shadowed-namespace-function]
10+
// CHECK-FIXES: void foo::f0() {}
11+
void f1() {}
12+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: free function 'f1' shadows foo::f1 [misc-shadowed-namespace-function]
13+
// CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes

0 commit comments

Comments
 (0)