1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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.
12 #include "internal_ftm_use.hpp"
14 #include <clang/Lex/Lexer.h>
15 #include <clang/Lex/PPCallbacks.h>
16 #include <clang/Lex/Preprocessor.h>
22 std::array valid_macros
{
24 "_LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS",
27 "_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER",
29 // TODO: Why does this macro even exist?
30 "_LIBCPP_HAS_NO_TREE_BARRIER",
32 // Experimental features
33 "_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB",
34 "_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM",
35 "_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN",
36 "_LIBCPP_HAS_NO_INCOMPLETE_PSTL",
39 class internal_ftm_use_callbacks
: public clang::PPCallbacks
{
41 internal_ftm_use_callbacks(clang::tidy::ClangTidyCheck
& check
) : check_(check
) {}
43 void Defined(const clang::Token
& token
,
44 const clang::MacroDefinition
& macro_definition
,
45 clang::SourceRange location
) override
{
46 check_macro(token
.getIdentifierInfo()->getName(), location
.getBegin());
49 void Ifdef(clang::SourceLocation location
, const clang::Token
& token
, const clang::MacroDefinition
&) override
{
50 check_macro(token
.getIdentifierInfo()->getName(), location
);
53 void Elifdef(clang::SourceLocation location
, const clang::Token
& token
, const clang::MacroDefinition
&) override
{
54 check_macro(token
.getIdentifierInfo()->getName(), location
);
57 void Ifndef(clang::SourceLocation location
, const clang::Token
& token
, const clang::MacroDefinition
&) override
{
58 check_macro(token
.getIdentifierInfo()->getName(), location
);
61 void Elifndef(clang::SourceLocation location
, const clang::Token
& token
, const clang::MacroDefinition
&) override
{
62 check_macro(token
.getIdentifierInfo()->getName(), location
);
66 void check_macro(std::string_view macro
, clang::SourceLocation location
) {
67 if (macro
.starts_with("_LIBCPP_HAS_") && std::ranges::find(valid_macros
, macro
) == valid_macros
.end()) {
68 check_
.diag(location
, std::string("\'") + std::string
{macro
} + "' is always defined to 1 or 0.");
72 clang::tidy::ClangTidyCheck
& check_
;
76 internal_ftm_use::internal_ftm_use(llvm::StringRef name
, clang::tidy::ClangTidyContext
* context
)
77 : clang::tidy::ClangTidyCheck(name
, context
) {}
79 void internal_ftm_use::registerPPCallbacks(const clang::SourceManager
& source_manager
,
80 clang::Preprocessor
* preprocessor
,
81 clang::Preprocessor
* module_expander
) {
82 preprocessor
->addPPCallbacks(std::make_unique
<internal_ftm_use_callbacks
>(*this));