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// This clang-tidy check ensures that we don't use any _LIBCPP_HAS_FOO macro
10// inside `#ifdef`, `#ifndef` & friends, since the intent is to always use `#if` instead.
11
12#include "internal_ftm_use.hpp"
13
14#include <clang/Lex/Lexer.h>
15#include <clang/Lex/PPCallbacks.h>
16#include <clang/Lex/Preprocessor.h>
17
18#include <string>
19
20namespace libcpp {
21namespace {
22std::array valid_macros{
23 // Public API macros
24 "_LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS",
25
26 // Testing macros
27 "_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER",
28};
29
30class internal_ftm_use_callbacks : public clang::PPCallbacks {
31public:
32 internal_ftm_use_callbacks(clang::tidy::ClangTidyCheck& check) : check_(check) {}
33
34 void Defined(const clang::Token& token,
35 const clang::MacroDefinition& macro_definition,
36 clang::SourceRange location) override {
37 check_macro(macro: token.getIdentifierInfo()->getName(), location: location.getBegin());
38 }
39
40 void Ifdef(clang::SourceLocation location, const clang::Token& token, const clang::MacroDefinition&) override {
41 check_macro(macro: token.getIdentifierInfo()->getName(), location);
42 }
43
44 void Elifdef(clang::SourceLocation location, const clang::Token& token, const clang::MacroDefinition&) override {
45 check_macro(macro: token.getIdentifierInfo()->getName(), location);
46 }
47
48 void Ifndef(clang::SourceLocation location, const clang::Token& token, const clang::MacroDefinition&) override {
49 check_macro(macro: token.getIdentifierInfo()->getName(), location);
50 }
51
52 void Elifndef(clang::SourceLocation location, const clang::Token& token, const clang::MacroDefinition&) override {
53 check_macro(macro: token.getIdentifierInfo()->getName(), location);
54 }
55
56private:
57 void check_macro(std::string_view macro, clang::SourceLocation location) {
58 if (macro.starts_with("_LIBCPP_HAS_") && std::ranges::find(valid_macros, macro) == valid_macros.end()) {
59 check_.diag(location, std::string("\'") + std::string{macro} + "' is always defined to 1 or 0.");
60 }
61 }
62
63 clang::tidy::ClangTidyCheck& check_;
64};
65} // namespace
66
67internal_ftm_use::internal_ftm_use(llvm::StringRef name, clang::tidy::ClangTidyContext* context)
68 : clang::tidy::ClangTidyCheck(name, context) {}
69
70void internal_ftm_use::registerPPCallbacks(const clang::SourceManager& source_manager,
71 clang::Preprocessor* preprocessor,
72 clang::Preprocessor* module_expander) {
73 preprocessor->addPPCallbacks(std::make_unique<internal_ftm_use_callbacks>(args&: *this));
74}
75
76} // namespace libcpp
77

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of libcxx/test/tools/clang_tidy_checks/internal_ftm_use.cpp