10 #include "clang/Tooling/FixIt.h"
11 #include "llvm/ADT/IndexedMap.h"
22 return static_cast<unsigned>(Scale);
27 static llvm::Optional<llvm::APSInt>
29 double Value = FloatLiteral.getValueAsApproximateDouble();
30 if (std::fmod(Value, 1) == 0) {
31 if (Value >= static_cast<double>(1u << 31))
34 return llvm::APSInt::get(static_cast<int64_t>(Value));
39 const std::pair<llvm::StringRef, llvm::StringRef> &
41 static const llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>,
46 llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>,
50 InverseMap[DurationScale::Hours] =
51 std::make_pair(
"::absl::ToDoubleHours",
"::absl::ToInt64Hours");
52 InverseMap[DurationScale::Minutes] =
53 std::make_pair(
"::absl::ToDoubleMinutes",
"::absl::ToInt64Minutes");
54 InverseMap[DurationScale::Seconds] =
55 std::make_pair(
"::absl::ToDoubleSeconds",
"::absl::ToInt64Seconds");
56 InverseMap[DurationScale::Milliseconds] = std::make_pair(
57 "::absl::ToDoubleMilliseconds",
"::absl::ToInt64Milliseconds");
58 InverseMap[DurationScale::Microseconds] = std::make_pair(
59 "::absl::ToDoubleMicroseconds",
"::absl::ToInt64Microseconds");
60 InverseMap[DurationScale::Nanoseconds] = std::make_pair(
61 "::absl::ToDoubleNanoseconds",
"::absl::ToInt64Nanoseconds");
65 return InverseMap[Scale];
70 static llvm::Optional<std::string>
73 const std::pair<llvm::StringRef, llvm::StringRef> &InverseFunctions =
75 if (
const auto *MaybeCallArg = selectFirst<const Expr>(
77 match(callExpr(callee(functionDecl(hasAnyName(
78 InverseFunctions.first, InverseFunctions.second))),
79 hasArgument(0, expr().bind(
"e"))),
80 Node, *Result.Context))) {
81 return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
89 static llvm::Optional<std::string>
93 if (
const auto *MaybeCallArg = selectFirst<const Expr>(
94 "e",
match(callExpr(callee(functionDecl(hasName(InverseFunction))),
95 hasArgument(0, expr().bind(
"e"))),
96 Node, *Result.Context))) {
97 return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
106 case DurationScale::Hours:
107 return "absl::Hours";
108 case DurationScale::Minutes:
109 return "absl::Minutes";
110 case DurationScale::Seconds:
111 return "absl::Seconds";
112 case DurationScale::Milliseconds:
113 return "absl::Milliseconds";
114 case DurationScale::Microseconds:
115 return "absl::Microseconds";
116 case DurationScale::Nanoseconds:
117 return "absl::Nanoseconds";
119 llvm_unreachable(
"unknown scaling factor");
124 case DurationScale::Hours:
125 return "absl::FromUnixHours";
126 case DurationScale::Minutes:
127 return "absl::FromUnixMinutes";
128 case DurationScale::Seconds:
129 return "absl::FromUnixSeconds";
130 case DurationScale::Milliseconds:
131 return "absl::FromUnixMillis";
132 case DurationScale::Microseconds:
133 return "absl::FromUnixMicros";
134 case DurationScale::Nanoseconds:
135 return "absl::FromUnixNanos";
137 llvm_unreachable(
"unknown scaling factor");
143 case DurationScale::Hours:
144 return "absl::ToUnixHours";
145 case DurationScale::Minutes:
146 return "absl::ToUnixMinutes";
147 case DurationScale::Seconds:
148 return "absl::ToUnixSeconds";
149 case DurationScale::Milliseconds:
150 return "absl::ToUnixMillis";
151 case DurationScale::Microseconds:
152 return "absl::ToUnixMicros";
153 case DurationScale::Nanoseconds:
154 return "absl::ToUnixNanos";
156 llvm_unreachable(
"unknown scaling factor");
160 bool IsLiteralZero(
const MatchFinder::MatchResult &Result,
const Expr &Node) {
162 anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0)));
165 if (selectFirst<const clang::Expr>(
166 "val",
match(expr(ignoringImpCasts(ZeroMatcher)).bind(
"val"), Node,
167 *Result.Context)) !=
nullptr)
172 if (selectFirst<const clang::Expr>(
173 "val",
match(cxxFunctionalCastExpr(
175 anyOf(isInteger(), realFloatingPointType())),
176 hasSourceExpression(initListExpr(
177 hasInit(0, ignoringParenImpCasts(ZeroMatcher)))))
179 Node, *Result.Context)) !=
nullptr)
185 llvm::Optional<std::string>
188 if (
const Expr *MaybeCastArg = selectFirst<const Expr>(
190 match(expr(anyOf(cxxStaticCastExpr(
191 hasDestinationType(realFloatingPointType()),
192 hasSourceExpression(expr().bind(
"cast_arg"))),
194 hasDestinationType(realFloatingPointType()),
195 hasSourceExpression(expr().bind(
"cast_arg"))),
196 cxxFunctionalCastExpr(
197 hasDestinationType(realFloatingPointType()),
198 hasSourceExpression(expr().bind(
"cast_arg"))))),
199 Node, *Result.Context)))
200 return tooling::fixit::getText(*MaybeCastArg, *Result.Context).str();
205 llvm::Optional<std::string>
208 if (
const auto *LitFloat = llvm::dyn_cast<FloatingLiteral>(&Node))
211 return IntValue->toString(10);
219 if (llvm::Optional<std::string> MaybeArg =
stripFloatCast(Result, Node))
223 if (llvm::Optional<std::string> MaybeArg =
228 return tooling::fixit::getText(Node, *Result.Context).str();
232 static const llvm::StringMap<DurationScale> ScaleMap(
233 {{
"ToDoubleHours", DurationScale::Hours},
234 {
"ToInt64Hours", DurationScale::Hours},
235 {
"ToDoubleMinutes", DurationScale::Minutes},
236 {
"ToInt64Minutes", DurationScale::Minutes},
237 {
"ToDoubleSeconds", DurationScale::Seconds},
238 {
"ToInt64Seconds", DurationScale::Seconds},
239 {
"ToDoubleMilliseconds", DurationScale::Milliseconds},
240 {
"ToInt64Milliseconds", DurationScale::Milliseconds},
241 {
"ToDoubleMicroseconds", DurationScale::Microseconds},
242 {
"ToInt64Microseconds", DurationScale::Microseconds},
243 {
"ToDoubleNanoseconds", DurationScale::Nanoseconds},
244 {
"ToInt64Nanoseconds", DurationScale::Nanoseconds}});
246 auto ScaleIter = ScaleMap.find(std::string(
Name));
247 if (ScaleIter == ScaleMap.end())
250 return ScaleIter->second;
254 static const llvm::StringMap<DurationScale> ScaleMap(
255 {{
"ToUnixHours", DurationScale::Hours},
256 {
"ToUnixMinutes", DurationScale::Minutes},
257 {
"ToUnixSeconds", DurationScale::Seconds},
258 {
"ToUnixMillis", DurationScale::Milliseconds},
259 {
"ToUnixMicros", DurationScale::Microseconds},
260 {
"ToUnixNanos", DurationScale::Nanoseconds}});
262 auto ScaleIter = ScaleMap.find(std::string(
Name));
263 if (ScaleIter == ScaleMap.end())
266 return ScaleIter->second;
270 const ast_matchers::MatchFinder::MatchResult &Result,
DurationScale Scale,
272 const Expr &RootNode = *Node->IgnoreParenImpCasts();
275 if (llvm::Optional<std::string> MaybeRewrite =
277 return *MaybeRewrite;
280 return std::string(
"absl::ZeroDuration()");
288 const ast_matchers::MatchFinder::MatchResult &Result,
DurationScale Scale,
290 const Expr &RootNode = *Node->IgnoreParenImpCasts();
293 if (llvm::Optional<std::string> MaybeRewrite =
295 return *MaybeRewrite;
298 return std::string(
"absl::UnixEpoch()");
301 tooling::fixit::getText(RootNode, *Result.Context) +
")")
305 bool isInMacro(
const MatchFinder::MatchResult &Result,
const Expr *
E) {
306 if (!
E->getBeginLoc().isMacroID())
309 SourceLocation
Loc =
E->getBeginLoc();
312 while (Result.SourceManager->isMacroArgExpansion(
Loc)) {
317 Loc = Result.SourceManager->getImmediateMacroCallerLoc(
Loc);
319 return Loc.isMacroID();