diff options
author | Justin Lebar <jlebar@google.com> | 2016-12-14 03:15:01 +0000 |
---|---|---|
committer | Justin Lebar <jlebar@google.com> | 2016-12-14 03:15:01 +0000 |
commit | 94a7ed0b294b7f862447b74fd945f7fdccf2b1e9 (patch) | |
tree | 12b2ba4c720177abc45d595fc43db951131d193c /clang-tidy/performance | |
parent | f2f54efba2afec4634c7e1fc2346b0edb76831f4 (diff) |
[ClangTidy] Add new performance-type-promotion-in-math-fn check.
Summary:
This checks for calls to double-precision math.h with single-precision
arguments. For example, it suggests replacing ::sin(0.f) with
::sinf(0.f).
Subscribers: mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D27284
git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@289627 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-tidy/performance')
-rw-r--r-- | clang-tidy/performance/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang-tidy/performance/PerformanceTidyModule.cpp | 6 | ||||
-rw-r--r-- | clang-tidy/performance/TypePromotionInMathFnCheck.cpp | 172 | ||||
-rw-r--r-- | clang-tidy/performance/TypePromotionInMathFnCheck.h | 40 |
4 files changed, 217 insertions, 2 deletions
diff --git a/clang-tidy/performance/CMakeLists.txt b/clang-tidy/performance/CMakeLists.txt index 71becce5..8473f2c1 100644 --- a/clang-tidy/performance/CMakeLists.txt +++ b/clang-tidy/performance/CMakeLists.txt @@ -6,6 +6,7 @@ add_clang_library(clangTidyPerformanceModule ImplicitCastInLoopCheck.cpp InefficientStringConcatenationCheck.cpp PerformanceTidyModule.cpp + TypePromotionInMathFnCheck.cpp UnnecessaryCopyInitialization.cpp UnnecessaryValueParamCheck.cpp diff --git a/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tidy/performance/PerformanceTidyModule.cpp index a722ffb1..90255c5e 100644 --- a/clang-tidy/performance/PerformanceTidyModule.cpp +++ b/clang-tidy/performance/PerformanceTidyModule.cpp @@ -10,11 +10,11 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" -#include "InefficientStringConcatenationCheck.h" - #include "FasterStringFindCheck.h" #include "ForRangeCopyCheck.h" #include "ImplicitCastInLoopCheck.h" +#include "InefficientStringConcatenationCheck.h" +#include "TypePromotionInMathFnCheck.h" #include "UnnecessaryCopyInitialization.h" #include "UnnecessaryValueParamCheck.h" @@ -33,6 +33,8 @@ public: "performance-implicit-cast-in-loop"); CheckFactories.registerCheck<InefficientStringConcatenationCheck>( "performance-inefficient-string-concatenation"); + CheckFactories.registerCheck<TypePromotionInMathFnCheck>( + "performance-type-promotion-in-math-fn"); CheckFactories.registerCheck<UnnecessaryCopyInitialization>( "performance-unnecessary-copy-initialization"); CheckFactories.registerCheck<UnnecessaryValueParamCheck>( diff --git a/clang-tidy/performance/TypePromotionInMathFnCheck.cpp b/clang-tidy/performance/TypePromotionInMathFnCheck.cpp new file mode 100644 index 00000000..57bcc0ad --- /dev/null +++ b/clang-tidy/performance/TypePromotionInMathFnCheck.cpp @@ -0,0 +1,172 @@ +//===--- TypePromotionInMathFnCheck.cpp - clang-tidy-----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TypePromotionInMathFnCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/StringSet.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace performance { + +namespace { +AST_MATCHER_P(Type, isBuiltinType, BuiltinType::Kind, Kind) { + if (const auto *BT = dyn_cast<BuiltinType>(&Node)) { + return BT->getKind() == Kind; + } + return false; +} +} // anonymous namespace + +void TypePromotionInMathFnCheck::registerMatchers(MatchFinder *Finder) { + constexpr BuiltinType::Kind IntTy = BuiltinType::Int; + constexpr BuiltinType::Kind LongTy = BuiltinType::Long; + constexpr BuiltinType::Kind FloatTy = BuiltinType::Float; + constexpr BuiltinType::Kind DoubleTy = BuiltinType::Double; + constexpr BuiltinType::Kind LongDoubleTy = BuiltinType::LongDouble; + + auto hasBuiltinTyParam = [](int Pos, BuiltinType::Kind Kind) { + return hasParameter(Pos, hasType(isBuiltinType(Kind))); + }; + auto hasBuiltinTyArg = [](int Pos, BuiltinType::Kind Kind) { + return hasArgument(Pos, hasType(isBuiltinType(Kind))); + }; + + // Match calls to foo(double) with a float argument. + auto OneDoubleArgFns = hasAnyName( + "::acos", "::acosh", "::asin", "::asinh", "::atan", "::atanh", "::cbrt", + "::ceil", "::cos", "::cosh", "::erf", "::erfc", "::exp", "::exp2", + "::expm1", "::fabs", "::floor", "::ilogb", "::lgamma", "::llrint", + "::log", "::log10", "::log1p", "::log2", "::logb", "::lrint", "::modf", + "::nearbyint", "::rint", "::round", "::sin", "::sinh", "::sqrt", "::tan", + "::tanh", "::tgamma", "::trunc", "::llround", "::lround"); + Finder->addMatcher( + callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1), + hasBuiltinTyParam(0, DoubleTy))), + hasBuiltinTyArg(0, FloatTy)) + .bind("call"), + this); + + // Match calls to foo(double, double) where both args are floats. + auto TwoDoubleArgFns = hasAnyName("::atan2", "::copysign", "::fdim", "::fmax", + "::fmin", "::fmod", "::hypot", "::ldexp", + "::nextafter", "::pow", "::remainder"); + Finder->addMatcher( + callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2), + hasBuiltinTyParam(0, DoubleTy), + hasBuiltinTyParam(1, DoubleTy))), + hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy)) + .bind("call"), + this); + + // Match calls to fma(double, double, double) where all args are floats. + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::fma"), parameterCountIs(3), + hasBuiltinTyParam(0, DoubleTy), + hasBuiltinTyParam(1, DoubleTy), + hasBuiltinTyParam(2, DoubleTy))), + hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy), + hasBuiltinTyArg(2, FloatTy)) + .bind("call"), + this); + + // Match calls to frexp(double, int*) where the first arg is a float. + Finder->addMatcher( + callExpr(callee(functionDecl( + hasName("::frexp"), parameterCountIs(2), + hasBuiltinTyParam(0, DoubleTy), + hasParameter(1, parmVarDecl(hasType(pointerType( + pointee(isBuiltinType(IntTy)))))))), + hasBuiltinTyArg(0, FloatTy)) + .bind("call"), + this); + + // Match calls to nexttoward(double, long double) where the first arg is a + // float. + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::nexttoward"), parameterCountIs(2), + hasBuiltinTyParam(0, DoubleTy), + hasBuiltinTyParam(1, LongDoubleTy))), + hasBuiltinTyArg(0, FloatTy)) + .bind("call"), + this); + + // Match calls to remquo(double, double, int*) where the first two args are + // floats. + Finder->addMatcher( + callExpr( + callee(functionDecl( + hasName("::remquo"), parameterCountIs(3), + hasBuiltinTyParam(0, DoubleTy), hasBuiltinTyParam(1, DoubleTy), + hasParameter(2, parmVarDecl(hasType(pointerType( + pointee(isBuiltinType(IntTy)))))))), + hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy)) + .bind("call"), + this); + + // Match calls to scalbln(double, long) where the first arg is a float. + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::scalbln"), parameterCountIs(2), + hasBuiltinTyParam(0, DoubleTy), + hasBuiltinTyParam(1, LongTy))), + hasBuiltinTyArg(0, FloatTy)) + .bind("call"), + this); + + // Match calls to scalbn(double, int) where the first arg is a float. + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::scalbn"), parameterCountIs(2), + hasBuiltinTyParam(0, DoubleTy), + hasBuiltinTyParam(1, IntTy))), + hasBuiltinTyArg(0, FloatTy)) + .bind("call"), + this); + + // modf(double, double*) is omitted because the second parameter forces the + // type -- there's no conversion from float* to double*. +} + +void TypePromotionInMathFnCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call"); + assert(Call != nullptr); + + StringRef OldFnName = Call->getDirectCallee()->getName(); + + // In C++ mode, we prefer std::foo to ::foof. But some of these suggestions + // are only valid in C++11 and newer. + static llvm::StringSet<> Cpp11OnlyFns = { + "acosh", "asinh", "atanh", "cbrt", "copysign", "erf", + "erfc", "exp2", "expm1", "fdim", "fma", "fmax", + "fmin", "hypot", "ilogb", "lgamma", "llrint", "llround", + "log1p", "log2", "logb", "lrint", "lround", "nearbyint", + "nextafter", "nexttoward", "remainder", "remquo", "rint", "round", + "scalbln", "scalbn", "tgamma", "trunc"}; + bool StdFnRequiresCpp11 = Cpp11OnlyFns.count(OldFnName); + + std::string NewFnName; + if (getLangOpts().CPlusPlus && + (!StdFnRequiresCpp11 || getLangOpts().CPlusPlus11)) + NewFnName = ("std::" + OldFnName).str(); + else + NewFnName = (OldFnName + "f").str(); + + diag(Call->getExprLoc(), "call to '%0' promotes float to double") + << OldFnName << FixItHint::CreateReplacement( + Call->getCallee()->getSourceRange(), NewFnName); + + // FIXME: Perhaps we should suggest #include <cmath> if we suggest a cmath + // function and cmath is not already included. +} + +} // namespace performance +} // namespace tidy +} // namespace clang diff --git a/clang-tidy/performance/TypePromotionInMathFnCheck.h b/clang-tidy/performance/TypePromotionInMathFnCheck.h new file mode 100644 index 00000000..9132a547 --- /dev/null +++ b/clang-tidy/performance/TypePromotionInMathFnCheck.h @@ -0,0 +1,40 @@ +//===--- TypePromotionInMathFnCheck.h - clang-tidy---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace performance { + +/// Finds calls to C math library functions with implicit float to double +/// promotions. +/// +/// For example, warns on ::sin(0.f), because this funciton's parameter is a +/// double. You probably meant to call std::sin(0.f) (in C++), or sinf(0.f) (in +/// C). +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/performance-type-promotion-in-math-fn.html +class TypePromotionInMathFnCheck : public ClangTidyCheck { +public: + TypePromotionInMathFnCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace performance +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H |