clang-tools 10.0.0

TypePromotionInMathFnCheck.cpp
Go to the documentation of this file.
1 //===--- TypePromotionInMathFnCheck.cpp - clang-tidy-----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "TypePromotionInMathFnCheck.h"
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"
15
16 using namespace clang::ast_matchers;
17
18 namespace clang {
19 namespace tidy {
20 namespace performance {
21
22 namespace {
23 AST_MATCHER_P(Type, isBuiltinType, BuiltinType::Kind, Kind) {
24 if (const auto *BT = dyn_cast<BuiltinType>(&Node)) {
25 return BT->getKind() == Kind;
26 }
27 return false;
28 }
29 } // anonymous namespace
30
31 TypePromotionInMathFnCheck::TypePromotionInMathFnCheck(
32 StringRef Name, ClangTidyContext *Context)
33 : ClangTidyCheck(Name, Context),
34 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
35 Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
36
37 void TypePromotionInMathFnCheck::registerPPCallbacks(
38 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
39 IncludeInserter = std::make_unique<utils::IncludeInserter>(SM, getLangOpts(),
40 IncludeStyle);
41 PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks());
42 }
43
44 void TypePromotionInMathFnCheck::storeOptions(
45 ClangTidyOptions::OptionMap &Opts) {
46 Options.store(Opts, "IncludeStyle",
47 utils::IncludeSorter::toString(IncludeStyle));
48 }
49
50 void TypePromotionInMathFnCheck::registerMatchers(MatchFinder *Finder) {
51 constexpr BuiltinType::Kind IntTy = BuiltinType::Int;
52 constexpr BuiltinType::Kind LongTy = BuiltinType::Long;
53 constexpr BuiltinType::Kind FloatTy = BuiltinType::Float;
54 constexpr BuiltinType::Kind DoubleTy = BuiltinType::Double;
55 constexpr BuiltinType::Kind LongDoubleTy = BuiltinType::LongDouble;
56
57 auto hasBuiltinTyParam = [](int Pos, BuiltinType::Kind Kind) {
58 return hasParameter(Pos, hasType(isBuiltinType(Kind)));
59 };
60 auto hasBuiltinTyArg = [](int Pos, BuiltinType::Kind Kind) {
61 return hasArgument(Pos, hasType(isBuiltinType(Kind)));
62 };
63
64 // Match calls to foo(double) with a float argument.
65 auto OneDoubleArgFns = hasAnyName(
66 "::acos", "::acosh", "::asin", "::asinh", "::atan", "::atanh", "::cbrt",
67 "::ceil", "::cos", "::cosh", "::erf", "::erfc", "::exp", "::exp2",
68 "::expm1", "::fabs", "::floor", "::ilogb", "::lgamma", "::llrint",
69 "::log", "::log10", "::log1p", "::log2", "::logb", "::lrint", "::modf",
70 "::nearbyint", "::rint", "::round", "::sin", "::sinh", "::sqrt", "::tan",
71 "::tanh", "::tgamma", "::trunc", "::llround", "::lround");
72 Finder->addMatcher(
73 callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1),
74 hasBuiltinTyParam(0, DoubleTy))),
75 hasBuiltinTyArg(0, FloatTy))
76 .bind("call"),
77 this);
78
79 // Match calls to foo(double, double) where both args are floats.
80 auto TwoDoubleArgFns = hasAnyName("::atan2", "::copysign", "::fdim", "::fmax",
81 "::fmin", "::fmod", "::hypot", "::ldexp",
82 "::nextafter", "::pow", "::remainder");
83 Finder->addMatcher(
84 callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2),
85 hasBuiltinTyParam(0, DoubleTy),
86 hasBuiltinTyParam(1, DoubleTy))),
87 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
88 .bind("call"),
89 this);
90
91 // Match calls to fma(double, double, double) where all args are floats.
92 Finder->addMatcher(
93 callExpr(callee(functionDecl(hasName("::fma"), parameterCountIs(3),
94 hasBuiltinTyParam(0, DoubleTy),
95 hasBuiltinTyParam(1, DoubleTy),
96 hasBuiltinTyParam(2, DoubleTy))),
97 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy),
98 hasBuiltinTyArg(2, FloatTy))
99 .bind("call"),
100 this);
101
102 // Match calls to frexp(double, int*) where the first arg is a float.
103 Finder->addMatcher(
104 callExpr(callee(functionDecl(
105 hasName("::frexp"), parameterCountIs(2),
106 hasBuiltinTyParam(0, DoubleTy),
107 hasParameter(1, parmVarDecl(hasType(pointerType(
108 pointee(isBuiltinType(IntTy)))))))),
109 hasBuiltinTyArg(0, FloatTy))
110 .bind("call"),
111 this);
112
113 // Match calls to nexttoward(double, long double) where the first arg is a
114 // float.
115 Finder->addMatcher(
116 callExpr(callee(functionDecl(hasName("::nexttoward"), parameterCountIs(2),
117 hasBuiltinTyParam(0, DoubleTy),
118 hasBuiltinTyParam(1, LongDoubleTy))),
119 hasBuiltinTyArg(0, FloatTy))
120 .bind("call"),
121 this);
122
123 // Match calls to remquo(double, double, int*) where the first two args are
124 // floats.
125 Finder->addMatcher(
126 callExpr(
127 callee(functionDecl(
128 hasName("::remquo"), parameterCountIs(3),
129 hasBuiltinTyParam(0, DoubleTy), hasBuiltinTyParam(1, DoubleTy),
130 hasParameter(2, parmVarDecl(hasType(pointerType(
131 pointee(isBuiltinType(IntTy)))))))),
132 hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
133 .bind("call"),
134 this);
135
136 // Match calls to scalbln(double, long) where the first arg is a float.
137 Finder->addMatcher(
138 callExpr(callee(functionDecl(hasName("::scalbln"), parameterCountIs(2),
139 hasBuiltinTyParam(0, DoubleTy),
140 hasBuiltinTyParam(1, LongTy))),
141 hasBuiltinTyArg(0, FloatTy))
142 .bind("call"),
143 this);
144
145 // Match calls to scalbn(double, int) where the first arg is a float.
146 Finder->addMatcher(
147 callExpr(callee(functionDecl(hasName("::scalbn"), parameterCountIs(2),
148 hasBuiltinTyParam(0, DoubleTy),
149 hasBuiltinTyParam(1, IntTy))),
150 hasBuiltinTyArg(0, FloatTy))
151 .bind("call"),
152 this);
153
154 // modf(double, double*) is omitted because the second parameter forces the
155 // type -- there's no conversion from float* to double*.
156 }
157
158 void TypePromotionInMathFnCheck::check(const MatchFinder::MatchResult &Result) {
159 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
160 assert(Call != nullptr);
161
162 StringRef OldFnName = Call->getDirectCallee()->getName();
163
164 // In C++ mode, we prefer std::foo to ::foof. But some of these suggestions
165 // are only valid in C++11 and newer.
166 static llvm::StringSet<> Cpp11OnlyFns = {
167 "acosh", "asinh", "atanh", "cbrt", "copysign", "erf",
168 "erfc", "exp2", "expm1", "fdim", "fma", "fmax",
169 "fmin", "hypot", "ilogb", "lgamma", "llrint", "llround",
170 "log1p", "log2", "logb", "lrint", "lround", "nearbyint",
171 "nextafter", "nexttoward", "remainder", "remquo", "rint", "round",
172 "scalbln", "scalbn", "tgamma", "trunc"};
173 bool StdFnRequiresCpp11 = Cpp11OnlyFns.count(OldFnName);
174
175 std::string NewFnName;
176 bool FnInCmath = false;
177 if (getLangOpts().CPlusPlus &&
178 (!StdFnRequiresCpp11 || getLangOpts().CPlusPlus11)) {
179 NewFnName = ("std::" + OldFnName).str();
180 FnInCmath = true;
181 } else {
182 NewFnName = (OldFnName + "f").str();
183 }
184
185 auto Diag = diag(Call->getExprLoc(), "call to '%0' promotes float to double")
186 << OldFnName
187 << FixItHint::CreateReplacement(
188 Call->getCallee()->getSourceRange(), NewFnName);
189
190 // Suggest including <cmath> if the function we're suggesting is declared in
191 // <cmath> and it's not already included. We never have to suggest including
192 // <math.h>, because the functions we're suggesting moving away from are all
193 // declared in <math.h>.
194 if (FnInCmath)
195 if (auto IncludeFixit = IncludeInserter->CreateIncludeInsertion(
196 Result.Context->getSourceManager().getFileID(Call->getBeginLoc()),
197 "cmath", /*IsAngled=*/true))
198 Diag << *IncludeFixit;
199 }
200
201 } // namespace performance
202 } // namespace tidy
203 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:14
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:44
clang::tidy::utils::IncludeSorter::toString
static StringRef toString(IncludeStyle Style)
Converts IncludeStyle to string representation.
Definition: IncludeSorter.cpp:283
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:47
clang::tidy::ClangTidyCheck::getLangOpts
const LangOptions & getLangOpts() const
Returns the language options from the context.
Definition: ClangTidyCheck.h:188
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:184
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:57
clang::tidy::ClangTidyCheck::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: ClangTidyCheck.cpp:58
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:97
TypePromotionInMathFnCheck.h
Pos
Position Pos
Definition: SourceCode.cpp:772
clang::tidy::performance::TypePromotionInMathFnCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: TypePromotionInMathFnCheck.cpp:50
clang::tidy::performance::TypePromotionInMathFnCheck::registerPPCallbacks
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
Definition: TypePromotionInMathFnCheck.cpp:37
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:28
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:77
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:158
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
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: ClangTidyCheck.cpp:21
clang::tidy::readability::AST_MATCHER_P
AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl, ast_matchers::internal::Matcher< CXXMethodDecl >, InnerMatcher)
Definition: ConvertMemberFunctionsToStatic.cpp:52