1 //===--- DurationConversionCastCheck.cpp - clang-tidy ---------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DurationConversionCastCheck.h"
10 #include "DurationRewriter.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Tooling/FixIt.h"
16 using namespace clang::ast_matchers
;
18 namespace clang::tidy::abseil
{
20 void DurationConversionCastCheck::registerMatchers(MatchFinder
*Finder
) {
21 auto CallMatcher
= ignoringImpCasts(callExpr(
22 callee(functionDecl(DurationConversionFunction()).bind("func_decl")),
23 hasArgument(0, expr().bind("arg"))));
27 cxxStaticCastExpr(hasSourceExpression(CallMatcher
)).bind("cast_expr"),
28 cStyleCastExpr(hasSourceExpression(CallMatcher
)).bind("cast_expr"),
29 cxxFunctionalCastExpr(hasSourceExpression(CallMatcher
))
34 void DurationConversionCastCheck::check(
35 const MatchFinder::MatchResult
&Result
) {
36 const auto *MatchedCast
=
37 Result
.Nodes
.getNodeAs
<ExplicitCastExpr
>("cast_expr");
39 if (isInMacro(Result
, MatchedCast
))
42 const auto *FuncDecl
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("func_decl");
43 const auto *Arg
= Result
.Nodes
.getNodeAs
<Expr
>("arg");
44 StringRef ConversionFuncName
= FuncDecl
->getName();
46 std::optional
<DurationScale
> Scale
=
47 getScaleForDurationInverse(ConversionFuncName
);
51 // Casting a double to an integer.
52 if (MatchedCast
->getTypeAsWritten()->isIntegerType() &&
53 ConversionFuncName
.contains("Double")) {
54 llvm::StringRef NewFuncName
= getDurationInverseForScale(*Scale
).second
;
56 diag(MatchedCast
->getBeginLoc(),
57 "duration should be converted directly to an integer rather than "
58 "through a type cast")
59 << FixItHint::CreateReplacement(
60 MatchedCast
->getSourceRange(),
61 (llvm::Twine(NewFuncName
.substr(2)) + "(" +
62 tooling::fixit::getText(*Arg
, *Result
.Context
) + ")")
66 // Casting an integer to a double.
67 if (MatchedCast
->getTypeAsWritten()->isRealFloatingType() &&
68 ConversionFuncName
.contains("Int64")) {
69 llvm::StringRef NewFuncName
= getDurationInverseForScale(*Scale
).first
;
71 diag(MatchedCast
->getBeginLoc(), "duration should be converted directly to "
72 "a floating-point number rather than "
73 "through a type cast")
74 << FixItHint::CreateReplacement(
75 MatchedCast
->getSourceRange(),
76 (llvm::Twine(NewFuncName
.substr(2)) + "(" +
77 tooling::fixit::getText(*Arg
, *Result
.Context
) + ")")
82 } // namespace clang::tidy::abseil