11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Tooling/FixIt.h" 24 static llvm::Optional<DurationScale>
26 static const std::unordered_map<std::string, DurationScale> ScaleMap(
27 {{
"Nanoseconds", DurationScale::Nanoseconds},
28 {
"Microseconds", DurationScale::Microseconds},
29 {
"Milliseconds", DurationScale::Milliseconds},
30 {
"Seconds", DurationScale::Seconds},
31 {
"Minutes", DurationScale::Minutes},
32 {
"Hours", DurationScale::Hours}});
34 auto ScaleIter = ScaleMap.find(FactoryName);
35 if (ScaleIter == ScaleMap.end())
38 return ScaleIter->second;
43 static double GetValue(
const IntegerLiteral *IntLit,
44 const FloatingLiteral *FloatLit) {
46 return IntLit->getValue().getLimitedValue();
48 assert(FloatLit !=
nullptr &&
"Neither IntLit nor FloatLit set");
49 return FloatLit->getValueAsApproximateDouble();
55 static llvm::Optional<std::tuple<DurationScale, double>>
58 case DurationScale::Hours:
59 if (Multiplier <= 1.0 / 60.0)
60 return std::make_tuple(DurationScale::Minutes, Multiplier * 60.0);
63 case DurationScale::Minutes:
64 if (Multiplier >= 60.0)
65 return std::make_tuple(DurationScale::Hours, Multiplier / 60.0);
66 if (Multiplier <= 1.0 / 60.0)
67 return std::make_tuple(DurationScale::Seconds, Multiplier * 60.0);
70 case DurationScale::Seconds:
71 if (Multiplier >= 60.0)
72 return std::make_tuple(DurationScale::Minutes, Multiplier / 60.0);
73 if (Multiplier <= 1e-3)
74 return std::make_tuple(DurationScale::Milliseconds, Multiplier * 1e3);
77 case DurationScale::Milliseconds:
78 if (Multiplier >= 1e3)
79 return std::make_tuple(DurationScale::Seconds, Multiplier / 1e3);
80 if (Multiplier <= 1e-3)
81 return std::make_tuple(DurationScale::Microseconds, Multiplier * 1e3);
84 case DurationScale::Microseconds:
85 if (Multiplier >= 1e3)
86 return std::make_tuple(DurationScale::Milliseconds, Multiplier / 1e3);
87 if (Multiplier <= 1e-3)
88 return std::make_tuple(DurationScale::Nanoseconds, Multiplier * 1e-3);
91 case DurationScale::Nanoseconds:
92 if (Multiplier >= 1e3)
93 return std::make_tuple(DurationScale::Microseconds, Multiplier / 1e3);
104 while (Multiplier != 1.0) {
105 llvm::Optional<std::tuple<DurationScale, double>> result =
109 if (std::get<1>(*result) == 1.0)
110 return std::get<0>(*result);
111 Multiplier = std::get<1>(*result);
112 OldScale = std::get<0>(*result);
118 void DurationFactoryScaleCheck::registerMatchers(MatchFinder *Finder) {
121 callee(functionDecl(DurationFactoryFunction()).bind(
"call_decl")),
124 ignoringImpCasts(anyOf(
125 cxxFunctionalCastExpr(
127 anyOf(isInteger(), realFloatingPointType())),
128 hasSourceExpression(initListExpr())),
129 integerLiteral(equals(0)), floatLiteral(equals(0.0)),
130 binaryOperator(hasOperatorName(
"*"),
131 hasEitherOperand(ignoringImpCasts(
132 anyOf(integerLiteral(), floatLiteral()))))
134 binaryOperator(hasOperatorName(
"/"), hasRHS(floatLiteral()))
135 .bind(
"div_binop")))))
140 void DurationFactoryScaleCheck::check(
const MatchFinder::MatchResult &
Result) {
141 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
144 if (Call->getExprLoc().isMacroID())
147 const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
149 if (Arg->getBeginLoc().isMacroID())
154 diag(Call->getBeginLoc(),
155 "use ZeroDuration() for zero-length time intervals")
156 << FixItHint::CreateReplacement(Call->getSourceRange(),
157 "absl::ZeroDuration()");
161 const auto *CallDecl = Result.Nodes.getNodeAs<FunctionDecl>(
"call_decl");
162 llvm::Optional<DurationScale> MaybeScale =
168 const Expr *Remainder;
169 llvm::Optional<DurationScale> NewScale;
172 if (
const auto *MultBinOp =
173 Result.Nodes.getNodeAs<BinaryOperator>(
"mult_binop")) {
178 const auto *IntLit = llvm::dyn_cast<IntegerLiteral>(MultBinOp->getLHS());
179 const auto *FloatLit = llvm::dyn_cast<FloatingLiteral>(MultBinOp->getLHS());
180 if (IntLit || FloatLit) {
183 Remainder = MultBinOp->getRHS();
188 IntLit = llvm::dyn_cast<IntegerLiteral>(MultBinOp->getRHS());
189 FloatLit = llvm::dyn_cast<FloatingLiteral>(MultBinOp->getRHS());
190 if (IntLit || FloatLit) {
193 Remainder = MultBinOp->getLHS();
196 }
else if (
const auto *DivBinOp =
197 Result.Nodes.getNodeAs<BinaryOperator>(
"div_binop")) {
200 const auto *FloatLit = llvm::dyn_cast<FloatingLiteral>(DivBinOp->getRHS());
202 llvm::Optional<DurationScale> NewScale =
203 GetNewScale(Scale, 1.0 / FloatLit->getValueAsApproximateDouble());
205 const Expr *Remainder = DivBinOp->getLHS();
209 diag(Call->getBeginLoc(),
"internal duration scaling can be removed")
210 << FixItHint::CreateReplacement(
211 Call->getSourceRange(),
213 tooling::fixit::getText(*Remainder, *Result.Context) +
")")
219 assert(Remainder &&
"No remainder found");
222 diag(Call->getBeginLoc(),
"internal duration scaling can be removed")
223 << FixItHint::CreateReplacement(
224 Call->getSourceRange(),
226 tooling::fixit::getText(*Remainder, *Result.Context) +
")")
static llvm::Optional< std::tuple< DurationScale, double > > GetNewScaleSingleStep(DurationScale OldScale, double Multiplier)
static llvm::Optional< DurationScale > GetNewScale(DurationScale OldScale, double Multiplier)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static double GetValue(const IntegerLiteral *IntLit, const FloatingLiteral *FloatLit)
static llvm::Optional< DurationScale > getScaleForFactory(llvm::StringRef FactoryName)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
llvm::StringRef getDurationFactoryForScale(DurationScale Scale)
Returns the factory function name for a given Scale.
bool IsLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node)
Returns true if Node is a value which evaluates to a literal 0.
DurationScale
Duration factory and conversion scales.