xref: /llvm-project/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp (revision a074f8869563cb5b296732e0e8af46dcdc286ae5)
100a57558SPaula Toth //===--- ImplementationInNamespaceCheck.cpp - clang-tidy ------------------===//
200a57558SPaula Toth //
300a57558SPaula Toth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
400a57558SPaula Toth // See https://llvm.org/LICENSE.txt for license information.
500a57558SPaula Toth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
600a57558SPaula Toth //
700a57558SPaula Toth //===----------------------------------------------------------------------===//
800a57558SPaula Toth 
900a57558SPaula Toth #include "ImplementationInNamespaceCheck.h"
10daca9721Smichaelrj-google #include "NamespaceConstants.h"
1100a57558SPaula Toth #include "clang/AST/ASTContext.h"
1200a57558SPaula Toth #include "clang/ASTMatchers/ASTMatchFinder.h"
1300a57558SPaula Toth 
1400a57558SPaula Toth using namespace clang::ast_matchers;
1500a57558SPaula Toth 
167d2ea6c4SCarlos Galvez namespace clang::tidy::llvm_libc {
1700a57558SPaula Toth 
1800a57558SPaula Toth void ImplementationInNamespaceCheck::registerMatchers(MatchFinder *Finder) {
1900a57558SPaula Toth   Finder->addMatcher(
20774116b8SGuillaume Chatelet       translationUnitDecl(
21774116b8SGuillaume Chatelet           forEach(decl(isExpansionInMainFile(), unless(linkageSpecDecl()),
22774116b8SGuillaume Chatelet                        // anonymous namespaces generate usingDirective
23774116b8SGuillaume Chatelet                        unless(usingDirectiveDecl(isImplicit())))
24774116b8SGuillaume Chatelet                       .bind("child_of_translation_unit"))),
2500a57558SPaula Toth       this);
2600a57558SPaula Toth }
2700a57558SPaula Toth 
2800a57558SPaula Toth void ImplementationInNamespaceCheck::check(
2900a57558SPaula Toth     const MatchFinder::MatchResult &Result) {
3000a57558SPaula Toth   const auto *MatchedDecl =
3100a57558SPaula Toth       Result.Nodes.getNodeAs<Decl>("child_of_translation_unit");
32774116b8SGuillaume Chatelet   const auto *NS = dyn_cast<NamespaceDecl>(MatchedDecl);
33*a074f886SPaul Kirth 
34*a074f886SPaul Kirth   // LLVM libc declarations should be inside of a non-anonymous namespace.
35774116b8SGuillaume Chatelet   if (NS == nullptr || NS->isAnonymousNamespace()) {
3600a57558SPaula Toth     diag(MatchedDecl->getLocation(),
37774116b8SGuillaume Chatelet          "declaration must be enclosed within the '%0' namespace")
38*a074f886SPaul Kirth         << RequiredNamespaceDeclMacroName;
39774116b8SGuillaume Chatelet     return;
40774116b8SGuillaume Chatelet   }
41*a074f886SPaul Kirth 
42*a074f886SPaul Kirth   // Enforce that the namespace is the result of macro expansion
43774116b8SGuillaume Chatelet   if (Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) == false) {
44774116b8SGuillaume Chatelet     diag(NS->getLocation(), "the outermost namespace should be the '%0' macro")
45*a074f886SPaul Kirth         << RequiredNamespaceDeclMacroName;
46774116b8SGuillaume Chatelet     return;
47774116b8SGuillaume Chatelet   }
48*a074f886SPaul Kirth 
49*a074f886SPaul Kirth   // We want the macro to have [[gnu::visibility("hidden")]] as a prefix, but
50*a074f886SPaul Kirth   // visibility is just an attribute in the AST construct, so we check that
51*a074f886SPaul Kirth   // instead.
52*a074f886SPaul Kirth   if (NS->getVisibility() != Visibility::HiddenVisibility) {
53774116b8SGuillaume Chatelet     diag(NS->getLocation(), "the '%0' macro should start with '%1'")
54*a074f886SPaul Kirth         << RequiredNamespaceDeclMacroName << RequiredNamespaceDeclStart;
55*a074f886SPaul Kirth     return;
56*a074f886SPaul Kirth   }
57*a074f886SPaul Kirth 
58*a074f886SPaul Kirth   // Lastly, make sure the namespace name actually has the __llvm_libc prefix
59*a074f886SPaul Kirth   if (NS->getName().starts_with(RequiredNamespaceRefStart) == false) {
60*a074f886SPaul Kirth     diag(NS->getLocation(), "the '%0' macro expansion should start with '%1'")
61*a074f886SPaul Kirth         << RequiredNamespaceDeclMacroName << RequiredNamespaceRefStart;
62774116b8SGuillaume Chatelet     return;
63774116b8SGuillaume Chatelet   }
6400a57558SPaula Toth }
6500a57558SPaula Toth 
667d2ea6c4SCarlos Galvez } // namespace clang::tidy::llvm_libc
67