100f1d767SJonas Toth //===--- DurationComparisonCheck.cpp - clang-tidy -------------------------===//
200f1d767SJonas Toth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
600f1d767SJonas Toth //
700f1d767SJonas Toth //===----------------------------------------------------------------------===//
800f1d767SJonas Toth
900f1d767SJonas Toth #include "DurationComparisonCheck.h"
1000f1d767SJonas Toth #include "DurationRewriter.h"
1100f1d767SJonas Toth #include "clang/AST/ASTContext.h"
1200f1d767SJonas Toth #include "clang/ASTMatchers/ASTMatchFinder.h"
1300f1d767SJonas Toth #include "clang/Tooling/FixIt.h"
1471f55735SKazu Hirata #include <optional>
1500f1d767SJonas Toth
1600f1d767SJonas Toth using namespace clang::ast_matchers;
1700f1d767SJonas Toth
18*7d2ea6c4SCarlos Galvez namespace clang::tidy::abseil {
1900f1d767SJonas Toth
registerMatchers(MatchFinder * Finder)2000f1d767SJonas Toth void DurationComparisonCheck::registerMatchers(MatchFinder *Finder) {
211603447bSHyrum Wright auto Matcher = expr(comparisonOperatorWithCallee(functionDecl(
221603447bSHyrum Wright functionDecl(DurationConversionFunction())
231603447bSHyrum Wright .bind("function_decl"))))
2400f1d767SJonas Toth .bind("binop");
2500f1d767SJonas Toth
2600f1d767SJonas Toth Finder->addMatcher(Matcher, this);
2700f1d767SJonas Toth }
2800f1d767SJonas Toth
check(const MatchFinder::MatchResult & Result)2900f1d767SJonas Toth void DurationComparisonCheck::check(const MatchFinder::MatchResult &Result) {
3000f1d767SJonas Toth const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>("binop");
3100f1d767SJonas Toth
32f71ffd3bSKazu Hirata std::optional<DurationScale> Scale = getScaleForDurationInverse(
3300f1d767SJonas Toth Result.Nodes.getNodeAs<FunctionDecl>("function_decl")->getName());
3400f1d767SJonas Toth if (!Scale)
3500f1d767SJonas Toth return;
3600f1d767SJonas Toth
3700f1d767SJonas Toth // In most cases, we'll only need to rewrite one of the sides, but we also
3800f1d767SJonas Toth // want to handle the case of rewriting both sides. This is much simpler if
3900f1d767SJonas Toth // we unconditionally try and rewrite both, and let the rewriter determine
4000f1d767SJonas Toth // if nothing needs to be done.
418172a0a5SHyrum Wright if (isInMacro(Result, Binop->getLHS()) || isInMacro(Result, Binop->getRHS()))
4200f1d767SJonas Toth return;
4306a8febeSHyrum Wright std::string LhsReplacement =
4406a8febeSHyrum Wright rewriteExprFromNumberToDuration(Result, *Scale, Binop->getLHS());
4506a8febeSHyrum Wright std::string RhsReplacement =
4606a8febeSHyrum Wright rewriteExprFromNumberToDuration(Result, *Scale, Binop->getRHS());
4700f1d767SJonas Toth
4800f1d767SJonas Toth diag(Binop->getBeginLoc(), "perform comparison in the duration domain")
4900f1d767SJonas Toth << FixItHint::CreateReplacement(Binop->getSourceRange(),
5006a8febeSHyrum Wright (llvm::Twine(LhsReplacement) + " " +
5100f1d767SJonas Toth Binop->getOpcodeStr() + " " +
5206a8febeSHyrum Wright RhsReplacement)
5300f1d767SJonas Toth .str());
5400f1d767SJonas Toth }
5500f1d767SJonas Toth
56*7d2ea6c4SCarlos Galvez } // namespace clang::tidy::abseil
57