@@ -52,10 +52,22 @@ void DurationUnnecessaryConversionCheck::registerMatchers(MatchFinder *Finder) {
5252 callee (functionDecl (hasName (" ::absl::FDivDuration" ))),
5353 hasArgument (0 , expr ().bind (" arg" )), hasArgument (1 , factory_matcher));
5454
55+ // Matcher which matches a duration argument being scaled,
56+ // e.g. `absl::ToDoubleSeconds(dur) * 2`
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" )))))
64+ .bind (" binop" ));
65+
5566 Finder->addMatcher (
5667 callExpr (callee (functionDecl (hasName (DurationFactory))),
5768 hasArgument (0 , anyOf (inverse_function_matcher,
58- division_operator_matcher, fdiv_matcher)))
69+ division_operator_matcher, fdiv_matcher,
70+ scalar_matcher)))
5971 .bind (" call" ),
6072 this );
6173 }
@@ -64,16 +76,41 @@ void DurationUnnecessaryConversionCheck::registerMatchers(MatchFinder *Finder) {
6476void DurationUnnecessaryConversionCheck::check (
6577 const MatchFinder::MatchResult &Result) {
6678 const auto *OuterCall = Result.Nodes .getNodeAs <Expr>(" call" );
67- const auto *Arg = Result.Nodes .getNodeAs <Expr>(" arg" );
6879
6980 if (isInMacro (Result, OuterCall))
7081 return ;
7182
83+ FixItHint Hint;
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 ();
89+
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 ))
95+ .str ());
96+ } else {
97+ assert (RHS->IgnoreParenImpCasts () == InnerCall &&
98+ " Inner call should be find on the RHS" );
99+
100+ Hint = FixItHint::CreateReplacement (
101+ OuterCall->getSourceRange (),
102+ (llvm::Twine (tooling::fixit::getText (*LHS, *Result.Context )) + " * " +
103+ tooling::fixit::getText (*Arg, *Result.Context ))
104+ .str ());
105+ }
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 ));
110+ }
72111 diag (OuterCall->getBeginLoc (),
73112 " remove unnecessary absl::Duration conversions" )
74- << FixItHint::CreateReplacement (
75- OuterCall->getSourceRange (),
76- tooling::fixit::getText (*Arg, *Result.Context ));
113+ << Hint;
77114}
78115
79116} // namespace abseil
0 commit comments