callee(functionDecl(hasName("::absl::FDivDuration"))),
hasArgument(0, expr().bind("arg")), hasArgument(1, factory_matcher));
+ // Matcher which matches a duration argument being scaled,
+ // e.g. `absl::ToDoubleSeconds(dur) * 2`
+ auto scalar_matcher = ignoringImpCasts(
+ binaryOperator(hasOperatorName("*"),
+ hasEitherOperand(expr(ignoringParenImpCasts(
+ callExpr(callee(functionDecl(hasAnyName(
+ FloatConversion, IntegerConversion))),
+ hasArgument(0, expr().bind("arg")))
+ .bind("inner_call")))))
+ .bind("binop"));
+
Finder->addMatcher(
callExpr(callee(functionDecl(hasName(DurationFactory))),
hasArgument(0, anyOf(inverse_function_matcher,
- division_operator_matcher, fdiv_matcher)))
+ division_operator_matcher, fdiv_matcher,
+ scalar_matcher)))
.bind("call"),
this);
}
void DurationUnnecessaryConversionCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *OuterCall = Result.Nodes.getNodeAs<Expr>("call");
- const auto *Arg = Result.Nodes.getNodeAs<Expr>("arg");
if (isInMacro(Result, OuterCall))
return;
+ FixItHint Hint;
+ if (const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>("binop")) {
+ const auto *Arg = Result.Nodes.getNodeAs<Expr>("arg");
+ const auto *InnerCall = Result.Nodes.getNodeAs<Expr>("inner_call");
+ const Expr *LHS = Binop->getLHS();
+ const Expr *RHS = Binop->getRHS();
+
+ if (LHS->IgnoreParenImpCasts() == InnerCall) {
+ Hint = FixItHint::CreateReplacement(
+ OuterCall->getSourceRange(),
+ (llvm::Twine(tooling::fixit::getText(*Arg, *Result.Context)) + " * " +
+ tooling::fixit::getText(*RHS, *Result.Context))
+ .str());
+ } else {
+ assert(RHS->IgnoreParenImpCasts() == InnerCall &&
+ "Inner call should be find on the RHS");
+
+ Hint = FixItHint::CreateReplacement(
+ OuterCall->getSourceRange(),
+ (llvm::Twine(tooling::fixit::getText(*LHS, *Result.Context)) + " * " +
+ tooling::fixit::getText(*Arg, *Result.Context))
+ .str());
+ }
+ } else if (const auto *Arg = Result.Nodes.getNodeAs<Expr>("arg")) {
+ Hint = FixItHint::CreateReplacement(
+ OuterCall->getSourceRange(),
+ tooling::fixit::getText(*Arg, *Result.Context));
+ }
diag(OuterCall->getBeginLoc(),
"remove unnecessary absl::Duration conversions")
- << FixItHint::CreateReplacement(
- OuterCall->getSourceRange(),
- tooling::fixit::getText(*Arg, *Result.Context));
+ << Hint;
}
} // namespace abseil
d2 = VALUE(d1);
#undef VALUE
+ // Multiplication
+ d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1) * 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = d1 * 2
+ d2 = absl::Microseconds(absl::ToInt64Microseconds(d1) * 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = d1 * 2
+ d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1) * 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = d1 * 2
+ d2 = absl::Seconds(absl::ToInt64Seconds(d1) * 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = d1 * 2
+ d2 = absl::Minutes(absl::ToDoubleMinutes(d1) * 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = d1 * 2
+ d2 = absl::Hours(absl::ToInt64Hours(d1) * 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = d1 * 2
+ d2 = absl::Nanoseconds(2 * absl::ToDoubleNanoseconds(d1));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = 2 * d1
+ d2 = absl::Microseconds(2 * absl::ToInt64Microseconds(d1));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = 2 * d1
+ d2 = absl::Milliseconds(2 * absl::ToDoubleMilliseconds(d1));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = 2 * d1
+ d2 = absl::Seconds(2 * absl::ToInt64Seconds(d1));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = 2 * d1
+ d2 = absl::Minutes(2 * absl::ToDoubleMinutes(d1));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = 2 * d1
+ d2 = absl::Hours(2 * absl::ToInt64Hours(d1));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion]
+ // CHECK-FIXES: d2 = 2 * d1
+
// These should not match
d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1));
d2 = absl::Seconds(4);
d2 = absl::Seconds(d1 / absl::Seconds(30));
d2 = absl::Hours(absl::FDivDuration(d1, absl::Minutes(1)));
d2 = absl::Milliseconds(absl::FDivDuration(d1, absl::Milliseconds(20)));
+ d2 = absl::Seconds(absl::ToInt64Milliseconds(d1) * 2);
+ d2 = absl::Milliseconds(absl::ToDoubleSeconds(d1) * 2);
}