11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Frontend/CompilerInstance.h" 14 #include "clang/Lex/Preprocessor.h" 15 #include "llvm/ADT/StringSet.h" 21 namespace performance {
25 if (
const auto *BT = dyn_cast<BuiltinType>(&Node)) {
26 return BT->getKind() ==
Kind;
32 TypePromotionInMathFnCheck::TypePromotionInMathFnCheck(
35 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
36 Options.getLocalOrGlobal(
"IncludeStyle",
"llvm"))) {}
39 CompilerInstance &Compiler) {
40 IncludeInserter = llvm::make_unique<utils::IncludeInserter>(
41 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
42 Compiler.getPreprocessor().addPPCallbacks(
43 IncludeInserter->CreatePPCallbacks());
60 return hasParameter(Pos, hasType(isBuiltinType(
Kind)));
63 return hasArgument(Pos, hasType(isBuiltinType(
Kind)));
67 auto OneDoubleArgFns = hasAnyName(
68 "::acos",
"::acosh",
"::asin",
"::asinh",
"::atan",
"::atanh",
"::cbrt",
69 "::ceil",
"::cos",
"::cosh",
"::erf",
"::erfc",
"::exp",
"::exp2",
70 "::expm1",
"::fabs",
"::floor",
"::ilogb",
"::lgamma",
"::llrint",
71 "::log",
"::log10",
"::log1p",
"::log2",
"::logb",
"::lrint",
"::modf",
72 "::nearbyint",
"::rint",
"::round",
"::sin",
"::sinh",
"::sqrt",
"::tan",
73 "::tanh",
"::tgamma",
"::trunc",
"::llround",
"::lround");
75 callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1),
76 hasBuiltinTyParam(0, DoubleTy))),
77 hasBuiltinTyArg(0, FloatTy))
82 auto TwoDoubleArgFns = hasAnyName(
"::atan2",
"::copysign",
"::fdim",
"::fmax",
83 "::fmin",
"::fmod",
"::hypot",
"::ldexp",
84 "::nextafter",
"::pow",
"::remainder");
86 callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2),
87 hasBuiltinTyParam(0, DoubleTy),
88 hasBuiltinTyParam(1, DoubleTy))),
89 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
95 callExpr(callee(functionDecl(hasName(
"::fma"), parameterCountIs(3),
96 hasBuiltinTyParam(0, DoubleTy),
97 hasBuiltinTyParam(1, DoubleTy),
98 hasBuiltinTyParam(2, DoubleTy))),
99 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy),
100 hasBuiltinTyArg(2, FloatTy))
106 callExpr(callee(functionDecl(
107 hasName(
"::frexp"), parameterCountIs(2),
108 hasBuiltinTyParam(0, DoubleTy),
109 hasParameter(1, parmVarDecl(hasType(pointerType(
110 pointee(isBuiltinType(IntTy)))))))),
111 hasBuiltinTyArg(0, FloatTy))
118 callExpr(callee(functionDecl(hasName(
"::nexttoward"), parameterCountIs(2),
119 hasBuiltinTyParam(0, DoubleTy),
120 hasBuiltinTyParam(1, LongDoubleTy))),
121 hasBuiltinTyArg(0, FloatTy))
130 hasName(
"::remquo"), parameterCountIs(3),
131 hasBuiltinTyParam(0, DoubleTy), hasBuiltinTyParam(1, DoubleTy),
132 hasParameter(2, parmVarDecl(hasType(pointerType(
133 pointee(isBuiltinType(IntTy)))))))),
134 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
140 callExpr(callee(functionDecl(hasName(
"::scalbln"), parameterCountIs(2),
141 hasBuiltinTyParam(0, DoubleTy),
142 hasBuiltinTyParam(1, LongTy))),
143 hasBuiltinTyArg(0, FloatTy))
149 callExpr(callee(functionDecl(hasName(
"::scalbn"), parameterCountIs(2),
150 hasBuiltinTyParam(0, DoubleTy),
151 hasBuiltinTyParam(1, IntTy))),
152 hasBuiltinTyArg(0, FloatTy))
161 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
162 assert(Call !=
nullptr);
164 StringRef OldFnName = Call->getDirectCallee()->getName();
168 static llvm::StringSet<> Cpp11OnlyFns = {
169 "acosh",
"asinh",
"atanh",
"cbrt",
"copysign",
"erf",
170 "erfc",
"exp2",
"expm1",
"fdim",
"fma",
"fmax",
171 "fmin",
"hypot",
"ilogb",
"lgamma",
"llrint",
"llround",
172 "log1p",
"log2",
"logb",
"lrint",
"lround",
"nearbyint",
173 "nextafter",
"nexttoward",
"remainder",
"remquo",
"rint",
"round",
174 "scalbln",
"scalbn",
"tgamma",
"trunc"};
175 bool StdFnRequiresCpp11 = Cpp11OnlyFns.count(OldFnName);
177 std::string NewFnName;
178 bool FnInCmath =
false;
180 (!StdFnRequiresCpp11 ||
getLangOpts().CPlusPlus11)) {
181 NewFnName = (
"std::" + OldFnName).str();
184 NewFnName = (OldFnName +
"f").str();
187 auto Diag =
diag(Call->getExprLoc(),
"call to '%0' promotes float to double")
189 << FixItHint::CreateReplacement(
190 Call->getCallee()->getSourceRange(), NewFnName);
197 if (
auto IncludeFixit = IncludeInserter->CreateIncludeInsertion(
198 Result.Context->getSourceManager().getFileID(Call->getLocStart()),
200 Diag << *IncludeFixit;
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
LangOptions getLangOpts() const
Returns the language options from the context.
static StringRef toString(IncludeStyle Style)
Converts IncludeStyle to string representation.
Base class for all clang-tidy checks.
std::map< std::string, std::string > OptionMap
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N)
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.