[clang-tools-extra] 0eb7d53 - [clang-tidy] add modernize-use-std-numbers (#66583)
Piotr Zegar via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 6 12:51:01 PST 2023
Author: Julian Schmidt
Date: 2023-12-06T20:49:14Z
New Revision: 0eb7d53cfc48f2e9287bb116415620618ca850b7
URL: https://github.com/llvm/llvm-project/commit/0eb7d53cfc48f2e9287bb116415620618ca850b7
DIFF: https://github.com/llvm/llvm-project/commit/0eb7d53cfc48f2e9287bb116415620618ca850b7.diff
LOG: [clang-tidy] add modernize-use-std-numbers (#66583)
Finds constants and function calls to math functions that can be
replaced with c++20's mathematical constants from the 'numbers'
header and offers fix-it hints.
Does not match the use of variables with that value, and instead,
offers a replacement at the definition of those variables.
Added:
clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
Modified:
clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c40065358d2dc..28ca52f46943a 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -39,6 +39,7 @@ add_clang_library(clangTidyModernizeModule
UseNullptrCheck.cpp
UseOverrideCheck.cpp
UseStartsEndsWithCheck.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 e994ffd2a75c8..654f4bd0c6ba4 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -40,6 +40,7 @@
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
#include "UseStartsEndsWithCheck.h"
+#include "UseStdNumbersCheck.h"
#include "UseStdPrintCheck.h"
#include "UseTrailingReturnTypeCheck.h"
#include "UseTransparentFunctorsCheck.h"
@@ -69,6 +70,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
CheckFactories.registerCheck<UseStartsEndsWithCheck>(
"modernize-use-starts-ends-with");
+ CheckFactories.registerCheck<UseStdNumbersCheck>(
+ "modernize-use-std-numbers");
CheckFactories.registerCheck<UseStdPrintCheck>("modernize-use-std-print");
CheckFactories.registerCheck<RawStringLiteralCheck>(
"modernize-raw-string-literal");
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 0000000000000..1f2b034713ecf
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
@@ -0,0 +1,449 @@
+//===--- 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 "../ClangTidyDiagnosticConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include <array>
+#include <cstdint>
+#include <cstdlib>
+#include <initializer_list>
+#include <string>
+#include <tuple>
+#include <utility>
+
+namespace {
+using namespace clang::ast_matchers;
+using clang::ast_matchers::internal::Matcher;
+using llvm::StringRef;
+
+AST_MATCHER_P2(clang::FloatingLiteral, near, double, Value, double,
+ DiffThreshold) {
+ return std::abs(Node.getValueAsApproximateDouble() - Value) < DiffThreshold;
+}
+
+AST_MATCHER_P(clang::QualType, hasCanonicalTypeUnqualified,
+ Matcher<clang::QualType>, InnerMatcher) {
+ return !Node.isNull() &&
+ InnerMatcher.matches(Node->getCanonicalTypeUnqualified(), Finder,
+ Builder);
+}
+
+AST_MATCHER(clang::QualType, isArithmetic) {
+ return !Node.isNull() && Node->isArithmeticType();
+}
+AST_MATCHER(clang::QualType, isFloating) {
+ return !Node.isNull() && Node->isFloatingType();
+}
+
+AST_MATCHER_P(clang::Expr, anyOfExhaustive,
+ llvm::ArrayRef<Matcher<clang::Stmt>>, Exprs) {
+ bool FoundMatch = false;
+ for (const auto &InnerMatcher : Exprs) {
+ clang::ast_matchers::internal::BoundNodesTreeBuilder Result = *Builder;
+ if (InnerMatcher.matches(Node, Finder, &Result)) {
+ *Builder = std::move(Result);
+ FoundMatch = true;
+ }
+ }
+ return FoundMatch;
+}
+
+// Using this struct to store the 'DiffThreshold' config value to create the
+// matchers without the need to pass 'DiffThreshold' into every matcher.
+// 'DiffThreshold' is needed in the 'near' matcher, which is used for matching
+// the literal of every constant and for formulas' subexpressions that look at
+// literals.
+struct MatchBuilder {
+ auto
+ ignoreParenAndArithmeticCasting(const Matcher<clang::Expr> Matcher) const {
+ return expr(hasType(qualType(isArithmetic())), ignoringParenCasts(Matcher));
+ }
+
+ auto ignoreParenAndFloatingCasting(const Matcher<clang::Expr> Matcher) const {
+ return expr(hasType(qualType(isFloating())), ignoringParenCasts(Matcher));
+ }
+
+ auto matchMathCall(const StringRef FunctionName,
+ const Matcher<clang::Expr> ArgumentMatcher) const {
+ return expr(ignoreParenAndFloatingCasting(
+ callExpr(callee(functionDecl(hasName(FunctionName),
+ hasParameter(0, hasType(isArithmetic())))),
+ hasArgument(0, ArgumentMatcher))));
+ }
+
+ auto matchSqrt(const Matcher<clang::Expr> ArgumentMatcher) const {
+ return matchMathCall("sqrt", ArgumentMatcher);
+ }
+
+ // Used for top-level matchers (i.e. the match that replaces Val with its
+ // constant).
+ //
+ // E.g. The matcher of `std::numbers::pi` uses this matcher to look for
+ // floatLiterals that have the value of pi.
+ //
+ // If the match is for a top-level match, we only care about the literal.
+ auto matchFloatLiteralNear(const StringRef Constant, const double Val) const {
+ return expr(ignoreParenAndFloatingCasting(
+ floatLiteral(near(Val, DiffThreshold)).bind(Constant)));
+ }
+
+ // Used for non-top-level matchers (i.e. matchers that are used as inner
+ // matchers for top-level matchers).
+ //
+ // E.g.: The matcher of `std::numbers::log2e` uses this matcher to check if
+ // `e` of `log2(e)` is declared constant and initialized with the value for
+ // eulers number.
+ //
+ // Here, we do care about literals and about DeclRefExprs to variable
+ // declarations that are constant and initialized with `Val`. This allows
+ // top-level matchers to see through declared constants for their inner
+ // matches like the `std::numbers::log2e` matcher.
+ auto matchFloatValueNear(const double Val) const {
+ const auto Float = floatLiteral(near(Val, DiffThreshold));
+
+ const auto Dref = declRefExpr(
+ to(varDecl(hasType(qualType(isConstQualified(), isFloating())),
+ hasInitializer(ignoreParenAndFloatingCasting(Float)))));
+ return expr(ignoreParenAndFloatingCasting(anyOf(Float, Dref)));
+ }
+
+ auto matchValue(const int64_t ValInt) const {
+ const auto Int =
+ expr(ignoreParenAndArithmeticCasting(integerLiteral(equals(ValInt))));
+ const auto Float = expr(ignoreParenAndFloatingCasting(
+ matchFloatValueNear(static_cast<double>(ValInt))));
+ const auto Dref = declRefExpr(to(varDecl(
+ hasType(qualType(isConstQualified(), isArithmetic())),
+ hasInitializer(expr(anyOf(ignoringImplicit(Int),
+ ignoreParenAndFloatingCasting(Float)))))));
+ return expr(anyOf(Int, Float, Dref));
+ }
+
+ auto match1Div(const Matcher<clang::Expr> Match) const {
+ return binaryOperator(hasOperatorName("/"), hasLHS(matchValue(1)),
+ hasRHS(Match));
+ }
+
+ auto matchEuler() const {
+ return expr(anyOf(matchFloatValueNear(llvm::numbers::e),
+ matchMathCall("exp", matchValue(1))));
+ }
+ auto matchEulerTopLevel() const {
+ return expr(anyOf(matchFloatLiteralNear("e_literal", llvm::numbers::e),
+ matchMathCall("exp", matchValue(1)).bind("e_pattern")))
+ .bind("e");
+ }
+
+ auto matchLog2Euler() const {
+ return expr(
+ anyOf(
+ matchFloatLiteralNear("log2e_literal", llvm::numbers::log2e),
+ matchMathCall("log2", matchEuler()).bind("log2e_pattern")))
+ .bind("log2e");
+ }
+
+ auto matchLog10Euler() const {
+ return expr(
+ anyOf(
+ matchFloatLiteralNear("log10e_literal",
+ llvm::numbers::log10e),
+ matchMathCall("log10", matchEuler()).bind("log10e_pattern")))
+ .bind("log10e");
+ }
+
+ auto matchPi() const { return matchFloatValueNear(llvm::numbers::pi); }
+ auto matchPiTopLevel() const {
+ return matchFloatLiteralNear("pi_literal", llvm::numbers::pi).bind("pi");
+ }
+
+ auto matchEgamma() const {
+ return matchFloatLiteralNear("egamma_literal", llvm::numbers::egamma)
+ .bind("egamma");
+ }
+
+ auto matchInvPi() const {
+ return expr(anyOf(matchFloatLiteralNear("inv_pi_literal",
+ llvm::numbers::inv_pi),
+ match1Div(matchPi()).bind("inv_pi_pattern")))
+ .bind("inv_pi");
+ }
+
+ auto matchInvSqrtPi() const {
+ return expr(anyOf(
+ matchFloatLiteralNear("inv_sqrtpi_literal",
+ llvm::numbers::inv_sqrtpi),
+ match1Div(matchSqrt(matchPi())).bind("inv_sqrtpi_pattern")))
+ .bind("inv_sqrtpi");
+ }
+
+ auto matchLn2() const {
+ return expr(anyOf(matchFloatLiteralNear("ln2_literal", llvm::numbers::ln2),
+ matchMathCall("log", matchValue(2)).bind("ln2_pattern")))
+ .bind("ln2");
+ }
+
+ auto machterLn10() const {
+ return expr(
+ anyOf(matchFloatLiteralNear("ln10_literal", llvm::numbers::ln10),
+ matchMathCall("log", matchValue(10)).bind("ln10_pattern")))
+ .bind("ln10");
+ }
+
+ auto matchSqrt2() const {
+ return expr(anyOf(matchFloatLiteralNear("sqrt2_literal",
+ llvm::numbers::sqrt2),
+ matchSqrt(matchValue(2)).bind("sqrt2_pattern")))
+ .bind("sqrt2");
+ }
+
+ auto matchSqrt3() const {
+ return expr(anyOf(matchFloatLiteralNear("sqrt3_literal",
+ llvm::numbers::sqrt3),
+ matchSqrt(matchValue(3)).bind("sqrt3_pattern")))
+ .bind("sqrt3");
+ }
+
+ auto matchInvSqrt3() const {
+ return expr(anyOf(matchFloatLiteralNear("inv_sqrt3_literal",
+ llvm::numbers::inv_sqrt3),
+ match1Div(matchSqrt(matchValue(3)))
+ .bind("inv_sqrt3_pattern")))
+ .bind("inv_sqrt3");
+ }
+
+ auto matchPhi() const {
+ const auto PhiFormula = binaryOperator(
+ hasOperatorName("/"),
+ hasLHS(binaryOperator(
+ hasOperatorName("+"), hasEitherOperand(matchValue(1)),
+ hasEitherOperand(matchMathCall("sqrt", matchValue(5))))),
+ hasRHS(matchValue(2)));
+ return expr(anyOf(PhiFormula.bind("phi_pattern"),
+ matchFloatLiteralNear("phi_literal", llvm::numbers::phi)))
+ .bind("phi");
+ }
+
+ double DiffThreshold;
+};
+
+std::string getCode(const StringRef Constant, const bool IsFloat,
+ const bool IsLongDouble) {
+ if (IsFloat) {
+ return ("std::numbers::" + Constant + "_v<float>").str();
+ }
+ if (IsLongDouble) {
+ return ("std::numbers::" + Constant + "_v<long double>").str();
+ }
+ return ("std::numbers::" + Constant).str();
+}
+
+bool isRangeOfCompleteMacro(const clang::SourceRange &Range,
+ const clang::SourceManager &SM,
+ const clang::LangOptions &LO) {
+ if (!Range.getBegin().isMacroID()) {
+ return false;
+ }
+ if (!clang::Lexer::isAtStartOfMacroExpansion(Range.getBegin(), SM, LO)) {
+ return false;
+ }
+
+ if (!Range.getEnd().isMacroID()) {
+ return false;
+ }
+
+ if (!clang::Lexer::isAtEndOfMacroExpansion(Range.getEnd(), SM, LO)) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace clang::tidy::modernize {
+UseStdNumbersCheck::UseStdNumbersCheck(const StringRef Name,
+ ClangTidyContext *const Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()),
+ DiffThresholdString{Options.get("DiffThreshold", "0.001")} {
+ if (DiffThresholdString.getAsDouble(DiffThreshold)) {
+ configurationDiag(
+ "Invalid DiffThreshold config value: '%0', expected a double")
+ << DiffThresholdString;
+ DiffThreshold = 0.001;
+ }
+}
+
+void UseStdNumbersCheck::registerMatchers(MatchFinder *const Finder) {
+ const auto Matches = MatchBuilder{DiffThreshold};
+ static const auto ConstantMatchers = {
+ Matches.matchLog2Euler(), Matches.matchLog10Euler(),
+ Matches.matchEulerTopLevel(), Matches.matchEgamma(),
+ Matches.matchInvSqrtPi(), Matches.matchInvPi(),
+ Matches.matchPiTopLevel(), Matches.matchLn2(),
+ Matches.machterLn10(), Matches.matchSqrt2(),
+ Matches.matchInvSqrt3(), Matches.matchSqrt3(),
+ Matches.matchPhi(),
+ };
+
+ Finder->addMatcher(
+ expr(
+ anyOfExhaustive(ConstantMatchers),
+ unless(hasParent(explicitCastExpr(hasDestinationType(isFloating())))),
+ hasType(qualType(hasCanonicalTypeUnqualified(
+ anyOf(qualType(asString("float")).bind("float"),
+ qualType(asString("double")),
+ qualType(asString("long double")).bind("long double")))))),
+ this);
+}
+
+void UseStdNumbersCheck::check(const MatchFinder::MatchResult &Result) {
+ /*
+ List of all math constants in the `<numbers>` header
+ + e
+ + log2e
+ + log10e
+ + pi
+ + inv_pi
+ + inv_sqrtpi
+ + ln2
+ + ln10
+ + sqrt2
+ + sqrt3
+ + inv_sqrt3
+ + egamma
+ + phi
+ */
+
+ // The ordering determines what constants are looked at first.
+ // E.g. look at 'inv_sqrt3' before 'sqrt3' to be able to replace the larger
+ // expression
+ constexpr auto Constants = std::array<std::pair<StringRef, double>, 13>{
+ std::pair{StringRef{"log2e"}, llvm::numbers::log2e},
+ std::pair{StringRef{"log10e"}, llvm::numbers::log10e},
+ std::pair{StringRef{"e"}, llvm::numbers::e},
+ std::pair{StringRef{"egamma"}, llvm::numbers::egamma},
+ std::pair{StringRef{"inv_sqrtpi"}, llvm::numbers::inv_sqrtpi},
+ std::pair{StringRef{"inv_pi"}, llvm::numbers::inv_pi},
+ std::pair{StringRef{"pi"}, llvm::numbers::pi},
+ std::pair{StringRef{"ln2"}, llvm::numbers::ln2},
+ std::pair{StringRef{"ln10"}, llvm::numbers::ln10},
+ std::pair{StringRef{"sqrt2"}, llvm::numbers::sqrt2},
+ std::pair{StringRef{"inv_sqrt3"}, llvm::numbers::inv_sqrt3},
+ std::pair{StringRef{"sqrt3"}, llvm::numbers::sqrt3},
+ std::pair{StringRef{"phi"}, llvm::numbers::phi},
+ };
+
+ auto MatchedLiterals =
+ llvm::SmallVector<std::tuple<std::string, double, const Expr *>>{};
+
+ const auto &SM = *Result.SourceManager;
+ const auto &LO = Result.Context->getLangOpts();
+
+ const auto IsFloat = Result.Nodes.getNodeAs<QualType>("float") != nullptr;
+ const auto IsLongDouble =
+ Result.Nodes.getNodeAs<QualType>("long double") != nullptr;
+
+ for (const auto &[ConstantName, ConstantValue] : Constants) {
+ const auto *const Match = Result.Nodes.getNodeAs<Expr>(ConstantName);
+ if (Match == nullptr) {
+ continue;
+ }
+
+ const auto Range = Match->getSourceRange();
+
+ const auto IsMacro = Range.getBegin().isMacroID();
+
+ // We do not want to emit a diagnostic when we are matching a macro, but the
+ // match inside of the macro does not cover the whole macro.
+ if (IsMacro && !isRangeOfCompleteMacro(Range, SM, LO)) {
+ continue;
+ }
+
+ if (const auto PatternBindString = (ConstantName + "_pattern").str();
+ Result.Nodes.getNodeAs<Expr>(PatternBindString) != nullptr) {
+ const auto Code = getCode(ConstantName, IsFloat, IsLongDouble);
+ diag(Range.getBegin(), "prefer '%0' to this %select{formula|macro}1")
+ << Code << IsMacro << FixItHint::CreateReplacement(Range, Code);
+ return;
+ }
+
+ const auto LiteralBindString = (ConstantName + "_literal").str();
+ if (const auto *const Literal =
+ Result.Nodes.getNodeAs<FloatingLiteral>(LiteralBindString)) {
+ MatchedLiterals.emplace_back(
+ ConstantName,
+ std::abs(Literal->getValueAsApproximateDouble() - ConstantValue),
+ Match);
+ }
+ }
+
+ // We may have had no matches with literals, but a match with a pattern that
+ // was a part of a macro which was therefore skipped.
+ if (MatchedLiterals.empty()) {
+ return;
+ }
+
+ llvm::sort(MatchedLiterals, [](const auto &LHS, const auto &RHS) {
+ return std::get<1>(LHS) < std::get<1>(RHS);
+ });
+
+ const auto &[Constant, Diff, Node] = MatchedLiterals.front();
+
+ const auto Range = Node->getSourceRange();
+ const auto IsMacro = Range.getBegin().isMacroID();
+
+ // We do not want to emit a diagnostic when we are matching a macro, but the
+ // match inside of the macro does not cover the whole macro.
+ if (IsMacro && !isRangeOfCompleteMacro(Range, SM, LO)) {
+ return;
+ }
+
+ const auto Code = getCode(Constant, IsFloat, IsLongDouble);
+ diag(Range.getBegin(),
+ "prefer '%0' to this %select{literal|macro}1,
diff ers by '%2'")
+ << Code << IsMacro << llvm::formatv("{0:e2}", Diff).str()
+ << FixItHint::CreateReplacement(Range, Code)
+ << IncludeInserter.createIncludeInsertion(
+ Result.SourceManager->getFileID(Range.getBegin()), "<numbers>");
+}
+
+void UseStdNumbersCheck::registerPPCallbacks(
+ const SourceManager &SM, Preprocessor *const PP,
+ Preprocessor *const ModuleExpanderPP) {
+ IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdNumbersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+ Options.store(Opts, "DiffThreshold", DiffThresholdString);
+}
+} // 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 0000000000000..05fc5ada14b87
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.h
@@ -0,0 +1,49 @@
+//===--- 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 "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang::tidy::modernize {
+
+/// Finds constants and function calls to math functions that can be replaced
+/// with c++20's mathematical constants from the ``numbers`` header and
+/// offers fix-it hints.
+/// Does not match the use of variables with that value, and instead,
+/// offers a replacement at the definition of those variables.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-numbers.html
+class UseStdNumbersCheck : public ClangTidyCheck {
+public:
+ UseStdNumbersCheck(StringRef Name, ClangTidyContext *Context);
+
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus20;
+ }
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+
+private:
+ utils::IncludeInserter IncludeInserter;
+ StringRef DiffThresholdString;
+ double DiffThreshold;
+};
+
+} // 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 4ff4494cef562..9262f9bbfe62a 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -193,6 +193,13 @@ New checks
replacing with ``starts_with`` when the method exists in the class. Notably,
this will work with ``std::string`` and ``std::string_view``.
+- 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 from the ``numbers`` header and
+ offers fix-it hints.
+
- New :doc:`performance-enum-size
<clang-tidy/checks/performance/enum-size>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index df2d5d15238d6..e6c02fe48fbf8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -293,6 +293,7 @@ Clang-Tidy Checks
:doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
:doc:`modernize-use-override <modernize/use-override>`, "Yes"
:doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, "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 0000000000000..207e9c00e74ba
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-numbers.rst
@@ -0,0 +1,74 @@
+.. title:: clang-tidy - modernize-use-std-numbers
+
+modernize-use-std-numbers
+=========================
+
+Finds constants and function calls to math functions that can be replaced
+with C++20's mathematical constants from the ``numbers`` header and offers
+fix-it hints.
+Does not match the use of variables with that value, and instead,
+offers a replacement for the definition of those variables.
+Function calls that match the pattern of how the constant is calculated are
+matched and replaced with the ``std::numbers`` constant.
+The use of macros gets replaced with the corresponding ``std::numbers``
+constant, instead of changing the macro definition.
+
+The following list of constants from the ``numbers`` header are supported:
+
+* ``e``
+* ``log2e``
+* ``log10e``
+* ``pi``
+* ``inv_pi``
+* ``inv_sqrtpi``
+* ``ln2``
+* ``ln10``
+* ``sqrt2``
+* ``sqrt3``
+* ``inv_sqrt3``
+* ``egamma``
+* ``phi``
+
+The list currently includes all constants as of C++20.
+
+The replacements use the type of the matched constant and can remove explicit
+casts, i.e., switching between ``std::numbers::e``,
+``std::numbers::e_v<float>`` and ``std::numbers::e_v<long double>`` where
+appropriate.
+
+.. code-block:: c++
+
+ double sqrt(double);
+ double log2(double);
+ void sink(auto&&) {}
+ void floatSink(float);
+
+ #define MY_PI 3.1415926
+
+ 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;
+ sink(MY_PI); // sink(std::numbers::pi);
+ floatSink(MY_PI); // floatSink(std::numbers::pi);
+ floatSink(static_cast<float>(MY_PI)); // floatSink(std::numbers::pi_v<float>);
+ }
+
+Options
+-------
+
+.. option:: DiffThreshold
+
+ A floating point value that sets the detection threshold for when literals
+ match a constant. A literal matches a constant if
+ ``abs(literal - constant) < DiffThreshold`` evaluates to ``true``. Default
+ is `0.001`.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
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 0000000000000..6c5762da5e2e8
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-numbers.cpp
@@ -0,0 +1,493 @@
+// RUN: %check_clang_tidy -check-suffix=ALL -std=c++20 %s modernize-use-std-numbers %t
+// RUN: %check_clang_tidy -check-suffix=ALL,IMPRECISE -std=c++20 %s modernize-use-std-numbers %t -- -config="{CheckOptions: { modernize-use-std-numbers.DiffThreshold: 0.01 }}"
+
+// CHECK-FIXES-ALL: #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-ALL: :[[@LINE-1]]:33: warning: prefer 'std::numbers::e' to this literal,
diff ers by '0.00e+00' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double e = std::numbers::e;
+}
+
+double exp(double Arg);
+double log(double Arg);
+
+double log2(double Arg);
+float log2(float Arg);
+template <typename T>
+auto log2(T val) { return log2(static_cast<double>(val)); }
+
+double log10(double Arg);
+
+template<typename T>
+void sink(T&&) { }
+
+void floatSink(float) {}
+
+#define MY_PI 3.1415926
+
+#define INV_SQRT3 1 / bar::sqrt(3)
+#define NOT_INV_SQRT3 1 / bar::sqrt(3) + 1
+
+using my_double = double;
+using my_float = float;
+
+void foo(){
+ static constexpr double Pi = 3.1415926;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:34: warning: prefer 'std::numbers::pi' to this literal,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double Pi = std::numbers::pi;
+
+ static constexpr double Euler = 2.7182818;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:37: warning: prefer 'std::numbers::e' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double Euler = std::numbers::e;
+
+ static constexpr double Phi = 1.6180339;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:35: warning: prefer 'std::numbers::phi' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double Phi = std::numbers::phi;
+
+ static constexpr double PiCopy = Pi;
+ static constexpr double PiDefineFromMacro = MY_PI;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:49: warning: prefer 'std::numbers::pi' to this macro,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double PiDefineFromMacro = std::numbers::pi;
+
+ static constexpr double Pi2 = 3.14;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:35: warning: prefer 'std::numbers::pi' to this literal,
diff ers by '1.59e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: static constexpr double Pi2 = std::numbers::pi;
+ static constexpr double Euler2 = 2.71;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:38: warning: prefer 'std::numbers::e' to this literal,
diff ers by '8.28e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: static constexpr double Euler2 = std::numbers::e;
+ static constexpr double Phi2 = 1.61;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:36: warning: prefer 'std::numbers::phi' to this literal,
diff ers by '8.03e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: static constexpr double Phi2 = std::numbers::phi;
+
+ static constexpr double Pi3 = 3.1415926L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:35: warning: prefer 'std::numbers::pi_v<long double>' to this literal,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double Pi3 = std::numbers::pi_v<long double>;
+
+ static constexpr double Euler3 = 2.7182818L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:38: warning: prefer 'std::numbers::e_v<long double>' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double Euler3 = std::numbers::e_v<long double>;
+
+ static constexpr double Phi3 = 1.6180339L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:36: warning: prefer 'std::numbers::phi_v<long double>' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double Phi3 = std::numbers::phi_v<long double>;
+
+ static constexpr long double Pi4 = 3.1415926L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:40: warning: prefer 'std::numbers::pi_v<long double>' to this literal,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr long double Pi4 = std::numbers::pi_v<long double>;
+
+ static constexpr long double Euler4 = 2.7182818L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:43: warning: prefer 'std::numbers::e_v<long double>' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr long double Euler4 = std::numbers::e_v<long double>;
+
+ static constexpr long double Phi4 = 1.6180339L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:41: warning: prefer 'std::numbers::phi_v<long double>' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr long double Phi4 = std::numbers::phi_v<long double>;
+
+ static constexpr my_double Euler5 = 2.7182818;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:41: warning: prefer 'std::numbers::e' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr my_double Euler5 = std::numbers::e;
+
+ static constexpr my_float Euler6 = 2.7182818;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:40: warning: prefer 'std::numbers::e' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr my_float Euler6 = std::numbers::e;
+
+ static constexpr int NotEuler7 = 2.7182818;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:38: warning: prefer 'std::numbers::e' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr int NotEuler7 = std::numbers::e;
+
+ static constexpr double InvPi = 1.0 / Pi;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:37: warning: prefer 'std::numbers::inv_pi' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr double InvPi = std::numbers::inv_pi;
+
+ static constexpr my_float Actually2MyFloat = 2;
+ bar::sqrt(Actually2MyFloat);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2_v<float>;
+
+ sink(MY_PI);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::pi' to this macro,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::pi);
+
+ auto X = 42.0;
+ auto Y = X * 3.14;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:18: warning: prefer 'std::numbers::pi' to this literal,
diff ers by '1.59e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: auto Y = X * std::numbers::pi;
+
+ constexpr static auto One = 1;
+ constexpr static auto Two = 2;
+
+ bar::sqrt(2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ bar::sqrt(Two);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ bar::sqrt(2.0);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ auto Not2 = 2;
+ Not2 = 42;
+ bar::sqrt(Not2);
+
+ const auto Actually2 = 2;
+ bar::sqrt(Actually2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ exp(1);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::e;
+
+ exp(One);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::e;
+
+ exp(1.00000000000001);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::e;
+
+ log2(exp(1));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:10: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e;
+
+ log2(Euler);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e;
+
+ log2(bar::e);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e;
+
+ log2(Euler5);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e;
+
+ log2(Euler6);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e_v<float>;
+
+ log2(NotEuler7);
+
+ auto log2e = 1.4426950;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:18: warning: prefer 'std::numbers::log2e' to this literal,
diff ers by '4.09e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: auto log2e = std::numbers::log2e;
+
+ floatSink(log2(Euler));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e);
+
+ floatSink(static_cast<float>(log2(Euler)));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+ floatSink(1.4426950);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this literal,
diff ers by '4.09e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e);
+
+ floatSink(static_cast<float>(1.4426950));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this literal,
diff ers by '4.09e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+ floatSink(log2(static_cast<float>(Euler)));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+ floatSink(static_cast<float>(log2(static_cast<float>(Euler))));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+ floatSink(static_cast<float>(log2(static_cast<int>(Euler))));
+
+ floatSink(static_cast<int>(log2(static_cast<float>(Euler))));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:32: warning: prefer 'std::numbers::log2e_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(static_cast<int>(std::numbers::log2e_v<float>));
+
+ floatSink(1.4426950F);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e_v<float>' to this literal,
diff ers by '1.93e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e_v<float>);
+
+ floatSink(static_cast<double>(1.4426950F));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this literal,
diff ers by '1.93e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(std::numbers::log2e);
+
+ floatSink(static_cast<int>(1.4426950F));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:32: warning: prefer 'std::numbers::log2e_v<float>' to this literal,
diff ers by '1.93e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: floatSink(static_cast<int>(std::numbers::log2e_v<float>));
+
+ log10(exp(1));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:11: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log10e;
+
+ log10(Euler);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log10e;
+
+ log10(bar::e);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log10e;
+
+ auto log10e = .434294;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:19: warning: prefer 'std::numbers::log10e' to this literal,
diff ers by '4.82e-07' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: auto log10e = std::numbers::log10e;
+
+ auto egamma = 0.5772156 * 42;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:19: warning: prefer 'std::numbers::egamma' to this literal,
diff ers by '6.49e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: auto egamma = std::numbers::egamma * 42;
+
+ sink(InvPi);
+
+ sink(1 / Pi);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_pi' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_pi);
+
+ sink(1 / bar::sqrt(Pi));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrtpi' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrtpi);
+
+ sink(1 / bar::sqrt(MY_PI));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrtpi' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:24: warning: prefer 'std::numbers::pi' to this macro,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrtpi);
+
+ log(2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::ln2;
+
+ log(10);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln10' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::ln10;
+
+ bar::sqrt(2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ sink(1 / bar::sqrt(3));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrt3' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:14: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrt3);
+
+ sink(INV_SQRT3);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrt3' to this macro [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrt3);
+
+ sink(NOT_INV_SQRT3);
+
+ const auto inv_sqrt3f = .577350269F;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:29: warning: prefer 'std::numbers::inv_sqrt3_v<float>' to this literal,
diff ers by '1.04e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: const auto inv_sqrt3f = std::numbers::inv_sqrt3_v<float>;
+
+ bar::sqrt(3);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt3;
+
+ auto somePhi = 1.6180339;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:20: warning: prefer 'std::numbers::phi' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: auto somePhi = std::numbers::phi;
+
+ sink(Phi);
+
+ sink((42 + bar::sqrt(5)) / 2);
+
+ sink((1 + bar::sqrt(5)) / 2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::phi);
+
+ sink((bar::sqrt(5.0F) + 1) / 2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::phi_v<float>);
+}
+
+
+
+template <typename T>
+void baz(){
+ static constexpr T Pi = 3.1415926;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:29: warning: prefer 'std::numbers::pi' to this literal,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T Pi = std::numbers::pi;
+
+ static constexpr T Euler = 2.7182818;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:32: warning: prefer 'std::numbers::e' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T Euler = std::numbers::e;
+
+ static constexpr T Phi = 1.6180339;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:30: warning: prefer 'std::numbers::phi' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T Phi = std::numbers::phi;
+
+ static constexpr T PiCopy = Pi;
+ static constexpr T PiDefineFromMacro = MY_PI;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:44: warning: prefer 'std::numbers::pi' to this macro,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T PiDefineFromMacro = std::numbers::pi;
+
+ static constexpr T Pi2 = 3.14;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:30: warning: prefer 'std::numbers::pi' to this literal,
diff ers by '1.59e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: static constexpr T Pi2 = std::numbers::pi;
+ static constexpr T Euler2 = 2.71;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:33: warning: prefer 'std::numbers::e' to this literal,
diff ers by '8.28e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: static constexpr T Euler2 = std::numbers::e;
+ static constexpr T Phi2 = 1.61;
+ // CHECK-MESSAGES-IMPRECISE: :[[@LINE-1]]:31: warning: prefer 'std::numbers::phi' to this literal,
diff ers by '8.03e-03' [modernize-use-std-numbers]
+ // CHECK-FIXES-IMPRECISE: static constexpr T Phi2 = std::numbers::phi;
+
+ static constexpr T Pi3 = 3.1415926L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:30: warning: prefer 'std::numbers::pi_v<long double>' to this literal,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T Pi3 = std::numbers::pi_v<long double>;
+
+ static constexpr T Euler3 = 2.7182818L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:33: warning: prefer 'std::numbers::e_v<long double>' to this literal,
diff ers by '2.85e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T Euler3 = std::numbers::e_v<long double>;
+
+ static constexpr T Phi3 = 1.6180339L;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:31: warning: prefer 'std::numbers::phi_v<long double>' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: static constexpr T Phi3 = std::numbers::phi_v<long double>;
+
+ static constexpr my_float Actually2MyFloat = 2;
+ bar::sqrt(Actually2MyFloat);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2_v<float>;
+
+ constexpr static T One = 1;
+ constexpr static T Two = 2;
+
+ bar::sqrt(2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ bar::sqrt(Two);
+
+ bar::sqrt(2.0);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ T Not2 = 2;
+ Not2 = 42;
+ bar::sqrt(Not2);
+
+ const T Actually2 = 2;
+ bar::sqrt(Actually2);
+
+ exp(1);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::e;
+
+ exp(One);
+
+ exp(1.00000000000001);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::e;
+
+ log2(exp(1));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:10: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e;
+
+ log2(Euler);
+
+ log2(bar::e);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log2e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log2e;
+
+ T log2e = 1.4426950;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: prefer 'std::numbers::log2e' to this literal,
diff ers by '4.09e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: T log2e = std::numbers::log2e;
+
+ log10(exp(1));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:11: warning: prefer 'std::numbers::e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log10e;
+
+ log10(Euler);
+
+ log10(bar::e);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::log10e' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::log10e;
+
+ T log10e = .434294;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:16: warning: prefer 'std::numbers::log10e' to this literal,
diff ers by '4.82e-07' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: T log10e = std::numbers::log10e;
+
+ T egamma = 0.5772156 * 42;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:16: warning: prefer 'std::numbers::egamma' to this literal,
diff ers by '6.49e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: T egamma = std::numbers::egamma * 42;
+
+ sink(1 / Pi);
+
+ sink(1 / bar::sqrt(Pi));
+
+ sink(1 / bar::sqrt(MY_PI));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrtpi' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:24: warning: prefer 'std::numbers::pi' to this macro,
diff ers by '5.36e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrtpi);
+
+
+ log(2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::ln2;
+
+ log(10);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::ln10' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::ln10;
+
+ bar::sqrt(2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt2' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt2;
+
+ sink(1 / bar::sqrt(3));
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::inv_sqrt3' to this formula [modernize-use-std-numbers]
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:14: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::inv_sqrt3);
+
+ bar::sqrt(3);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:5: warning: prefer 'std::numbers::sqrt3' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: std::numbers::sqrt3;
+
+ T phi = 1.6180339;
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: prefer 'std::numbers::phi' to this literal,
diff ers by '8.87e-08' [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: T phi = std::numbers::phi;
+
+ sink((42 + bar::sqrt(5)) / 2);
+
+ sink((1 + bar::sqrt(5)) / 2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::phi);
+
+ sink((bar::sqrt(5.0F) + 1) / 2);
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: prefer 'std::numbers::phi_v<float>' to this formula [modernize-use-std-numbers]
+ // CHECK-FIXES-ALL: sink(std::numbers::phi_v<float>);
+}
+
+template <typename T>
+void foobar(){
+ const T Two = 2;
+ bar::sqrt(Two);
+}
+void use_templates() {
+ foobar<float>();
+ foobar<double>();
+
+ baz<float>();
+ baz<double>();
+}
+
+#define BIG_MARCO \
+ struct InvSqrt3 { \
+ template <typename T> static T get() { return 1 / bar::sqrt(3); } \
+ }
+
+BIG_MARCO;
+
+void use_BIG_MACRO() {
+InvSqrt3 f{};
+f.get<float>();
+f.get<double>();
+}
More information about the cfe-commits
mailing list