14#include "clang/Tooling/FixIt.h"
21static std::optional<llvm::APSInt>
23 double Value = FloatLiteral.getValueAsApproximateDouble();
24 if (std::fmod(Value, 1) == 0) {
25 if (Value >=
static_cast<double>(1U << 31))
28 return llvm::APSInt::get(
static_cast<int64_t
>(Value));
33const std::pair<llvm::StringRef, llvm::StringRef> &
35 static constexpr std::array<std::pair<llvm::StringRef, llvm::StringRef>, 6>
37 {
"::absl::ToDoubleHours",
"::absl::ToInt64Hours"},
38 {
"::absl::ToDoubleMinutes",
"::absl::ToInt64Minutes"},
39 {
"::absl::ToDoubleSeconds",
"::absl::ToInt64Seconds"},
40 {
"::absl::ToDoubleMilliseconds",
"::absl::ToInt64Milliseconds"},
41 {
"::absl::ToDoubleMicroseconds",
"::absl::ToInt64Microseconds"},
42 {
"::absl::ToDoubleNanoseconds",
"::absl::ToInt64Nanoseconds"},
45 return InverseMap[llvm::to_underlying(Scale)];
50static std::optional<std::string>
53 const std::pair<llvm::StringRef, llvm::StringRef> &InverseFunctions =
55 if (
const auto *MaybeCallArg = selectFirst<const Expr>(
57 match(callExpr(callee(functionDecl(hasAnyName(
58 InverseFunctions.first, InverseFunctions.second))),
59 hasArgument(0, expr().bind(
"e"))),
60 Node, *Result.Context))) {
61 return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
69static std::optional<std::string>
73 if (
const auto *MaybeCallArg = selectFirst<const Expr>(
74 "e", match(callExpr(callee(functionDecl(hasName(InverseFunction))),
75 hasArgument(0, expr().bind(
"e"))),
76 Node, *Result.Context))) {
77 return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
85 static constexpr std::array<llvm::StringRef, 6> FactoryMap = {
86 "absl::Hours",
"absl::Minutes",
"absl::Seconds",
87 "absl::Milliseconds",
"absl::Microseconds",
"absl::Nanoseconds",
90 return FactoryMap[llvm::to_underlying(Scale)];
94 static constexpr std::array<llvm::StringRef, 6> FactoryMap = {
95 "absl::FromUnixHours",
"absl::FromUnixMinutes",
"absl::FromUnixSeconds",
96 "absl::FromUnixMillis",
"absl::FromUnixMicros",
"absl::FromUnixNanos",
99 return FactoryMap[llvm::to_underlying(Scale)];
104 static constexpr std::array<llvm::StringRef, 6> InverseMap = {
105 "absl::ToUnixHours",
"absl::ToUnixMinutes",
"absl::ToUnixSeconds",
106 "absl::ToUnixMillis",
"absl::ToUnixMicros",
"absl::ToUnixNanos",
109 return InverseMap[llvm::to_underlying(Scale)];
113bool isLiteralZero(
const MatchFinder::MatchResult &Result,
const Expr &Node) {
115 anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0)));
118 if (selectFirst<const clang::Expr>(
119 "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind(
"val"), Node,
120 *Result.Context)) !=
nullptr)
125 if (selectFirst<const clang::Expr>(
126 "val", match(cxxFunctionalCastExpr(
128 anyOf(isInteger(), realFloatingPointType())),
129 hasSourceExpression(initListExpr(
130 hasInit(0, ignoringParenImpCasts(ZeroMatcher)))))
132 Node, *Result.Context)) !=
nullptr)
138std::optional<std::string>
141 if (
const Expr *MaybeCastArg = selectFirst<const Expr>(
143 match(expr(anyOf(cxxStaticCastExpr(
144 hasDestinationType(realFloatingPointType()),
145 hasSourceExpression(expr().bind(
"cast_arg"))),
147 hasDestinationType(realFloatingPointType()),
148 hasSourceExpression(expr().bind(
"cast_arg"))),
149 cxxFunctionalCastExpr(
150 hasDestinationType(realFloatingPointType()),
151 hasSourceExpression(expr().bind(
"cast_arg"))))),
152 Node, *Result.Context)))
153 return tooling::fixit::getText(*MaybeCastArg, *Result.Context).str();
158std::optional<std::string>
161 if (
const auto *LitFloat = llvm::dyn_cast<FloatingLiteral>(&Node))
164 return toString(*IntValue, 10);
172 if (std::optional<std::string> MaybeArg =
stripFloatCast(Result, Node))
176 if (std::optional<std::string> MaybeArg =
181 return tooling::fixit::getText(Node, *Result.Context).str();
185 static const llvm::StringMap<DurationScale> ScaleMap(
199 auto ScaleIter = ScaleMap.find(Name);
200 if (ScaleIter == ScaleMap.end())
203 return ScaleIter->second;
207 static const llvm::StringMap<DurationScale> ScaleMap(
215 auto ScaleIter = ScaleMap.find(Name);
216 if (ScaleIter == ScaleMap.end())
219 return ScaleIter->second;
223 const ast_matchers::MatchFinder::MatchResult &Result,
DurationScale Scale,
225 const Expr &RootNode = *Node->IgnoreParenImpCasts();
228 if (std::optional<std::string> MaybeRewrite =
230 return *MaybeRewrite;
233 return {
"absl::ZeroDuration()"};
241 const ast_matchers::MatchFinder::MatchResult &Result,
DurationScale Scale,
243 const Expr &RootNode = *Node->IgnoreParenImpCasts();
246 if (std::optional<std::string> MaybeRewrite =
248 return *MaybeRewrite;
251 return {
"absl::UnixEpoch()"};
254 tooling::fixit::getText(RootNode, *Result.Context) +
")")
258bool isInMacro(
const MatchFinder::MatchResult &Result,
const Expr *E) {
259 if (!E->getBeginLoc().isMacroID())
262 SourceLocation Loc = E->getBeginLoc();
265 while (Result.SourceManager->isMacroArgExpansion(Loc)) {
270 Loc = Result.SourceManager->getImmediateMacroCallerLoc(Loc);
272 return Loc.isMacroID();
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.