Skip to content

Commit 774116b

Browse files
authored
[clang-tidy] Update llvmlibc-implementation-in-namespace to new rules (#66504)
This is the implementation of step 3 of https://discourse.llvm.org/t/rfc-customizable-namespace-to-allow-testing-the-libc-when-the-system-libc-is-also-llvms-libc/73079.
1 parent 12fda30 commit 774116b

File tree

4 files changed

+77
-31
lines changed

4 files changed

+77
-31
lines changed

clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,41 @@ using namespace clang::ast_matchers;
1414

1515
namespace clang::tidy::llvm_libc {
1616

17-
const static StringRef RequiredNamespace = "__llvm_libc";
17+
const static StringRef RequiredNamespaceStart = "__llvm_libc";
18+
const static StringRef RequiredNamespaceMacroName = "LIBC_NAMESPACE";
19+
1820
void ImplementationInNamespaceCheck::registerMatchers(MatchFinder *Finder) {
1921
Finder->addMatcher(
20-
decl(hasParent(translationUnitDecl()), unless(linkageSpecDecl()))
21-
.bind("child_of_translation_unit"),
22+
translationUnitDecl(
23+
forEach(decl(isExpansionInMainFile(), unless(linkageSpecDecl()),
24+
// anonymous namespaces generate usingDirective
25+
unless(usingDirectiveDecl(isImplicit())))
26+
.bind("child_of_translation_unit"))),
2227
this);
2328
}
2429

2530
void ImplementationInNamespaceCheck::check(
2631
const MatchFinder::MatchResult &Result) {
2732
const auto *MatchedDecl =
2833
Result.Nodes.getNodeAs<Decl>("child_of_translation_unit");
29-
if (!Result.SourceManager->isInMainFile(MatchedDecl->getLocation()))
34+
MatchedDecl->dump();
35+
const auto *NS = dyn_cast<NamespaceDecl>(MatchedDecl);
36+
if (NS == nullptr || NS->isAnonymousNamespace()) {
37+
diag(MatchedDecl->getLocation(),
38+
"declaration must be enclosed within the '%0' namespace")
39+
<< RequiredNamespaceMacroName;
3040
return;
31-
32-
if (const auto *NS = dyn_cast<NamespaceDecl>(MatchedDecl)) {
33-
if (NS->getName() != RequiredNamespace) {
34-
diag(NS->getLocation(), "'%0' needs to be the outermost namespace")
35-
<< RequiredNamespace;
36-
}
41+
}
42+
if (Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) == false) {
43+
diag(NS->getLocation(), "the outermost namespace should be the '%0' macro")
44+
<< RequiredNamespaceMacroName;
45+
return;
46+
}
47+
if (NS->getName().starts_with(RequiredNamespaceStart) == false) {
48+
diag(NS->getLocation(), "the '%0' macro should start with '%1'")
49+
<< RequiredNamespaceMacroName << RequiredNamespaceStart;
3750
return;
3851
}
39-
diag(MatchedDecl->getLocation(),
40-
"declaration must be declared within the '%0' namespace")
41-
<< RequiredNamespace;
4252
}
4353

4454
} // namespace clang::tidy::llvm_libc

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,11 @@ Changes in existing checks
241241
<clang-tidy/checks/llvm/namespace-comment>` check to provide fixes for
242242
``inline`` namespaces in the same format as :program:`clang-format`.
243243

244+
- Improved :doc:`llvmlibc-implementation-in-namespace
245+
<clang-tidy/checks/llvmlibc/implementation-in-namespace>` to support
246+
customizable namespace. This further allows for testing the libc when the
247+
system-libc is also LLVM's libc.
248+
244249
- Improved :doc:`misc-include-cleaner
245250
<clang-tidy/checks/misc/include-cleaner>` check by adding option
246251
`DeduplicateFindings` to output one finding per symbol occurrence.

clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,30 @@ correct namespace.
88

99
.. code-block:: c++
1010

11-
// Correct: implementation inside the correct namespace.
12-
namespace __llvm_libc {
11+
// Implementation inside the LIBC_NAMESPACE namespace.
12+
// Correct if:
13+
// - LIBC_NAMESPACE is a macro
14+
// - LIBC_NAMESPACE expansion starts with `__llvm_libc`
15+
namespace LIBC_NAMESPACE {
1316
void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
14-
// Namespaces within __llvm_libc namespace are allowed.
15-
namespace inner{
17+
// Namespaces within LIBC_NAMESPACE namespace are allowed.
18+
namespace inner {
1619
int localVar = 0;
1720
}
1821
// Functions with C linkage are allowed.
19-
extern "C" void str_fuzz(){}
22+
extern "C" void str_fuzz() {}
2023
}
2124
22-
// Incorrect: implementation not in a namespace.
25+
// Incorrect: implementation not in the LIBC_NAMESPACE namespace.
2326
void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
2427
25-
// Incorrect: outer most namespace is not correct.
28+
// Incorrect: outer most namespace is not the LIBC_NAMESPACE macro.
2629
namespace something_else {
2730
void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
2831
}
32+
33+
// Incorrect: outer most namespace expansion does not start with `__llvm_libc`.
34+
#define LIBC_NAMESPACE custom_namespace
35+
namespace LIBC_NAMESPACE {
36+
void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
37+
}

clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,30 @@
33
#define MACRO_A "defining macros outside namespace is valid"
44

55
class ClassB;
6-
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be declared within the '__llvm_libc' namespace
6+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
77
struct StructC {};
8-
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration must be declared within the '__llvm_libc' namespace
8+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
99
char *VarD = MACRO_A;
10-
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be declared within the '__llvm_libc' namespace
10+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
1111
typedef int typeE;
12-
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be declared within the '__llvm_libc' namespace
12+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
1313
void funcF() {}
14-
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration must be declared within the '__llvm_libc' namespace
14+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
15+
16+
namespace outer_most {
17+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE' macro
18+
class A {};
19+
}
20+
21+
// Wrapped in anonymous namespace.
22+
namespace {
23+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
24+
class A {};
25+
}
1526

1627
namespace namespaceG {
17-
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '__llvm_libc' needs to be the outermost namespace
18-
namespace __llvm_libc{
28+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE' macro
29+
namespace __llvm_libc {
1930
namespace namespaceH {
2031
class ClassB;
2132
} // namespace namespaceH
@@ -26,9 +37,20 @@ typedef int typeE;
2637
void funcF() {}
2738
} // namespace namespaceG
2839

29-
// Wrapped in correct namespace.
30-
namespace __llvm_libc {
31-
// Namespaces within __llvim_libc namespace allowed.
40+
// Wrapped in macro namespace but with an incorrect name
41+
#define LIBC_NAMESPACE custom_namespace
42+
namespace LIBC_NAMESPACE {
43+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the 'LIBC_NAMESPACE' macro should start with '__llvm_libc'
44+
namespace namespaceH {
45+
class ClassB;
46+
} // namespace namespaceH
47+
} // namespace LIBC_NAMESPACE
48+
49+
50+
// Wrapped in macro namespace with a valid name, LIBC_NAMESPACE starts with '__llvm_libc'
51+
#undef LIBC_NAMESPACE
52+
#define LIBC_NAMESPACE __llvm_libc_xyz
53+
namespace LIBC_NAMESPACE {
3254
namespace namespaceI {
3355
class ClassB;
3456
} // namespace namespaceI
@@ -37,4 +59,4 @@ char *VarD = MACRO_A;
3759
typedef int typeE;
3860
void funcF() {}
3961
extern "C" void extern_funcJ() {}
40-
} // namespace __llvm_libc
62+
} // namespace LIBC_NAMESPACE

0 commit comments

Comments
 (0)