Index: clang-tools-extra/clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyMiscModule DefinitionsInHeadersCheck.cpp + MathConstantsCheck.cpp MiscTidyModule.cpp MisplacedConstCheck.cpp NewDeleteOverloadsCheck.cpp Index: clang-tools-extra/clang-tidy/misc/MathConstantsCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/MathConstantsCheck.h @@ -0,0 +1,59 @@ +//===--- MathConstantsCheck.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_MISC_MATHCONSTANTSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MATHCONSTANTSCHECK_H + +#include "../ClangTidyCheck.h" + +#include "../utils/IncludeInserter.h" + +#include "llvm/ADT/Optional.h" + +#include +#include +#include + +namespace clang { +namespace tidy { +namespace misc { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-math-constants.html +class MathConstantsCheck : public ClangTidyCheck { +public: + MathConstantsCheck(StringRef Name, ClangTidyContext *Context); + 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; + +private: + void insertHeader(DiagnosticBuilder &Diag, FileID FD); + + struct MathConstantDescription + { + const Optional NameInC; + const Optional NameInCpp20; + const double Value; + }; + + const std::vector Constants; + const utils::IncludeSorter::IncludeStyle IncludeStyle; + std::string ChosenHeaderName; + std::unique_ptr Inserter; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MATHCONSTANTSCHECK_H Index: clang-tools-extra/clang-tidy/misc/MathConstantsCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/MathConstantsCheck.cpp @@ -0,0 +1,153 @@ +//===--- MathConstantsCheck.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 "MathConstantsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "../../../clang/unittests/AST/Language.h" + +#include +#include +#include + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +namespace +{ + +constexpr char StdMathHeader[] = "math"; +constexpr char StdCmathHeader[] = "cmath"; +constexpr char StdCHeader[] = "math.h"; +constexpr char FloatType[] = "floatLiteral"; +constexpr double Epsilon = 0.01; + +std::string GetAngledName(const std::string& filename) +{ + return "<" + filename + ">"; +} + +} // namespace + +MathConstantsCheck::MathConstantsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + Constants + { + {{"M_E"}, {"std::math::e"}, 2.7182818284590452354}, + {{"M_LOG2E"}, {"std::math::log2e"}, 1.4426950408889634074}, + {{"M_LOG10E"}, {"std::math::log10e"}, 0.43429448190325182765}, + {{"M_LN2"}, {"std::math::ln2"}, 0.69314718055994530942}, + {{"M_LN10"}, {"std::math::ln10"}, 2.30258509299404568402}, + {{"M_PI"}, {"std::math::pi"}, 3.14159265358979323846}, + {{"M_PI_2"}, {}, 1.57079632679489661923}, + {{"M_PI_4"}, {}, 0.78539816339744830962}, + {{"M_1_PI"}, {"std::math::inv_pi"}, 0.31830988618379067154}, + {{"M_2_PI"}, {}, 0.63661977236758134308}, + {{"M_2_SQRTPI"}, {"std::math::inv_sqrtpi"}, 1.12837916709551257390}, + {{"M_SQRT2"}, {"std::math::sqrt2"}, 1.41421356237309504880}, + {{"M_SQRT1_2"}, {"std::math::"}, 0.70710678118654752440}, + {{}, {"std::math::phi"}, 1.6180339887498948482}, + {{}, {"std::math::egamma"}, 0.5772156649015328606 } + }, + IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + Options.getLocalOrGlobal("IncludeStyle", "llvm"))) +{ +} + +void MathConstantsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IncludeStyle", IncludeStyle); +} + +void MathConstantsCheck::registerMatchers(MatchFinder *Finder) { + // FIXME: Add matchers. + Finder->addMatcher(floatLiteral().bind(FloatType), this); +} + +void MathConstantsCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + Inserter = llvm::make_unique(SM, getLangOpts(), + IncludeStyle); + PP->addPPCallbacks(Inserter->CreatePPCallbacks()); +} + +void MathConstantsCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs(FloatType); + const auto MatchedFloatConstant = MatchedDecl->getValue().convertToDouble(); + + const auto Language = getLangOpts(); + + for (const auto& MathConstant : Constants) + { + // Match constant + if (std::fabs(MatchedFloatConstant - MathConstant.Value) < Epsilon) + { + std::string ConstantName; + if(getLangOpts().CPlusPlus2a) + { + if(MathConstant.NameInCpp20.hasValue()) + { + ConstantName = MathConstant.NameInCpp20.getValue(); + ChosenHeaderName = StdMathHeader; + } + else + { + ConstantName = MathConstant.NameInC.getValue(); + ChosenHeaderName = StdCmathHeader; + } + } + else // For other C++ standards and whole C + { + if(!MathConstant.NameInC.hasValue()) + { + // We have not such constant for old standards + return; + } + + ConstantName = MathConstant.NameInC.getValue(); + if (Language.C99 || Language.C11 || Language.C17 || Language.C2x) + { + ChosenHeaderName = StdCHeader; + } + else if (Language.CPlusPlus) + { + ChosenHeaderName = StdCmathHeader; + } + } + + diag(MatchedDecl->getLocation(), "The constant " + std::to_string(MatchedFloatConstant) + " is being utilized. " + "The resulting value could be inaccurate. Consider using the " + ConstantName + + " constant from " + GetAngledName(ChosenHeaderName)); + + // Fix-hint + auto Diag = diag(MatchedDecl->getLocation(), "insert '" + ConstantName + "'", DiagnosticIDs::Note) + << FixItHint::CreateReplacement(MatchedDecl->getLocation(), ConstantName); + + SourceManager &SM = *Result.SourceManager; + insertHeader(Diag, SM.getFileID(MatchedDecl->getExprLoc())); + } + } +} + +void MathConstantsCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) { + if (ChosenHeaderName.empty()) { + return; + } + if (auto IncludeFixit = Inserter->CreateIncludeInsertion( + FD, ChosenHeaderName, + true)) { + Diag << *IncludeFixit; + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "DefinitionsInHeadersCheck.h" +#include "MathConstantsCheck.h" #include "MisplacedConstCheck.h" #include "NewDeleteOverloadsCheck.h" #include "NonCopyableObjects.h" @@ -32,6 +33,8 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "misc-definitions-in-headers"); + CheckFactories.registerCheck( + "misc-math-constants"); CheckFactories.registerCheck("misc-misplaced-const"); CheckFactories.registerCheck( "misc-new-delete-overloads"); Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -85,6 +85,11 @@ The improvements are... +- New :doc:`misc-math-constants + ` check. + + FIXME: add release notes. + Improvements to clang-include-fixer ----------------------------------- Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -276,6 +276,7 @@ llvm-prefer-isa-or-dyn-cast-in-conditionals llvm-twine-local misc-definitions-in-headers + misc-math-constants misc-misplaced-const misc-new-delete-overloads misc-non-copyable-objects Index: clang-tools-extra/docs/clang-tidy/checks/misc-math-constants.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/misc-math-constants.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - misc-math-constants + +misc-math-constants +=================== + +FIXME: Describe what patterns does the check detect and why. Give examples. Index: clang-tools-extra/test/clang-tidy/misc-math-constants.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/misc-math-constants.cpp @@ -0,0 +1,18 @@ +// RUN: %check_clang_tidy %s misc-math-constants %t + +// FIXME: Add something that triggers the check here. +void f(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [misc-math-constants] + +// FIXME: Verify the applied fix. +// * Make the CHECK patterns specific enough and try to make verified lines +// unique to avoid incorrect matches. +// * Use {{}} for regular expressions. +// CHECK-FIXES: {{^}}void awesome_f();{{$}} + +// FIXME: Add something that doesn't trigger the check here. +void foo() +{ + double pi = 3.14; + double p_2 = 1.57; +}