11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 #include "clang/Tooling/FixIt.h"
25 return !clang::Lexer::makeFileCharRange(
26 clang::CharSourceRange::getCharRange(
Range),
27 *Result.SourceManager, Result.Context->getLangOpts())
37 return selectFirst<const Expr>(
40 callExpr(hasParent(materializeTemporaryExpr(hasParent(
41 cxxConstructExpr(hasParent(exprWithCleanups(
42 hasParent(varDecl()))))))))
44 callExpr(hasParent(varDecl())).bind(
"e"))),
45 *Node, *Result.Context)) !=
nullptr;
48 static bool isArgument(
const MatchFinder::MatchResult &Result,
52 return selectFirst<const Expr>(
56 expr(hasParent(materializeTemporaryExpr(
57 hasParent(cxxConstructExpr(
58 hasParent(callExpr()),
59 unless(hasParent(cxxOperatorCallExpr())))))))
61 expr(hasParent(callExpr()),
62 unless(hasParent(cxxOperatorCallExpr())))
64 *Node, *Result.Context)) !=
nullptr;
67 static bool isReturn(
const MatchFinder::MatchResult &Result,
const Expr *Node) {
70 return selectFirst<const Expr>(
73 expr(hasParent(materializeTemporaryExpr(hasParent(
74 cxxConstructExpr(hasParent(exprWithCleanups(
75 hasParent(returnStmt()))))))))
77 expr(hasParent(returnStmt())).bind(
"e"))),
78 *Node, *Result.Context)) !=
nullptr;
90 llvm::StringRef Replacement) {
91 diag(Node->getBeginLoc(),
"perform subtraction in the time domain")
92 << FixItHint::CreateReplacement(Node->getSourceRange(), Replacement);
95 void TimeSubtractionCheck::registerMatchers(MatchFinder *Finder) {
97 {
"Hours",
"Minutes",
"Seconds",
"Millis",
"Micros",
"Nanos"}) {
98 std::string TimeInverse = (llvm::Twine(
"ToUnix") + ScaleName).str();
100 assert(Scale &&
"Unknown scale encountered");
102 auto TimeInverseMatcher = callExpr(callee(
103 functionDecl(hasName((llvm::Twine(
"::absl::") + TimeInverse).str()))
104 .bind(
"func_decl")));
114 hasArgument(0, binaryOperator(hasOperatorName(
"-"),
115 hasLHS(TimeInverseMatcher))
118 Finder->addMatcher(CallMatcher,
this);
123 auto OperandMatcher =
124 binaryOperator(hasOperatorName(
"-"), hasRHS(TimeInverseMatcher))
126 Finder->addMatcher(OperandMatcher,
this);
130 void TimeSubtractionCheck::check(
const MatchFinder::MatchResult &Result) {
131 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binop");
132 std::string InverseName =
141 const auto *OuterCall = Result.Nodes.getNodeAs<CallExpr>(
"outer_call");
153 (llvm::Twine(NeedParens ?
"(" :
"") +
156 (NeedParens ?
")" :
""))
162 const auto *MaybeCallArg = selectFirst<const CallExpr>(
163 "arg",
match(expr(hasAncestor(
164 callExpr(callee(functionDecl(hasName(
167 *BinOp, *Result.Context));
168 if (MaybeCallArg && MaybeCallArg->getArg(0)->IgnoreImpCasts() == BinOp &&
178 (llvm::Twine(NeedParens ?
"(" :
"") +
182 (NeedParens ?
")" :
""))