11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Tooling/FixIt.h"
23static std::optional<DurationScale>
25 return llvm::StringSwitch<std::optional<DurationScale>>(FactoryName)
32 .Default(std::nullopt);
37static double getValue(
const IntegerLiteral *IntLit,
38 const FloatingLiteral *FloatLit) {
40 return IntLit->getValue().getLimitedValue();
42 assert(FloatLit !=
nullptr &&
"Neither IntLit nor FloatLit set");
43 return FloatLit->getValueAsApproximateDouble();
49static std::optional<std::tuple<DurationScale, double>>
53 if (Multiplier <= 1.0 / 60.0)
58 if (Multiplier >= 60.0)
60 if (Multiplier <= 1.0 / 60.0)
65 if (Multiplier >= 60.0)
67 if (Multiplier <= 1e-3)
72 if (Multiplier >= 1e3)
74 if (Multiplier <= 1e-3)
79 if (Multiplier >= 1e3)
81 if (Multiplier <= 1e-3)
86 if (Multiplier >= 1e3)
98 while (Multiplier != 1.0) {
99 std::optional<std::tuple<DurationScale, double>> Result =
103 if (std::get<1>(*Result) == 1.0)
104 return std::get<0>(*Result);
105 Multiplier = std::get<1>(*Result);
106 OldScale = std::get<0>(*Result);
115 callee(functionDecl(DurationFactoryFunction()).bind(
"call_decl")),
118 ignoringImpCasts(anyOf(
119 cxxFunctionalCastExpr(
121 anyOf(isInteger(), realFloatingPointType())),
122 hasSourceExpression(initListExpr())),
123 integerLiteral(equals(0)), floatLiteral(equals(0.0)),
124 binaryOperator(hasOperatorName(
"*"),
125 hasEitherOperand(ignoringImpCasts(
126 anyOf(integerLiteral(), floatLiteral()))))
128 binaryOperator(hasOperatorName(
"/"), hasRHS(floatLiteral()))
129 .bind(
"div_binop")))))
135 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
138 if (Call->getExprLoc().isMacroID())
141 const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
143 if (Arg->getBeginLoc().isMacroID())
148 diag(Call->getBeginLoc(),
149 "use ZeroDuration() for zero-length time intervals")
150 << FixItHint::CreateReplacement(Call->getSourceRange(),
151 "absl::ZeroDuration()");
155 const auto *CallDecl = Result.Nodes.getNodeAs<FunctionDecl>(
"call_decl");
156 std::optional<DurationScale> MaybeScale =
162 const Expr *Remainder =
nullptr;
163 std::optional<DurationScale> NewScale;
166 if (
const auto *MultBinOp =
167 Result.Nodes.getNodeAs<BinaryOperator>(
"mult_binop")) {
172 const auto *IntLit = llvm::dyn_cast<IntegerLiteral>(MultBinOp->getLHS());
173 const auto *FloatLit = llvm::dyn_cast<FloatingLiteral>(MultBinOp->getLHS());
174 if (IntLit || FloatLit) {
177 Remainder = MultBinOp->getRHS();
182 IntLit = llvm::dyn_cast<IntegerLiteral>(MultBinOp->getRHS());
183 FloatLit = llvm::dyn_cast<FloatingLiteral>(MultBinOp->getRHS());
184 if (IntLit || FloatLit) {
187 Remainder = MultBinOp->getLHS();
190 }
else if (
const auto *DivBinOp =
191 Result.Nodes.getNodeAs<BinaryOperator>(
"div_binop")) {
194 const auto *FloatLit = llvm::cast<FloatingLiteral>(DivBinOp->getRHS());
196 std::optional<DurationScale> NewScale =
197 getNewScale(Scale, 1.0 / FloatLit->getValueAsApproximateDouble());
199 const Expr *Remainder = DivBinOp->getLHS();
203 diag(Call->getBeginLoc(),
"internal duration scaling can be removed")
204 << FixItHint::CreateReplacement(
205 Call->getSourceRange(),
207 tooling::fixit::getText(*Remainder, *Result.Context) +
")")
213 assert(Remainder &&
"No remainder found");
216 diag(Call->getBeginLoc(),
"internal duration scaling can be removed")
217 << FixItHint::CreateReplacement(
218 Call->getSourceRange(),
220 tooling::fixit::getText(*Remainder, *Result.Context) +
")")
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static std::optional< std::tuple< DurationScale, double > > getNewScaleSingleStep(DurationScale OldScale, double Multiplier)
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 double getValue(const IntegerLiteral *IntLit, const FloatingLiteral *FloatLit)
DurationScale
Duration factory and conversion scales.
static std::optional< DurationScale > getScaleForFactory(llvm::StringRef FactoryName)
static std::optional< DurationScale > getNewScale(DurationScale OldScale, double Multiplier)