Skip to content

Commit 45f7285

Browse files
authored
[clang-tidy] Use lexical anon-ns matcher in llvm-prefer-static-over-anonymous-namespace (#148357)
When having this code: ```cpp namespace { class MyClassOutOfAnon { public: MyClassOutOfAnon(); } // namespace MyClassOutOfAnon::MyClassOutOfAnon() {} ``` `MyClassOutOfAnon::MyClassOutOfAnon` is located in anonymous namespace in `DeclContext` but outside anonymous namespace in `LexicalDeclContext`. For this check to work correctly, we need to check if definition is located inside `LexicalDeclContext`.
1 parent 7cb8439 commit 45f7285

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

clang-tools-extra/clang-tidy/llvm/PreferStaticOverAnonymousNamespaceCheck.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ AST_MATCHER(NamedDecl, isInMacro) {
2121

2222
AST_MATCHER(VarDecl, isLocalVariable) { return Node.isLocalVarDecl(); }
2323

24+
AST_MATCHER(Decl, isLexicallyInAnonymousNamespace) {
25+
for (const DeclContext *DC = Node.getLexicalDeclContext(); DC != nullptr;
26+
DC = DC->getLexicalParent()) {
27+
if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
28+
if (ND->isAnonymousNamespace())
29+
return true;
30+
}
31+
32+
return false;
33+
}
34+
2435
} // namespace
2536

2637
PreferStaticOverAnonymousNamespaceCheck::
@@ -40,9 +51,9 @@ void PreferStaticOverAnonymousNamespaceCheck::storeOptions(
4051

4152
void PreferStaticOverAnonymousNamespaceCheck::registerMatchers(
4253
MatchFinder *Finder) {
43-
const auto IsDefinitionInAnonymousNamespace =
44-
allOf(unless(isExpansionInSystemHeader()), isInAnonymousNamespace(),
45-
unless(isInMacro()), isDefinition());
54+
const auto IsDefinitionInAnonymousNamespace = allOf(
55+
unless(isExpansionInSystemHeader()), isLexicallyInAnonymousNamespace(),
56+
unless(isInMacro()), isDefinition());
4657

4758
if (AllowMemberFunctionsInClass) {
4859
Finder->addMatcher(

clang-tools-extra/test/clang-tidy/checkers/llvm/prefer-static-over-anonymous-namespace.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,95 @@ void OuterClass::NestedClass::nestedMemberFunc() {}
178178

179179
} // namespace
180180

181+
namespace {
182+
183+
class MyClassOutOfAnon {
184+
public:
185+
MyClassOutOfAnon();
186+
MyClassOutOfAnon(const MyClassOutOfAnon&) {}
187+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 'MyClassOutOfAnon' outside of an anonymous namespace
188+
MyClassOutOfAnon(MyClassOutOfAnon&&) = default;
189+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 'MyClassOutOfAnon' outside of an anonymous namespace
190+
MyClassOutOfAnon& operator=(const MyClassOutOfAnon&);
191+
MyClassOutOfAnon& operator=(MyClassOutOfAnon&&);
192+
bool operator<(const MyClassOutOfAnon&) const;
193+
void memberFunction();
194+
static void staticMemberFunction();
195+
void memberDefinedInClass() {}
196+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 'memberDefinedInClass' outside of an anonymous namespace
197+
static void staticMemberDefinedInClass() {}
198+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:15: warning: place definition of method 'staticMemberDefinedInClass' outside of an anonymous namespace
199+
template <typename T>
200+
void templateFunction();
201+
template <typename T>
202+
void templateFunctionInClass() {}
203+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 'templateFunctionInClass' outside of an anonymous namespace
204+
};
205+
206+
} // namespace
207+
208+
MyClassOutOfAnon::MyClassOutOfAnon() {}
209+
210+
MyClassOutOfAnon& MyClassOutOfAnon::operator=(const MyClassOutOfAnon&) { return *this; }
211+
212+
MyClassOutOfAnon& MyClassOutOfAnon::operator=(MyClassOutOfAnon&&) = default;
213+
214+
bool MyClassOutOfAnon::operator<(const MyClassOutOfAnon&) const { return true; }
215+
216+
void MyClassOutOfAnon::memberFunction() {}
217+
218+
void MyClassOutOfAnon::staticMemberFunction() {}
219+
220+
template <typename T>
221+
void MyClassOutOfAnon::templateFunction() {}
222+
223+
namespace {
224+
225+
template<typename T>
226+
class TemplateClassOutOfAnon {
227+
public:
228+
TemplateClassOutOfAnon();
229+
TemplateClassOutOfAnon(const TemplateClassOutOfAnon&) {}
230+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 'TemplateClassOutOfAnon<T>' outside of an anonymous namespace
231+
TemplateClassOutOfAnon(TemplateClassOutOfAnon&&) = default;
232+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 'TemplateClassOutOfAnon<T>' outside of an anonymous namespace
233+
TemplateClassOutOfAnon& operator=(const TemplateClassOutOfAnon&);
234+
TemplateClassOutOfAnon& operator=(TemplateClassOutOfAnon&&);
235+
bool operator<(const TemplateClassOutOfAnon&) const;
236+
void memberFunc();
237+
T getValue() const;
238+
void memberDefinedInClass() {}
239+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 'memberDefinedInClass' outside of an anonymous namespace
240+
static void staticMemberDefinedInClass() {}
241+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:15: warning: place definition of method 'staticMemberDefinedInClass' outside of an anonymous namespace
242+
template <typename U>
243+
void templateMethodInTemplateClass() {}
244+
// CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 'templateMethodInTemplateClass' outside of an anonymous namespace
245+
private:
246+
T Value;
247+
};
248+
249+
} // namespace
250+
251+
template<typename T>
252+
TemplateClassOutOfAnon<T>::TemplateClassOutOfAnon() {}
253+
254+
template<typename T>
255+
TemplateClassOutOfAnon<T>& TemplateClassOutOfAnon<T>::operator=(const TemplateClassOutOfAnon&) { return *this; }
256+
257+
template<typename T>
258+
TemplateClassOutOfAnon<T>& TemplateClassOutOfAnon<T>::operator=(TemplateClassOutOfAnon&&) = default;
259+
260+
template<typename T>
261+
bool TemplateClassOutOfAnon<T>::operator<(const TemplateClassOutOfAnon&) const { return true; }
262+
263+
template<typename T>
264+
void TemplateClassOutOfAnon<T>::memberFunc() {}
265+
266+
template<typename T>
267+
T TemplateClassOutOfAnon<T>::getValue() const { return Value; }
268+
269+
181270
#define DEFINE_FUNCTION(name) \
182271
namespace { \
183272
void name() {} \

0 commit comments

Comments
 (0)