clang-tools 6.0.0

TypePromotionInMathFnCheck.cpp
Go to the documentation of this file.
1 //===--- TypePromotionInMathFnCheck.cpp - clang-tidy-----------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "TypePromotionInMathFnCheck.h"
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"
16
17 using namespace clang::ast_matchers;
18
19 namespace clang {
20 namespace tidy {
21 namespace performance {
22
23 namespace {
24 AST_MATCHER_P(Type, isBuiltinType, BuiltinType::Kind, Kind) {
25 if (const auto *BT = dyn_cast<BuiltinType>(&Node)) {
26 return BT->getKind() == Kind;
27 }
28 return false;
29 }
30 } // anonymous namespace
31
32 TypePromotionInMathFnCheck::TypePromotionInMathFnCheck(
33 StringRef Name, ClangTidyContext *Context)
34 : ClangTidyCheck(Name, Context),
35 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
36 Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
37
38 void TypePromotionInMathFnCheck::registerPPCallbacks(
39 CompilerInstance &Compiler) {
40 IncludeInserter = llvm::make_unique<utils::IncludeInserter>(
41 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
42 Compiler.getPreprocessor().addPPCallbacks(
43 IncludeInserter->CreatePPCallbacks());
44 }
45
46 void TypePromotionInMathFnCheck::storeOptions(
47 ClangTidyOptions::OptionMap &Opts) {
48 Options.store(Opts, "IncludeStyle",
49 utils::IncludeSorter::toString(IncludeStyle));
50 }
51
52 void TypePromotionInMathFnCheck::registerMatchers(MatchFinder *Finder) {
53 constexpr BuiltinType::Kind IntTy = BuiltinType::Int;
54 constexpr BuiltinType::Kind LongTy = BuiltinType::Long;
55 constexpr BuiltinType::Kind FloatTy = BuiltinType::Float;
56 constexpr BuiltinType::Kind DoubleTy = BuiltinType::Double;
57 constexpr BuiltinType::Kind LongDoubleTy = BuiltinType::LongDouble;
58
59 auto hasBuiltinTyParam = [](int Pos, BuiltinType::Kind Kind) {
60 return hasParameter(Pos, hasType(isBuiltinType(Kind)));
61 };
62 auto hasBuiltinTyArg = [](int Pos, BuiltinType::Kind Kind) {
63 return hasArgument(Pos, hasType(isBuiltinType(Kind)));
64 };
65
66 // Match calls to foo(double) with a float argument.
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");
74 Finder->addMatcher(
75 callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1),
76 hasBuiltinTyParam(0, DoubleTy))),
77 hasBuiltinTyArg(0, FloatTy))
78 .bind("call"),
79 this);
80
81 // Match calls to foo(double, double) where both args are floats.
82 auto TwoDoubleArgFns = hasAnyName("::atan2", "::copysign", "::fdim", "::fmax",
83 "::fmin", "::fmod", "::hypot", "::ldexp",
84 "::nextafter", "::pow", "::remainder");
85 Finder->addMatcher(
86 callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2),
87 hasBuiltinTyParam(0, DoubleTy),
88 hasBuiltinTyParam(1, DoubleTy))),
89 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
90 .bind("call"),
91 this);
92
93 // Match calls to fma(double, double, double) where all args are floats.
94 Finder->addMatcher(
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))
101 .bind("call"),
102 this);
103
104 // Match calls to frexp(double, int*) where the first arg is a float.
105 Finder->addMatcher(
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))
112 .bind("call"),
113 this);
114
115 // Match calls to nexttoward(double, long double) where the first arg is a
116 // float.
117 Finder->addMatcher(
118 callExpr(callee(functionDecl(hasName("::nexttoward"), parameterCountIs(2),
119 hasBuiltinTyParam(0, DoubleTy),
120 hasBuiltinTyParam(1, LongDoubleTy))),
121 hasBuiltinTyArg(0, FloatTy))
122 .bind("call"),
123 this);
124
125 // Match calls to remquo(double, double, int*) where the first two args are
126 // floats.
127 Finder->addMatcher(
128 callExpr(
129 callee(functionDecl(
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))
135 .bind("call"),
136 this);
137
138 // Match calls to scalbln(double, long) where the first arg is a float.
139 Finder->addMatcher(
140 callExpr(callee(functionDecl(hasName("::scalbln"), parameterCountIs(2),
141 hasBuiltinTyParam(0, DoubleTy),
142 hasBuiltinTyParam(1, LongTy))),
143 hasBuiltinTyArg(0, FloatTy))
144 .bind("call"),
145 this);
146
147 // Match calls to scalbn(double, int) where the first arg is a float.
148 Finder->addMatcher(
149 callExpr(callee(functionDecl(hasName("::scalbn"), parameterCountIs(2),
150 hasBuiltinTyParam(0, DoubleTy),
151 hasBuiltinTyParam(1, IntTy))),
152 hasBuiltinTyArg(0, FloatTy))
153 .bind("call"),
154 this);
155
156 // modf(double, double*) is omitted because the second parameter forces the
157 // type -- there's no conversion from float* to double*.
158 }
159
160 void TypePromotionInMathFnCheck::check(const MatchFinder::MatchResult &Result) {
161 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
162 assert(Call != nullptr);
163
164 StringRef OldFnName = Call->getDirectCallee()->getName();
165
166 // In C++ mode, we prefer std::foo to ::foof. But some of these suggestions
167 // are only valid in C++11 and newer.
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);
176
177 std::string NewFnName;
178 bool FnInCmath = false;
179 if (getLangOpts().CPlusPlus &&
180 (!StdFnRequiresCpp11 || getLangOpts().CPlusPlus11)) {
181 NewFnName = ("std::" + OldFnName).str();
182 FnInCmath = true;
183 } else {
184 NewFnName = (OldFnName + "f").str();
185 }
186
187 auto Diag = diag(Call->getExprLoc(), "call to '%0' promotes float to double")
188 << OldFnName
189 << FixItHint::CreateReplacement(
190 Call->getCallee()->getSourceRange(), NewFnName);
191
192 // Suggest including <cmath> if the function we're suggesting is declared in
193 // <cmath> and it's not already included. We never have to suggest including
194 // <math.h>, because the functions we're suggesting moving away from are all
195 // declared in <math.h>.
196 if (FnInCmath)
197 if (auto IncludeFixit = IncludeInserter->CreateIncludeInsertion(
198 Result.Context->getSourceManager().getFileID(Call->getLocStart()),
199 "cmath", /*IsAngled=*/true))
200 Diag << *IncludeFixit;
201 }
202
203 } // namespace performance
204 } // namespace tidy
205 } // namespace clang
clang::ast_matchers
Definition: ClangTidyDiagnosticConsumer.h:27
clang::tidy::OptionsView::store
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.
Definition: ClangTidy.cpp:449
clang::tidy::performance::TypePromotionInMathFnCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: TypePromotionInMathFnCheck.cpp:46
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
clang::tidy::ClangTidyCheck::getLangOpts
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
clang::tidy::utils::IncludeSorter::toString
static StringRef toString(IncludeStyle Style)
Converts IncludeStyle to string representation.
Definition: IncludeSorter.cpp:284
clang::tidy::performance::TypePromotionInMathFnCheck::registerPPCallbacks
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
Definition: TypePromotionInMathFnCheck.cpp:38
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:127
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:183
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:41
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:99
TypePromotionInMathFnCheck.h
clang::tidy::performance::TypePromotionInMathFnCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: TypePromotionInMathFnCheck.cpp:52
clang
Definition: AndroidTidyModule.cpp:28
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:104
clang::tidy::performance::TypePromotionInMathFnCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: TypePromotionInMathFnCheck.cpp:160
clang::tidy::bugprone::AST_MATCHER_P
AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N)
Definition: StringConstructorCheck.cpp:21
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:416