10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "llvm/ADT/StringSet.h"
20 namespace performance {
24 if (
const auto *BT = dyn_cast<BuiltinType>(&Node)) {
25 return BT->getKind() ==
Kind;
31 TypePromotionInMathFnCheck::TypePromotionInMathFnCheck(
34 IncludeStyle(Options.getLocalOrGlobal(
"IncludeStyle",
35 utils::IncludeSorter::IS_LLVM)) {}
38 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
39 IncludeInserter = std::make_unique<utils::IncludeInserter>(SM,
getLangOpts(),
41 PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks());
57 return hasParameter(
Pos, hasType(isBuiltinType(
Kind)));
60 return hasArgument(
Pos, hasType(isBuiltinType(
Kind)));
64 auto OneDoubleArgFns = hasAnyName(
65 "::acos",
"::acosh",
"::asin",
"::asinh",
"::atan",
"::atanh",
"::cbrt",
66 "::ceil",
"::cos",
"::cosh",
"::erf",
"::erfc",
"::exp",
"::exp2",
67 "::expm1",
"::fabs",
"::floor",
"::ilogb",
"::lgamma",
"::llrint",
68 "::log",
"::log10",
"::log1p",
"::log2",
"::logb",
"::lrint",
"::modf",
69 "::nearbyint",
"::rint",
"::round",
"::sin",
"::sinh",
"::sqrt",
"::tan",
70 "::tanh",
"::tgamma",
"::trunc",
"::llround",
"::lround");
72 callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1),
73 hasBuiltinTyParam(0, DoubleTy))),
74 hasBuiltinTyArg(0, FloatTy))
79 auto TwoDoubleArgFns = hasAnyName(
"::atan2",
"::copysign",
"::fdim",
"::fmax",
80 "::fmin",
"::fmod",
"::hypot",
"::ldexp",
81 "::nextafter",
"::pow",
"::remainder");
83 callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2),
84 hasBuiltinTyParam(0, DoubleTy),
85 hasBuiltinTyParam(1, DoubleTy))),
86 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
92 callExpr(callee(functionDecl(hasName(
"::fma"), parameterCountIs(3),
93 hasBuiltinTyParam(0, DoubleTy),
94 hasBuiltinTyParam(1, DoubleTy),
95 hasBuiltinTyParam(2, DoubleTy))),
96 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy),
97 hasBuiltinTyArg(2, FloatTy))
103 callExpr(callee(functionDecl(
104 hasName(
"::frexp"), parameterCountIs(2),
105 hasBuiltinTyParam(0, DoubleTy),
106 hasParameter(1, parmVarDecl(hasType(pointerType(
107 pointee(isBuiltinType(IntTy)))))))),
108 hasBuiltinTyArg(0, FloatTy))
115 callExpr(callee(functionDecl(hasName(
"::nexttoward"), parameterCountIs(2),
116 hasBuiltinTyParam(0, DoubleTy),
117 hasBuiltinTyParam(1, LongDoubleTy))),
118 hasBuiltinTyArg(0, FloatTy))
127 hasName(
"::remquo"), parameterCountIs(3),
128 hasBuiltinTyParam(0, DoubleTy), hasBuiltinTyParam(1, DoubleTy),
129 hasParameter(2, parmVarDecl(hasType(pointerType(
130 pointee(isBuiltinType(IntTy)))))))),
131 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
137 callExpr(callee(functionDecl(hasName(
"::scalbln"), parameterCountIs(2),
138 hasBuiltinTyParam(0, DoubleTy),
139 hasBuiltinTyParam(1, LongTy))),
140 hasBuiltinTyArg(0, FloatTy))
146 callExpr(callee(functionDecl(hasName(
"::scalbn"), parameterCountIs(2),
147 hasBuiltinTyParam(0, DoubleTy),
148 hasBuiltinTyParam(1, IntTy))),
149 hasBuiltinTyArg(0, FloatTy))
158 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
159 assert(Call !=
nullptr);
161 StringRef OldFnName = Call->getDirectCallee()->getName();
165 static llvm::StringSet<> Cpp11OnlyFns = {
166 "acosh",
"asinh",
"atanh",
"cbrt",
"copysign",
"erf",
167 "erfc",
"exp2",
"expm1",
"fdim",
"fma",
"fmax",
168 "fmin",
"hypot",
"ilogb",
"lgamma",
"llrint",
"llround",
169 "log1p",
"log2",
"logb",
"lrint",
"lround",
"nearbyint",
170 "nextafter",
"nexttoward",
"remainder",
"remquo",
"rint",
"round",
171 "scalbln",
"scalbn",
"tgamma",
"trunc"};
172 bool StdFnRequiresCpp11 = Cpp11OnlyFns.count(OldFnName);
174 std::string NewFnName;
175 bool FnInCmath =
false;
177 (!StdFnRequiresCpp11 ||
getLangOpts().CPlusPlus11)) {
178 NewFnName = (
"std::" + OldFnName).str();
181 NewFnName = (OldFnName +
"f").str();
184 auto Diag =
diag(Call->getExprLoc(),
"call to '%0' promotes float to double")
186 << FixItHint::CreateReplacement(
187 Call->getCallee()->getSourceRange(), NewFnName);
194 Diag << IncludeInserter->CreateIncludeInsertion(
195 Result.Context->getSourceManager().getFileID(Call->getBeginLoc()),