[libcxx-commits] [libcxx] 07efa28 - [libc++] Add clang-tidy check for version checks
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Mar 8 06:17:31 PST 2023
Author: Nikolas Klauser
Date: 2023-03-08T15:17:25+01:00
New Revision: 07efa28314ce968dadadbcaff95cde2b9424a5ed
URL: https://github.com/llvm/llvm-project/commit/07efa28314ce968dadadbcaff95cde2b9424a5ed
DIFF: https://github.com/llvm/llvm-project/commit/07efa28314ce968dadadbcaff95cde2b9424a5ed.diff
LOG: [libc++] Add clang-tidy check for version checks
This check flags code which uses `_LIBCPP_STD_VER` the wrong way, or tries to use `__cplusplus`. It flags cases where we use `_LIBCPP_STD_VER >` instead of `_LIBCPP_STD_VER >=` and where wrong values are used (e.g. `_LIBCPP_STD_VER >= 24`).
Reviewed By: ldionne, #libc
Spies: libcxx-commits
Differential Revision: https://reviews.llvm.org/D144261
Added:
libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp
libcxx/test/tools/clang_tidy_checks/proper_version_checks.hpp
Modified:
libcxx/include/__chrono/concepts.h
libcxx/include/__config
libcxx/include/iomanip
libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__chrono/concepts.h b/libcxx/include/__chrono/concepts.h
index d7502ef9f84dc..38d6b0ccd538c 100644
--- a/libcxx/include/__chrono/concepts.h
+++ b/libcxx/include/__chrono/concepts.h
@@ -20,12 +20,12 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-#if _LIBCPP_STD_VER > 17
+#if _LIBCPP_STD_VER >= 20
template <class _Tp>
concept __is_hh_mm_ss = __is_specialization_v<_Tp, chrono::hh_mm_ss>;
-#endif // _LIBCPP_STD_VER > 17
+#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__config b/libcxx/include/__config
index f531b1c057f84..95a75ea758d53 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -50,6 +50,7 @@
# define _LIBCPP_FREESTANDING
# endif
+// NOLINTBEGIN(libcpp-cpp-version-check)
# ifndef _LIBCPP_STD_VER
# if __cplusplus <= 201103L
# define _LIBCPP_STD_VER 11
@@ -64,6 +65,7 @@
# define _LIBCPP_STD_VER 23
# endif
# endif // _LIBCPP_STD_VER
+// NOLINTEND(libcpp-cpp-version-check)
# if defined(__ELF__)
# define _LIBCPP_OBJECT_FORMAT_ELF 1
@@ -181,6 +183,7 @@
# define _LIBCPP_TOSTRING2(x) #x
# define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x)
+// NOLINTNEXTLINE(libcpp-cpp-version-check)
# if __cplusplus < 201103L
# define _LIBCPP_CXX03_LANG
# endif
diff --git a/libcxx/include/iomanip b/libcxx/include/iomanip
index bf8fbfe2a16f8..53445c72ba19a 100644
--- a/libcxx/include/iomanip
+++ b/libcxx/include/iomanip
@@ -513,8 +513,6 @@ put_time(const tm* __tm, const _CharT* __fmt)
return __iom_t10<_CharT>(__tm, __fmt);
}
-#if _LIBCPP_STD_VER >= 11
-
template <class _CharT, class _Traits>
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
__quoted_output(basic_ostream<_CharT, _Traits>& __os,
@@ -622,8 +620,6 @@ __quoted(basic_string<_CharT, _Traits, _Allocator>& __s, _CharT __delim = _CharT
return __quoted_proxy<_CharT, _Traits, _Allocator>(__s, __delim, __escape);
}
-#endif // _LIBCPP_STD_VER >= 11
-
#if _LIBCPP_STD_VER >= 14
template <class _CharT>
diff --git a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
index 0e437d0a24308..bd1611fb0a9cc 100644
--- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
+++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
@@ -17,6 +17,7 @@ endif()
set(SOURCES
abi_tag_on_virtual.cpp
hide_from_abi.cpp
+ proper_version_checks.cpp
qualify_declval.cpp
robust_against_adl.cpp
uglify_attributes.cpp
diff --git a/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp
index 685d34a86b54a..9ecb41e20a2da 100644
--- a/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp
+++ b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp
@@ -11,8 +11,9 @@
#include "abi_tag_on_virtual.hpp"
#include "hide_from_abi.hpp"
-#include "robust_against_adl.hpp"
+#include "proper_version_checks.hpp"
#include "qualify_declval.hpp"
+#include "robust_against_adl.hpp"
#include "uglify_attributes.hpp"
namespace {
@@ -21,6 +22,7 @@ class LibcxxTestModule : public clang::tidy::ClangTidyModule {
void addCheckFactories(clang::tidy::ClangTidyCheckFactories& check_factories) override {
check_factories.registerCheck<libcpp::abi_tag_on_virtual>("libcpp-avoid-abi-tag-on-virtual");
check_factories.registerCheck<libcpp::hide_from_abi>("libcpp-hide-from-abi");
+ check_factories.registerCheck<libcpp::proper_version_checks>("libcpp-cpp-version-check");
check_factories.registerCheck<libcpp::robust_against_adl_check>("libcpp-robust-against-adl");
check_factories.registerCheck<libcpp::uglify_attributes>("libcpp-uglify-attributes");
check_factories.registerCheck<libcpp::qualify_declval>("libcpp-qualify-declval");
diff --git a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp
new file mode 100644
index 0000000000000..2abc5ceeecfb8
--- /dev/null
+++ b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "proper_version_checks.hpp"
+
+#include <clang/Lex/Lexer.h>
+#include <clang/Lex/PPCallbacks.h>
+#include <clang/Lex/Preprocessor.h>
+
+namespace libcpp {
+namespace {
+class proper_version_checks_callbacks : public clang::PPCallbacks {
+public:
+ proper_version_checks_callbacks(clang::Preprocessor& preprocessor, clang::tidy::ClangTidyCheck& check)
+ : preprocessor_(preprocessor), check_(check) {}
+
+ void If(clang::SourceLocation location, clang::SourceRange condition_range, ConditionValueKind) override {
+ check_condition(location, condition_range);
+ }
+
+ void Elif(clang::SourceLocation location,
+ clang::SourceRange condition_range,
+ ConditionValueKind,
+ clang::SourceLocation if_location) override {
+ check_condition(location, condition_range);
+ }
+
+private:
+ void check_condition(clang::SourceLocation location, clang::SourceRange condition_range) {
+ std::string_view condition = clang::Lexer::getSourceText(
+ clang::CharSourceRange::getTokenRange(condition_range),
+ preprocessor_.getSourceManager(),
+ preprocessor_.getLangOpts());
+ if (preprocessor_.getSourceManager().isInMainFile(location))
+ return;
+
+ if (condition.starts_with("_LIBCPP_STD_VER") && condition.find(">") != std::string_view::npos &&
+ condition.find(">=") == std::string_view::npos)
+ check_.diag(location, "_LIBCPP_STD_VER >= version should be used instead of _LIBCPP_STD_VER > prev_version");
+
+ else if (condition.starts_with("__cplusplus"))
+ check_.diag(location, "Use _LIBCPP_STD_VER instead of __cplusplus to constrain based on the C++ version");
+
+ else if (condition == "_LIBCPP_STD_VER >= 11")
+ check_.diag(location, "_LIBCPP_STD_VER >= 11 is always true. Did you mean '#ifndef _LIBCPP_CXX03_LANG'?");
+
+ else if (condition.starts_with("_LIBCPP_STD_VER >= ") &&
+ std::ranges::none_of(std::array{"14", "17", "20", "23"}, [&](auto val) {
+ return condition.find(val) != std::string_view::npos;
+ }))
+ check_.diag(location, "Not a valid value for _LIBCPP_STD_VER. Use 14, 17, 20 or 23");
+ }
+
+ clang::Preprocessor& preprocessor_;
+ clang::tidy::ClangTidyCheck& check_;
+};
+} // namespace
+
+proper_version_checks::proper_version_checks(llvm::StringRef name, clang::tidy::ClangTidyContext* context)
+ : clang::tidy::ClangTidyCheck(name, context) {}
+
+void proper_version_checks::registerPPCallbacks(
+ const clang::SourceManager& source_manager,
+ clang::Preprocessor* preprocessor,
+ clang::Preprocessor* module_expander) {
+ preprocessor->addPPCallbacks(std::make_unique<proper_version_checks_callbacks>(*preprocessor, *this));
+}
+
+} // namespace libcpp
diff --git a/libcxx/test/tools/clang_tidy_checks/proper_version_checks.hpp b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.hpp
new file mode 100644
index 0000000000000..5c33b9551bf27
--- /dev/null
+++ b/libcxx/test/tools/clang_tidy_checks/proper_version_checks.hpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-tidy/ClangTidyCheck.h"
+
+namespace libcpp {
+class proper_version_checks : public clang::tidy::ClangTidyCheck {
+public:
+ proper_version_checks(llvm::StringRef, clang::tidy::ClangTidyContext*);
+ void registerPPCallbacks(const clang::SourceManager& source_manager,
+ clang::Preprocessor* preprocessor,
+ clang::Preprocessor* module_expander) override;
+};
+} // namespace libcpp
More information about the libcxx-commits
mailing list