[clang-tools-extra] [clang-tidy] add modernize-use-std-numbers (PR #66583)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 16 12:19:33 PDT 2023
https://github.com/5chmidti updated https://github.com/llvm/llvm-project/pull/66583
>From 8f5e9e6024b0db8f251625669adbc5d607da83cb Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Sat, 16 Sep 2023 16:24:13 +0200
Subject: [PATCH 1/3] [clang-tidy] add modernize-use-std-numbers check
This check finds constants and function calls to math functions that can be replaced
with c++20's mathematical constants ('numbers' header) and offers fixit-hints.
Does not match the use of variables or macros with that value and instead, offers a replacement
at the definition of said variables and macros.
---
.../clang-tidy/modernize/CMakeLists.txt | 1 +
.../modernize/ModernizeTidyModule.cpp | 3 +
.../modernize/UseStdNumbersCheck.cpp | 377 ++++++++++++++++++
.../clang-tidy/modernize/UseStdNumbersCheck.h | 37 ++
clang-tools-extra/docs/ReleaseNotes.rst | 6 +
.../docs/clang-tidy/checks/list.rst | 3 +-
.../checks/modernize/use-std-numbers.rst | 25 ++
.../checkers/modernize/use-std-numbers.cpp | 205 ++++++++++
8 files changed, 656 insertions(+), 1 deletion(-)
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 717c400c4790330..d82353d74fbd0d4 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangTidyModernizeModule
MakeSharedCheck.cpp
MakeSmartPtrCheck.cpp
MakeUniqueCheck.cpp
+ UseStdNumbersCheck.cpp
ModernizeTidyModule.cpp
PassByValueCheck.cpp
RawStringLiteralCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 73751cf2705068d..73584e20166f66a 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -18,6 +18,7 @@
#include "MacroToEnumCheck.h"
#include "MakeSharedCheck.h"
#include "MakeUniqueCheck.h"
+#include "UseStdNumbersCheck.h"
#include "PassByValueCheck.h"
#include "RawStringLiteralCheck.h"
#include "RedundantVoidArgCheck.h"
@@ -65,6 +66,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<MacroToEnumCheck>("modernize-macro-to-enum");
CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared");
CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique");
+ CheckFactories.registerCheck<UseStdNumbersCheck>(
+ "modernize-use-std-numbers");
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
CheckFactories.registerCheck<UseStdPrintCheck>("modernize-use-std-print");
CheckFactories.registerCheck<RawStringLiteralCheck>(
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
new file mode 100644
index 000000000000000..c23dc6671013bc3
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
@@ -0,0 +1,377 @@
+//===--- UseStdNumbersCheck.cpp - clang_tidy -------------------------===//
+//
+// 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 "UseStdNumbersCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Token.h"
+#include "clang/Tooling/Transformer/RewriteRule.h"
+#include "clang/Tooling/Transformer/Stencil.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+#include <string>
+
+namespace {
+using namespace clang::ast_matchers;
+using clang::ast_matchers::internal::Matcher;
+using clang::transformer::addInclude;
+using clang::transformer::applyFirst;
+using clang::transformer::ASTEdit;
+using clang::transformer::cat;
+using clang::transformer::changeTo;
+using clang::transformer::edit;
+using clang::transformer::EditGenerator;
+using clang::transformer::flattenVector;
+using clang::transformer::RewriteRuleWith;
+using llvm::StringRef;
+
+constexpr double Pi = 3.141592653589793238462643383279502884197169399;
+constexpr double Euler = 2.718281828459045235360287471352662497757247093;
+constexpr double Phi = 1.618033988749894848204586834365638117720309179;
+constexpr double Egamma = 0.577215664901532860606512090082402431042159335;
+
+constexpr auto DiffThreshold = 0.001;
+
+AST_MATCHER_P2(clang::FloatingLiteral, near, double, Value, double, Threshold) {
+ return std::abs(Node.getValue().convertToDouble() - Value) < Threshold;
+}
+
+// We don't want to match uses of macros, such as
+//
+// auto PiHalved = MY_PI / 2;
+//
+// because a project might use defines for math constants.
+// Instead, the macro definition is matched and the value is exchanged there.
+// Hinting at replacing macro definitions with language constructs is done in
+// another check.
+AST_MATCHER(clang::Expr, isMathMacro) { return Node.getBeginLoc().isMacroID(); }
+
+AST_MATCHER_P(clang::QualType, hasUnqualifiedDesugaredType,
+ Matcher<clang::QualType>, InnerMatcher) {
+ return InnerMatcher.matches(Node->getCanonicalTypeUnqualified(), Finder,
+ Builder);
+}
+
+auto matchMathCall(const StringRef FunctionName,
+ const Matcher<clang::Expr> ArgumentMatcher) {
+ return callExpr(callee(functionDecl(hasName(FunctionName))),
+ hasArgument(0, ignoringImplicit(ArgumentMatcher)));
+}
+
+auto matchSqrt(const Matcher<clang::Expr> ArgumentMatcher) {
+ return matchMathCall("sqrt", ArgumentMatcher);
+}
+
+// 'MatchDeclRefExprOrMacro' is used to differentiate matching expressions where
+// the value of anything used is near 'Val' and matching expressions where we
+// only care about the actual literal.
+// We don't want top-level matches to match a simple DeclRefExpr/macro that was
+// initialized with this value because projects might declare their own
+// constants (e.g. namespaced constants or macros) to be used. We don't want to
+// flag the use of these variables/constants, but modify the definition of the
+// variable or macro.
+//
+// example:
+// const auto e = 2.71828182; // std::numbers::e
+// ^^^^^^^^^^
+// match here
+//
+// auto use = e / 2;
+// ^
+// don't match this as a top-level match, this would create noise
+//
+// auto use2 = log2(e); // std::numbers::log2e
+// ^^^^^^^
+// match here, matcher needs to check the initialization
+// of e to match log2e
+//
+// Therefore, all top-level matcher set MatchDeclRefExprOrMacro to false
+auto matchFloatValueNear(const double Val,
+ const bool MatchDeclRefExprOrMacro = true) {
+ const auto FloatVal = floatLiteral(near(Val, DiffThreshold));
+ if (!MatchDeclRefExprOrMacro) {
+ return expr(unless(isMathMacro()), ignoringImplicit(FloatVal));
+ }
+
+ const auto Dref = declRefExpr(to(varDecl(
+ anyOf(isConstexpr(), varDecl(hasType(qualType(isConstQualified())))),
+ hasInitializer(FloatVal))));
+ return expr(ignoringImplicit(anyOf(FloatVal, Dref)));
+}
+
+auto matchValue(const int64_t ValInt) {
+ const auto Int2 = integerLiteral(equals(ValInt));
+ const auto Float2 = matchFloatValueNear(static_cast<double>(ValInt));
+ const auto Dref = declRefExpr(to(varDecl(
+ anyOf(isConstexpr(), varDecl(hasType(qualType(isConstQualified())))),
+ hasInitializer(expr(ignoringImplicit(anyOf(Int2, Float2)))))));
+ return expr(ignoringImplicit(anyOf(Int2, Float2, Dref)));
+}
+
+auto match1Div(const Matcher<clang::Expr> Match) {
+ return binaryOperator(hasOperatorName("/"), hasLHS(matchValue(1)),
+ hasRHS(ignoringImplicit(Match)));
+}
+
+auto matchEuler() {
+ return expr(
+ anyOf(matchFloatValueNear(Euler), matchMathCall("exp", matchValue(1))));
+}
+auto matchEulerTopLevel() {
+ return expr(anyOf(matchFloatValueNear(Euler, false),
+ matchMathCall("exp", matchValue(1))));
+}
+
+auto matchLog2Euler() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::log2e, false),
+ matchMathCall("log2", matchEuler())));
+}
+
+auto matchLog10Euler() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::log10e, false),
+ matchMathCall("log10", matchEuler())));
+}
+
+auto matchPi() { return matchFloatValueNear(Pi); }
+auto matchPiTopLevel() { return matchFloatValueNear(Pi, false); }
+
+auto matchEgamma() { return matchFloatValueNear(Egamma, false); }
+
+auto matchInvPi() {
+ return expr(
+ anyOf(matchFloatValueNear(llvm::numbers::inv_pi), match1Div(matchPi())));
+}
+
+auto matchInvSqrtPi() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::inv_sqrtpi, false),
+ match1Div(matchSqrt(matchPi()))));
+}
+
+auto matchLn2() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::ln2, false),
+ matchMathCall("log", ignoringImplicit(matchValue(2)))));
+}
+
+auto machterLn10() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::ln10, false),
+ matchMathCall("log", ignoringImplicit(matchValue(10)))));
+}
+
+auto matchSqrt2() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::sqrt2, false),
+ matchSqrt(matchValue(2))));
+}
+
+auto matchSqrt3() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::sqrt3, false),
+ matchSqrt(matchValue(3))));
+}
+
+auto matchInvSqrt3() {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::inv_sqrt3, false),
+ match1Div(matchSqrt(matchValue(3)))));
+}
+
+auto matchPhi() {
+ const auto PhiFormula = binaryOperator(
+ hasOperatorName("/"),
+ hasLHS(parenExpr(has(binaryOperator(
+ hasOperatorName("+"), hasEitherOperand(matchValue(1)),
+ hasEitherOperand(matchMathCall("sqrt", matchValue(5))))))),
+ hasRHS(matchValue(2)));
+ return expr(anyOf(PhiFormula, matchFloatValueNear(Phi)));
+}
+
+EditGenerator
+chainedIfBound(ASTEdit DefaultEdit,
+ llvm::SmallVector<std::pair<StringRef, ASTEdit>, 2> Edits) {
+ return [Edits = std::move(Edits), DefaultEdit = std::move(DefaultEdit)](
+ const MatchFinder::MatchResult &Result) {
+ auto &Map = Result.Nodes.getMap();
+ for (const auto &[Id, EditOfId] : Edits) {
+ if (Map.find(Id) != Map.end()) {
+ return edit(EditOfId)(Result);
+ }
+ }
+ return edit(DefaultEdit)(Result);
+ };
+}
+
+RewriteRuleWith<std::string> makeRule(const Matcher<clang::Stmt> Matcher,
+ const StringRef Constant) {
+ static const auto AddNumbersInclude =
+ addInclude("numbers", clang::transformer::IncludeFormat::Angled);
+
+ const auto DefaultEdit = changeTo(cat("std::numbers::", Constant));
+ const auto FloatEdit = changeTo(cat("std::numbers::", Constant, "_v<float>"));
+ const auto LongDoubleEdit =
+ changeTo(cat("std::numbers::", Constant, "_v<long double>"));
+
+ const auto EditRules = chainedIfBound(
+ DefaultEdit, {{"float", FloatEdit}, {"long double", LongDoubleEdit}});
+
+ return makeRule(
+ expr(Matcher,
+ hasType(qualType(hasCanonicalType(hasUnqualifiedDesugaredType(anyOf(
+ qualType(asString("float")).bind("float"),
+ qualType(asString("double")),
+ qualType(asString("long double")).bind("long double"))))))),
+ flattenVector({edit(AddNumbersInclude), EditRules}),
+ cat("prefer std::numbers math constant"));
+}
+
+/*
+ List of all math constants
+ + e
+ + log2e
+ + log10e
+ + pi
+ + inv_pi
+ + inv_sqrtpi
+ + ln2
+ + ln10
+ + sqrt2
+ + sqrt3
+ + inv_sqrt3
+ + egamma
+ + phi
+*/
+
+RewriteRuleWith<std::string> makeRewriteRule() {
+ return applyFirst({
+ makeRule(matchLog2Euler(), "log2e"),
+ makeRule(matchLog10Euler(), "log10e"),
+ makeRule(matchEulerTopLevel(), "e"),
+ makeRule(matchEgamma(), "egamma"),
+ makeRule(matchInvSqrtPi(), "inv_sqrtpi"),
+ makeRule(matchInvPi(), "inv_pi"),
+ makeRule(matchPiTopLevel(), "pi"),
+ makeRule(matchLn2(), "ln2"),
+ makeRule(machterLn10(), "ln10"),
+ makeRule(matchSqrt2(), "sqrt2"),
+ makeRule(matchInvSqrt3(), "inv_sqrt3"),
+ makeRule(matchSqrt3(), "sqrt3"),
+ makeRule(matchPhi(), "phi"),
+ });
+}
+
+class MathConstantMacroCallback : public clang::PPCallbacks {
+public:
+ explicit MathConstantMacroCallback(
+ clang::tidy::modernize::UseStdNumbersCheck *Check)
+ : Check{Check} {};
+
+ void MacroDefined(const clang::Token & /*MacroNameTok*/,
+ const clang::MacroDirective *MD) override {
+ for (const auto &Tok : MD->getDefinition().getMacroInfo()->tokens()) {
+ if (!Tok.is(clang::tok::numeric_constant)) {
+ continue;
+ }
+
+ const auto Definition =
+ llvm::StringRef{Tok.getLiteralData(), Tok.getLength()};
+ double Value{};
+ Definition.getAsDouble(Value);
+
+ const auto IsNear = [](const auto Lhs, const auto Rhs) {
+ return std::abs(Lhs - Rhs) < DiffThreshold;
+ };
+
+ if (IsNear(Value, llvm::numbers::log2e)) {
+ reportDiag(Tok, "std::numbers::log2e");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::log10e)) {
+ reportDiag(Tok, "std::numbers::log10e");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::e)) {
+ reportDiag(Tok, "std::numbers::e");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::egamma)) {
+ reportDiag(Tok, "std::numbers::egamma");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::inv_sqrtpi)) {
+ reportDiag(Tok, "std::numbers::inv_sqrtpi");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::inv_pi)) {
+ reportDiag(Tok, "std::numbers::inv_pi");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::pi)) {
+ reportDiag(Tok, "std::numbers::pi");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::ln2)) {
+ reportDiag(Tok, "std::numbers::ln2");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::ln10)) {
+ reportDiag(Tok, "std::numbers::ln10");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::sqrt2)) {
+ reportDiag(Tok, "std::numbers::sqrt2");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::inv_sqrt3)) {
+ reportDiag(Tok, "std::numbers::inv_sqrt3");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::sqrt3)) {
+ reportDiag(Tok, "std::numbers::sqrt3");
+ return;
+ }
+ if (IsNear(Value, llvm::numbers::phi)) {
+ reportDiag(Tok, "std::numbers::phi");
+ return;
+ }
+ }
+ }
+
+private:
+ void reportDiag(const clang::Token &Tok, const llvm::StringRef Constant) {
+ Check->diag(Tok.getLocation(), "prefer math constant")
+ << clang::FixItHint::CreateReplacement(
+ clang::SourceRange(Tok.getLocation(), Tok.getLastLoc()),
+ Constant);
+ }
+
+ clang::tidy::modernize::UseStdNumbersCheck *Check{};
+};
+} // namespace
+
+namespace clang::tidy::modernize {
+UseStdNumbersCheck::UseStdNumbersCheck(const StringRef Name,
+ ClangTidyContext *const Context)
+ : TransformerClangTidyCheck(Name, Context) {
+ setRule(makeRewriteRule());
+}
+
+void UseStdNumbersCheck::registerPPCallbacks(const SourceManager &SM,
+ Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) {
+ utils::TransformerClangTidyCheck::registerPPCallbacks(SM, PP,
+ ModuleExpanderPP);
+ PP->addPPCallbacks(std::make_unique<MathConstantMacroCallback>(this));
+}
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
new file mode 100644
index 000000000000000..5598d533a3ea716
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
@@ -0,0 +1,37 @@
+//===--- UseStdNumbersCheck.h - clang-tidy ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H
+
+#include "../utils/TransformerClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Finds constants and function calls to math functions that can be replaced
+/// with c++20's mathematical constants ('numbers' header). Does not match the
+/// use of variables or macros with that value and instead offers a replacement
+/// at the definition of said variables and macros.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-numbers.html
+class UseStdNumbersCheck : public utils::TransformerClangTidyCheck {
+public:
+ UseStdNumbersCheck(StringRef Name, ClangTidyContext *Context);
+
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus20;
+ }
+
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) override;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6d6f51998a01e57..02efc22a7fe164e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -163,6 +163,12 @@ New checks
Flags coroutines that suspend while a lock guard is in scope at the
suspension point.
+- New :doc:`modernize-use-std-numbers
+ <clang-tidy/checks/modernize/use-std-numbers>` check.
+
+ Finds constants and function calls to math functions that can be replaced
+ with c++20's mathematical constants ('numbers' header).
+
- New :doc:`modernize-use-constraints
<clang-tidy/checks/modernize/use-constraints>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 1baabceea06ef48..ae1d541e40387a1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -82,7 +82,7 @@ Clang-Tidy Checks
:doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
:doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
:doc:`bugprone-branch-clone <bugprone/branch-clone>`,
- :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`, "Yes"
+ :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
:doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
@@ -290,6 +290,7 @@ Clang-Tidy Checks
:doc:`modernize-use-noexcept <modernize/use-noexcept>`, "Yes"
:doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
:doc:`modernize-use-override <modernize/use-override>`, "Yes"
+ :doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
:doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes"
:doc:`modernize-use-trailing-return-type <modernize/use-trailing-return-type>`, "Yes"
:doc:`modernize-use-transparent-functors <modernize/use-transparent-functors>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
new file mode 100644
index 000000000000000..7911f2f7f857b95
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - modernize-use-std-numbers
+
+modernize-use-std-numbers
+=========================
+
+This check finds constants and function calls to math functions that can be replaced
+with c++20's mathematical constants ('numbers' header) and offers fixit-hints.
+Does not match the use of variables or macros with that value and instead, offers a replacement
+at the definition of said variables and macros.
+
+.. code-block:: c++
+ double sqrt(double);
+ double log(double);
+
+ #define MY_PI 3.1415926 // #define MY_PI std::numbers::pi
+
+ void foo() {
+ const double Pi = 3.141592653589; // const double Pi = std::numbers::pi
+ const auto Use = Pi / 2; // no match for Pi
+ static constexpr double Euler = 2.7182818; // static constexpr double Euler = std::numbers::e;
+
+ log2(exp(1)); // std::numbers::log2e;
+ log2(Euler); // std::numbers::log2e;
+ 1 / sqrt(MY_PI); // std::numbers::inv_sqrtpi;
+ }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
new file mode 100644
index 000000000000000..2ba0525f38306df
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
@@ -0,0 +1,205 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-std-numbers %t
+
+// CHECK-FIXES: #include <numbers>
+
+namespace bar {
+ double sqrt(double Arg);
+ float sqrt(float Arg);
+ template <typename T>
+ auto sqrt(T val) { return sqrt(static_cast<double>(val)); }
+
+ static constexpr double e = 2.718281828459045235360287471352662497757247093;
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double e = std::numbers::e;
+}
+
+double exp(double Arg);
+double log(double Arg);
+double log2(double Arg);
+double log10(double Arg);
+
+template<typename T>
+void sink(T&&) { }
+
+#define MY_PI 3.1415926
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: prefer math constant [modernize-use-std-numbers]
+// CHECK-FIXES: #define MY_PI std::numbers::pi
+#define MY_PI2 static_cast<float>(3.1415926)
+// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: prefer math constant [modernize-use-std-numbers]
+// CHECK-FIXES: #define MY_PI2 static_cast<float>(std::numbers::pi)
+
+#define INV_SQRT3 1 / bar::sqrt(3)
+
+void foo(){
+ static constexpr double Pi = 3.1415926;
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double Pi = std::numbers::pi;
+
+ static constexpr double Euler = 2.7182818;
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double Euler = std::numbers::e;
+
+ static constexpr double Phi = 1.6180339;
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double Phi = std::numbers::phi;
+
+ static constexpr double PiCopy = Pi;
+ static constexpr double PiDefine = MY_PI;
+
+ // not close enough to match value (DiffThreshold)
+ static constexpr double Pi2 = 3.14;
+ static constexpr double Euler2 = 2.71;
+ static constexpr double Phi2 = 1.61;
+
+ static constexpr double Pi3 = 3.1415926L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double Pi3 = std::numbers::pi;
+
+ static constexpr double Euler3 = 2.7182818L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double Euler3 = std::numbers::e;
+
+ static constexpr double Phi3 = 1.6180339L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr double Phi3 = std::numbers::phi;
+
+ static constexpr long double Pi4 = 3.1415926L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr long double Pi4 = std::numbers::pi_v<long double>;
+
+ static constexpr long double Euler4 = 2.7182818L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr long double Euler4 = std::numbers::e_v<long double>;
+
+ static constexpr long double Phi4 = 1.6180339L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: static constexpr long double Phi4 = std::numbers::phi_v<long double>;
+
+ using my_float = const float;
+ static constexpr my_float Actually2MyFloat = 2;
+ bar::sqrt(Actually2MyFloat);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt2_v<float>;
+
+ constexpr static auto One = 1;
+ constexpr static auto Two = 2;
+
+ bar::sqrt(2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt2;
+
+ bar::sqrt(Two);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt2;
+
+ bar::sqrt(2.0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt2;
+
+ auto Not2 = 2;
+ Not2 = 42;
+ bar::sqrt(Not2);
+
+ const auto Actually2 = 2;
+ bar::sqrt(Actually2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt2;
+
+ exp(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::e;
+
+ exp(One);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::e;
+
+ exp(1.00000000000001);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::e;
+
+ log2(exp(1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::log2e;
+
+ log2(Euler);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::log2e;
+
+ log2(bar::e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::log2e;
+
+ auto log2e = 1.4426950;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: auto log2e = std::numbers::log2e;
+
+ log10(exp(1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::log10e;
+
+ log10(Euler);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::log10e;
+
+ log10(bar::e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::log10e;
+
+ auto log10e = .434294;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: auto log10e = std::numbers::log10e;
+
+ auto egamma = 0.5772156 * 42;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: auto egamma = std::numbers::egamma * 42;
+
+ sink(1 / Pi);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: sink(std::numbers::inv_pi);
+
+ sink(1 / bar::sqrt(Pi));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: sink(std::numbers::inv_sqrtpi);
+
+ sink(1 / bar::sqrt(MY_PI));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: sink(std::numbers::inv_sqrtpi);
+
+
+ log(2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::ln2;
+
+ log(10);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::ln10;
+
+ bar::sqrt(2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt2;
+
+ sink(1 / bar::sqrt(3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: sink(std::numbers::inv_sqrt3);
+
+ bar::sqrt(3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: std::numbers::sqrt3;
+
+ auto phi = 1.6180339;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: auto phi = std::numbers::phi;
+
+ sink((42 + bar::sqrt(5)) / 2);
+
+ sink((1 + bar::sqrt(5)) / 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: sink(std::numbers::phi);
+
+ sink((bar::sqrt(5.0F) + 1) / 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer math constant [modernize-use-std-numbers]
+ // CHECK-FIXES: sink(std::numbers::phi_v<float>);
+}
>From c52e8a625e5b098054ce24a5b9aa309ce4a290e8 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Sat, 16 Sep 2023 21:13:56 +0200
Subject: [PATCH 2/3] add "Yes" back to list.rst that mysteriously disappeared
for unrelated check
---
clang-tools-extra/docs/clang-tidy/checks/list.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index ae1d541e40387a1..dd90cd8ae92b424 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -82,7 +82,7 @@ Clang-Tidy Checks
:doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
:doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
:doc:`bugprone-branch-clone <bugprone/branch-clone>`,
- :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
+ :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`, "Yes"
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
:doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
>From 3fd29e448efb12d4d06a930bfcc045990b8ad02f Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Sat, 16 Sep 2023 21:19:10 +0200
Subject: [PATCH 3/3] fix lexicographical ordering in some places after rename
---
clang-tools-extra/clang-tidy/modernize/CMakeLists.txt | 2 +-
.../clang-tidy/modernize/ModernizeTidyModule.cpp | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++-----
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index d82353d74fbd0d4..b254d340c4e854a 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -16,7 +16,6 @@ add_clang_library(clangTidyModernizeModule
MakeSharedCheck.cpp
MakeSmartPtrCheck.cpp
MakeUniqueCheck.cpp
- UseStdNumbersCheck.cpp
ModernizeTidyModule.cpp
PassByValueCheck.cpp
RawStringLiteralCheck.cpp
@@ -39,6 +38,7 @@ add_clang_library(clangTidyModernizeModule
UseNoexceptCheck.cpp
UseNullptrCheck.cpp
UseOverrideCheck.cpp
+ UseStdNumbersCheck.cpp
UseStdPrintCheck.cpp
UseTrailingReturnTypeCheck.cpp
UseTransparentFunctorsCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 73584e20166f66a..4f33db5b741a7ef 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -18,7 +18,6 @@
#include "MacroToEnumCheck.h"
#include "MakeSharedCheck.h"
#include "MakeUniqueCheck.h"
-#include "UseStdNumbersCheck.h"
#include "PassByValueCheck.h"
#include "RawStringLiteralCheck.h"
#include "RedundantVoidArgCheck.h"
@@ -40,6 +39,7 @@
#include "UseNoexceptCheck.h"
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
+#include "UseStdNumbersCheck.h"
#include "UseStdPrintCheck.h"
#include "UseTrailingReturnTypeCheck.h"
#include "UseTransparentFunctorsCheck.h"
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 02efc22a7fe164e..9fabdda3619ed82 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -163,17 +163,17 @@ New checks
Flags coroutines that suspend while a lock guard is in scope at the
suspension point.
+- New :doc:`modernize-use-constraints
+ <clang-tidy/checks/modernize/use-constraints>` check.
+
+ Replace ``enable_if`` with C++20 requires clauses.
+
- New :doc:`modernize-use-std-numbers
<clang-tidy/checks/modernize/use-std-numbers>` check.
Finds constants and function calls to math functions that can be replaced
with c++20's mathematical constants ('numbers' header).
-- New :doc:`modernize-use-constraints
- <clang-tidy/checks/modernize/use-constraints>` check.
-
- Replace ``enable_if`` with C++20 requires clauses.
-
- New :doc:`performance-enum-size
<clang-tidy/checks/performance/enum-size>` check.
More information about the cfe-commits
mailing list