13#include "clang/Tooling/FixIt.h"
14#include "llvm/ADT/IndexedMap.h"
23 return static_cast<unsigned>(Scale);
28static std::optional<llvm::APSInt>
30 double Value = FloatLiteral.getValueAsApproximateDouble();
31 if (std::fmod(Value, 1) == 0) {
32 if (Value >=
static_cast<double>(1U << 31))
35 return llvm::APSInt::get(
static_cast<int64_t
>(Value));
40const std::pair<llvm::StringRef, llvm::StringRef> &
42 static const llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>,
47 llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>,
52 std::make_pair(
"::absl::ToDoubleHours",
"::absl::ToInt64Hours");
54 std::make_pair(
"::absl::ToDoubleMinutes",
"::absl::ToInt64Minutes");
56 std::make_pair(
"::absl::ToDoubleSeconds",
"::absl::ToInt64Seconds");
58 "::absl::ToDoubleMilliseconds",
"::absl::ToInt64Milliseconds");
60 "::absl::ToDoubleMicroseconds",
"::absl::ToInt64Microseconds");
62 "::absl::ToDoubleNanoseconds",
"::absl::ToInt64Nanoseconds");
66 return InverseMap[Scale];
71static std::optional<std::string>
74 const std::pair<llvm::StringRef, llvm::StringRef> &InverseFunctions =
76 if (
const auto *MaybeCallArg = selectFirst<const Expr>(
78 match(callExpr(callee(functionDecl(hasAnyName(
79 InverseFunctions.first, InverseFunctions.second))),
80 hasArgument(0, expr().bind(
"e"))),
81 Node, *Result.Context))) {
82 return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
90static std::optional<std::string>
94 if (
const auto *MaybeCallArg = selectFirst<const Expr>(
95 "e", match(callExpr(callee(functionDecl(hasName(InverseFunction))),
96 hasArgument(0, expr().bind(
"e"))),
97 Node, *Result.Context))) {
98 return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
108 return "absl::Hours";
110 return "absl::Minutes";
112 return "absl::Seconds";
114 return "absl::Milliseconds";
116 return "absl::Microseconds";
118 return "absl::Nanoseconds";
120 llvm_unreachable(
"unknown scaling factor");
126 return "absl::FromUnixHours";
128 return "absl::FromUnixMinutes";
130 return "absl::FromUnixSeconds";
132 return "absl::FromUnixMillis";
134 return "absl::FromUnixMicros";
136 return "absl::FromUnixNanos";
138 llvm_unreachable(
"unknown scaling factor");
145 return "absl::ToUnixHours";
147 return "absl::ToUnixMinutes";
149 return "absl::ToUnixSeconds";
151 return "absl::ToUnixMillis";
153 return "absl::ToUnixMicros";
155 return "absl::ToUnixNanos";
157 llvm_unreachable(
"unknown scaling factor");
161bool isLiteralZero(
const MatchFinder::MatchResult &Result,
const Expr &Node) {
163 anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0)));
166 if (selectFirst<const clang::Expr>(
167 "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind(
"val"),
Node,
168 *Result.Context)) !=
nullptr)
173 if (selectFirst<const clang::Expr>(
174 "val", match(cxxFunctionalCastExpr(
176 anyOf(isInteger(), realFloatingPointType())),
177 hasSourceExpression(initListExpr(
178 hasInit(0, ignoringParenImpCasts(ZeroMatcher)))))
180 Node, *Result.Context)) !=
nullptr)
186std::optional<std::string>
189 if (
const Expr *MaybeCastArg = selectFirst<const Expr>(
191 match(expr(anyOf(cxxStaticCastExpr(
192 hasDestinationType(realFloatingPointType()),
193 hasSourceExpression(expr().bind(
"cast_arg"))),
195 hasDestinationType(realFloatingPointType()),
196 hasSourceExpression(expr().bind(
"cast_arg"))),
197 cxxFunctionalCastExpr(
198 hasDestinationType(realFloatingPointType()),
199 hasSourceExpression(expr().bind(
"cast_arg"))))),
200 Node, *Result.Context)))
201 return tooling::fixit::getText(*MaybeCastArg, *Result.Context).str();
206std::optional<std::string>
209 if (
const auto *LitFloat = llvm::dyn_cast<FloatingLiteral>(&
Node))
212 return toString(*IntValue, 10);
224 if (std::optional<std::string> MaybeArg =
229 return tooling::fixit::getText(
Node, *Result.Context).str();
233 static const llvm::StringMap<DurationScale> ScaleMap(
247 auto ScaleIter = ScaleMap.find(
Name);
248 if (ScaleIter == ScaleMap.end())
251 return ScaleIter->second;
255 static const llvm::StringMap<DurationScale> ScaleMap(
263 auto ScaleIter = ScaleMap.find(
Name);
264 if (ScaleIter == ScaleMap.end())
267 return ScaleIter->second;
271 const ast_matchers::MatchFinder::MatchResult &Result,
DurationScale Scale,
273 const Expr &RootNode = *
Node->IgnoreParenImpCasts();
276 if (std::optional<std::string> MaybeRewrite =
278 return *MaybeRewrite;
281 return {
"absl::ZeroDuration()"};
289 const ast_matchers::MatchFinder::MatchResult &Result,
DurationScale Scale,
291 const Expr &RootNode = *
Node->IgnoreParenImpCasts();
294 if (std::optional<std::string> MaybeRewrite =
296 return *MaybeRewrite;
299 return {
"absl::UnixEpoch()"};
302 tooling::fixit::getText(RootNode, *Result.Context) +
")")
306bool isInMacro(
const MatchFinder::MatchResult &Result,
const Expr *
E) {
307 if (!
E->getBeginLoc().isMacroID())
310 SourceLocation
Loc =
E->getBeginLoc();
313 while (Result.SourceManager->isMacroArgExpansion(
Loc)) {
318 Loc = Result.SourceManager->getImmediateMacroCallerLoc(
Loc);
320 return Loc.isMacroID();
llvm::SmallString< 256U > Name
::clang::DynTypedNode Node
const std::pair< llvm::StringRef, llvm::StringRef > & getDurationInverseForScale(DurationScale Scale)
Given a Scale return the fully qualified inverse functions for it.
std::optional< DurationScale > getScaleForTimeInverse(llvm::StringRef Name)
Given the name of an inverse Time function (e.g., ToUnixSeconds), return its DurationScale,...
std::optional< std::string > stripFloatCast(const ast_matchers::MatchFinder::MatchResult &Result, const Expr &Node)
Possibly strip a floating point cast expression.
std::optional< std::string > stripFloatLiteralFraction(const MatchFinder::MatchResult &Result, const Expr &Node)
std::string simplifyDurationFactoryArg(const MatchFinder::MatchResult &Result, const Expr &Node)
bool isLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node)
Returns true if Node is a value which evaluates to a literal 0.
llvm::StringRef getDurationFactoryForScale(DurationScale Scale)
Returns the factory function name for a given Scale.
static std::optional< std::string > rewriteInverseDurationCall(const MatchFinder::MatchResult &Result, DurationScale Scale, const Expr &Node)
If Node is a call to the inverse of Scale, return that inverse's argument, otherwise std::nullopt.
std::string rewriteExprFromNumberToTime(const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale, const Expr *Node)
Assuming Node has a type int representing a time instant of Scale since The Epoch,...
DurationScale
Duration factory and conversion scales.
std::optional< DurationScale > getScaleForDurationInverse(llvm::StringRef Name)
Given the name of an inverse Duration function (e.g., ToDoubleSeconds), return its DurationScale,...
bool isInMacro(const MatchFinder::MatchResult &Result, const Expr *E)
llvm::StringRef getTimeFactoryForScale(DurationScale Scale)
Given a 'Scale', return the appropriate factory function call for constructing a Time for that scale.
std::string rewriteExprFromNumberToDuration(const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale, const Expr *Node)
Assuming Node has type double or int representing a time interval of Scale, return the expression to ...
static std::optional< llvm::APSInt > truncateIfIntegral(const FloatingLiteral &FloatLiteral)
Returns an integer if the fractional part of a FloatingLiteral is 0.
static std::optional< std::string > rewriteInverseTimeCall(const MatchFinder::MatchResult &Result, DurationScale Scale, const Expr &Node)
If Node is a call to the inverse of Scale, return that inverse's argument, otherwise std::nullopt.
llvm::StringRef getTimeInverseForScale(DurationScale Scale)
Returns the Time factory function name for a given Scale.
unsigned operator()(DurationScale Scale) const