12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/Tooling/FixIt.h"
22 void DurationUnnecessaryConversionCheck::registerMatchers(MatchFinder *Finder) {
23 for (
const auto &Scale : {
"Hours",
"Minutes",
"Seconds",
"Milliseconds",
24 "Microseconds",
"Nanoseconds"}) {
25 std::string DurationFactory = (llvm::Twine(
"::absl::") + Scale).str();
26 std::string FloatConversion =
27 (llvm::Twine(
"::absl::ToDouble") + Scale).str();
28 std::string IntegerConversion =
29 (llvm::Twine(
"::absl::ToInt64") + Scale).str();
33 auto factory_matcher = ignoringElidableConstructorCall(
34 callExpr(callee(functionDecl(hasName(DurationFactory))),
35 hasArgument(0, ignoringImpCasts(integerLiteral(equals(1))))));
39 auto inverse_function_matcher = callExpr(
40 callee(functionDecl(hasAnyName(FloatConversion, IntegerConversion))),
41 hasArgument(0, expr().bind(
"arg")));
45 auto division_operator_matcher = cxxOperatorCallExpr(
46 hasOverloadedOperatorName(
"/"), hasArgument(0, expr().bind(
"arg")),
47 hasArgument(1, factory_matcher));
51 auto fdiv_matcher = callExpr(
52 callee(functionDecl(hasName(
"::absl::FDivDuration"))),
53 hasArgument(0, expr().bind(
"arg")), hasArgument(1, factory_matcher));
57 auto scalar_matcher = ignoringImpCasts(
58 binaryOperator(hasOperatorName(
"*"),
59 hasEitherOperand(expr(ignoringParenImpCasts(
60 callExpr(callee(functionDecl(hasAnyName(
61 FloatConversion, IntegerConversion))),
62 hasArgument(0, expr().bind(
"arg")))
63 .bind(
"inner_call")))))
67 callExpr(callee(functionDecl(hasName(DurationFactory))),
68 hasArgument(0, anyOf(inverse_function_matcher,
69 division_operator_matcher, fdiv_matcher,
76 void DurationUnnecessaryConversionCheck::check(
77 const MatchFinder::MatchResult &Result) {
78 const auto *OuterCall = Result.Nodes.getNodeAs<Expr>(
"call");
84 if (
const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>(
"binop")) {
85 const auto *Arg = Result.Nodes.getNodeAs<Expr>(
"arg");
86 const auto *InnerCall = Result.Nodes.getNodeAs<Expr>(
"inner_call");
87 const Expr *LHS = Binop->getLHS();
88 const Expr *RHS = Binop->getRHS();
90 if (LHS->IgnoreParenImpCasts() == InnerCall) {
91 Hint = FixItHint::CreateReplacement(
92 OuterCall->getSourceRange(),
93 (llvm::Twine(tooling::fixit::getText(*Arg, *Result.Context)) +
" * " +
94 tooling::fixit::getText(*RHS, *Result.Context))
97 assert(RHS->IgnoreParenImpCasts() == InnerCall &&
98 "Inner call should be find on the RHS");
100 Hint = FixItHint::CreateReplacement(
101 OuterCall->getSourceRange(),
102 (llvm::Twine(tooling::fixit::getText(*LHS, *Result.Context)) +
" * " +
103 tooling::fixit::getText(*Arg, *Result.Context))
106 }
else if (
const auto *Arg = Result.Nodes.getNodeAs<Expr>(
"arg")) {
107 Hint = FixItHint::CreateReplacement(
108 OuterCall->getSourceRange(),
109 tooling::fixit::getText(*Arg, *Result.Context));
111 diag(OuterCall->getBeginLoc(),
112 "remove unnecessary absl::Duration conversions")