1//===--- DurationConversionCastCheck.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 "DurationConversionCastCheck.h"
10#include "DurationRewriter.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Tooling/FixIt.h"
14#include <optional>
15
16using namespace clang::ast_matchers;
17
18namespace clang::tidy::abseil {
19
20void DurationConversionCastCheck::registerMatchers(MatchFinder *Finder) {
21 auto CallMatcher = ignoringImpCasts(InnerMatcher: callExpr(
22 callee(InnerMatcher: functionDecl(DurationConversionFunction()).bind(ID: "func_decl")),
23 hasArgument(N: 0, InnerMatcher: expr().bind(ID: "arg"))));
24
25 Finder->addMatcher(
26 NodeMatch: expr(anyOf(
27 cxxStaticCastExpr(hasSourceExpression(InnerMatcher: CallMatcher)).bind(ID: "cast_expr"),
28 cStyleCastExpr(hasSourceExpression(InnerMatcher: CallMatcher)).bind(ID: "cast_expr"),
29 cxxFunctionalCastExpr(hasSourceExpression(InnerMatcher: CallMatcher))
30 .bind(ID: "cast_expr"))),
31 Action: this);
32}
33
34void DurationConversionCastCheck::check(
35 const MatchFinder::MatchResult &Result) {
36 const auto *MatchedCast =
37 Result.Nodes.getNodeAs<ExplicitCastExpr>(ID: "cast_expr");
38
39 if (isInMacro(Result, MatchedCast))
40 return;
41
42 const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>(ID: "func_decl");
43 const auto *Arg = Result.Nodes.getNodeAs<Expr>(ID: "arg");
44 StringRef ConversionFuncName = FuncDecl->getName();
45
46 std::optional<DurationScale> Scale =
47 getScaleForDurationInverse(Name: ConversionFuncName);
48 if (!Scale)
49 return;
50
51 // Casting a double to an integer.
52 if (MatchedCast->getTypeAsWritten()->isIntegerType() &&
53 ConversionFuncName.contains(Other: "Double")) {
54 llvm::StringRef NewFuncName = getDurationInverseForScale(Scale: *Scale).second;
55
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(Start: 2)) + "(" +
62 tooling::fixit::getText(Node: *Arg, Context: *Result.Context) + ")")
63 .str());
64 }
65
66 // Casting an integer to a double.
67 if (MatchedCast->getTypeAsWritten()->isRealFloatingType() &&
68 ConversionFuncName.contains(Other: "Int64")) {
69 llvm::StringRef NewFuncName = getDurationInverseForScale(Scale: *Scale).first;
70
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(Start: 2)) + "(" +
77 tooling::fixit::getText(Node: *Arg, Context: *Result.Context) + ")")
78 .str());
79 }
80}
81
82} // namespace clang::tidy::abseil
83

source code of clang-tools-extra/clang-tidy/abseil/DurationConversionCastCheck.cpp