1 | //===--- DurationFactoryFloatCheck.cpp - clang-tidy -----------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "DurationFactoryFloatCheck.h" |
10 | #include "DurationRewriter.h" |
11 | #include "clang/AST/ASTContext.h" |
12 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
13 | #include "clang/Lex/Lexer.h" |
14 | #include "clang/Tooling/FixIt.h" |
15 | #include <optional> |
16 | |
17 | using namespace clang::ast_matchers; |
18 | |
19 | namespace clang::tidy::abseil { |
20 | |
21 | // Returns `true` if `Range` is inside a macro definition. |
22 | static bool insideMacroDefinition(const MatchFinder::MatchResult &Result, |
23 | SourceRange Range) { |
24 | return !clang::Lexer::makeFileCharRange( |
25 | Range: clang::CharSourceRange::getCharRange(R: Range), |
26 | SM: *Result.SourceManager, LangOpts: Result.Context->getLangOpts()) |
27 | .isValid(); |
28 | } |
29 | |
30 | void DurationFactoryFloatCheck::registerMatchers(MatchFinder *Finder) { |
31 | Finder->addMatcher( |
32 | NodeMatch: callExpr(callee(InnerMatcher: functionDecl(DurationFactoryFunction())), |
33 | hasArgument(N: 0, InnerMatcher: anyOf(cxxStaticCastExpr(hasDestinationType( |
34 | InnerMatcher: realFloatingPointType())), |
35 | cStyleCastExpr(hasDestinationType( |
36 | InnerMatcher: realFloatingPointType())), |
37 | cxxFunctionalCastExpr(hasDestinationType( |
38 | InnerMatcher: realFloatingPointType())), |
39 | floatLiteral()))) |
40 | .bind(ID: "call" ), |
41 | Action: this); |
42 | } |
43 | |
44 | void DurationFactoryFloatCheck::check(const MatchFinder::MatchResult &Result) { |
45 | const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(ID: "call" ); |
46 | |
47 | // Don't try and replace things inside of macro definitions. |
48 | if (insideMacroDefinition(Result, MatchedCall->getSourceRange())) |
49 | return; |
50 | |
51 | const Expr *Arg = MatchedCall->getArg(Arg: 0)->IgnoreImpCasts(); |
52 | // Arguments which are macros are ignored. |
53 | if (Arg->getBeginLoc().isMacroID()) |
54 | return; |
55 | |
56 | std::optional<std::string> SimpleArg = stripFloatCast(Result, Node: *Arg); |
57 | if (!SimpleArg) |
58 | SimpleArg = stripFloatLiteralFraction(Result, Node: *Arg); |
59 | |
60 | if (SimpleArg) { |
61 | diag(Loc: MatchedCall->getBeginLoc(), Description: "use the integer version of absl::%0" ) |
62 | << MatchedCall->getDirectCallee()->getName() |
63 | << FixItHint::CreateReplacement(Arg->getSourceRange(), *SimpleArg); |
64 | } |
65 | } |
66 | |
67 | } // namespace clang::tidy::abseil |
68 | |