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 <optional> |
15 | |
16 | using namespace clang::ast_matchers; |
17 | |
18 | namespace clang::tidy::abseil { |
19 | |
20 | // Returns `true` if `Range` is inside a macro definition. |
21 | static bool insideMacroDefinition(const MatchFinder::MatchResult &Result, |
22 | SourceRange Range) { |
23 | return !clang::Lexer::makeFileCharRange( |
24 | Range: clang::CharSourceRange::getCharRange(R: Range), |
25 | SM: *Result.SourceManager, LangOpts: Result.Context->getLangOpts()) |
26 | .isValid(); |
27 | } |
28 | |
29 | void DurationFactoryFloatCheck::registerMatchers(MatchFinder *Finder) { |
30 | Finder->addMatcher( |
31 | NodeMatch: callExpr(callee(InnerMatcher: functionDecl(DurationFactoryFunction())), |
32 | hasArgument(N: 0, InnerMatcher: anyOf(cxxStaticCastExpr(hasDestinationType( |
33 | InnerMatcher: realFloatingPointType())), |
34 | cStyleCastExpr(hasDestinationType( |
35 | InnerMatcher: realFloatingPointType())), |
36 | cxxFunctionalCastExpr(hasDestinationType( |
37 | InnerMatcher: realFloatingPointType())), |
38 | floatLiteral()))) |
39 | .bind(ID: "call" ), |
40 | Action: this); |
41 | } |
42 | |
43 | void DurationFactoryFloatCheck::check(const MatchFinder::MatchResult &Result) { |
44 | const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(ID: "call" ); |
45 | |
46 | // Don't try and replace things inside of macro definitions. |
47 | if (insideMacroDefinition(Result, MatchedCall->getSourceRange())) |
48 | return; |
49 | |
50 | const Expr *Arg = MatchedCall->getArg(Arg: 0)->IgnoreImpCasts(); |
51 | // Arguments which are macros are ignored. |
52 | if (Arg->getBeginLoc().isMacroID()) |
53 | return; |
54 | |
55 | std::optional<std::string> SimpleArg = stripFloatCast(Result, Node: *Arg); |
56 | if (!SimpleArg) |
57 | SimpleArg = stripFloatLiteralFraction(Result, Node: *Arg); |
58 | |
59 | if (SimpleArg) { |
60 | diag(Loc: MatchedCall->getBeginLoc(), Description: "use the integer version of absl::%0" ) |
61 | << MatchedCall->getDirectCallee()->getName() |
62 | << FixItHint::CreateReplacement(Arg->getSourceRange(), *SimpleArg); |
63 | } |
64 | } |
65 | |
66 | } // namespace clang::tidy::abseil |
67 | |