aboutsummaryrefslogtreecommitdiff
path: root/clang-tidy/performance
diff options
context:
space:
mode:
authorJustin Lebar <jlebar@google.com>2016-12-14 03:15:01 +0000
committerJustin Lebar <jlebar@google.com>2016-12-14 03:15:01 +0000
commit94a7ed0b294b7f862447b74fd945f7fdccf2b1e9 (patch)
tree12b2ba4c720177abc45d595fc43db951131d193c /clang-tidy/performance
parentf2f54efba2afec4634c7e1fc2346b0edb76831f4 (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.txt1
-rw-r--r--clang-tidy/performance/PerformanceTidyModule.cpp6
-rw-r--r--clang-tidy/performance/TypePromotionInMathFnCheck.cpp172
-rw-r--r--clang-tidy/performance/TypePromotionInMathFnCheck.h40
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