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#include "proper_version_checks.hpp"
10
11#include <clang/Lex/Lexer.h>
12#include <clang/Lex/PPCallbacks.h>
13#include <clang/Lex/Preprocessor.h>
14
15namespace libcpp {
16namespace {
17class proper_version_checks_callbacks : public clang::PPCallbacks {
18public:
19 proper_version_checks_callbacks(clang::Preprocessor& preprocessor, clang::tidy::ClangTidyCheck& check)
20 : preprocessor_(preprocessor), check_(check) {}
21
22 void If(clang::SourceLocation location, clang::SourceRange condition_range, ConditionValueKind) override {
23 check_condition(location, condition_range);
24 }
25
26 void Elif(clang::SourceLocation location,
27 clang::SourceRange condition_range,
28 ConditionValueKind,
29 clang::SourceLocation if_location) override {
30 check_condition(location, condition_range);
31 }
32
33private:
34 void check_condition(clang::SourceLocation location, clang::SourceRange condition_range) {
35 std::string_view condition = clang::Lexer::getSourceText(
36 Range: clang::CharSourceRange::getTokenRange(R: condition_range),
37 SM: preprocessor_.getSourceManager(),
38 LangOpts: preprocessor_.getLangOpts());
39 if (preprocessor_.getSourceManager().isInMainFile(Loc: location))
40 return;
41
42 if (condition == "__cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)")
43 return;
44
45 if (condition.starts_with("_LIBCPP_STD_VER") && condition.find(">") != std::string_view::npos &&
46 condition.find(">=") == std::string_view::npos)
47 check_.diag(location, "_LIBCPP_STD_VER >= version should be used instead of _LIBCPP_STD_VER > prev_version");
48
49 else if (condition.starts_with("__cplusplus"))
50 check_.diag(location, "Use _LIBCPP_STD_VER instead of __cplusplus to constrain based on the C++ version");
51
52 else if (condition == "_LIBCPP_STD_VER >= 11")
53 check_.diag(location, "_LIBCPP_STD_VER >= 11 is always true. Did you mean '#ifndef _LIBCPP_CXX03_LANG'?");
54
55 else if (condition.starts_with("_LIBCPP_STD_VER >= ") &&
56 std::ranges::none_of(std::array{"14", "17", "20", "23", "26"}, [&](auto val) {
57 return condition.find(val) != std::string_view::npos;
58 }))
59 check_.diag(location, "Not a valid value for _LIBCPP_STD_VER. Use 14, 17, 20, 23, or 26");
60 }
61
62 clang::Preprocessor& preprocessor_;
63 clang::tidy::ClangTidyCheck& check_;
64};
65} // namespace
66
67proper_version_checks::proper_version_checks(llvm::StringRef name, clang::tidy::ClangTidyContext* context)
68 : clang::tidy::ClangTidyCheck(name, context) {}
69
70void proper_version_checks::registerPPCallbacks(
71 const clang::SourceManager& source_manager,
72 clang::Preprocessor* preprocessor,
73 clang::Preprocessor* module_expander) {
74 preprocessor->addPPCallbacks(std::make_unique<proper_version_checks_callbacks>(args&: *preprocessor, args&: *this));
75}
76
77} // namespace libcpp
78

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/proper_version_checks.cpp