|  | //===--- DurationConversionCastCheck.cpp - clang-tidy ---------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "DurationConversionCastCheck.h" | 
|  | #include "DurationRewriter.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
|  | #include "clang/Tooling/FixIt.h" | 
|  |  | 
|  | using namespace clang::ast_matchers; | 
|  |  | 
|  | namespace clang { | 
|  | namespace tidy { | 
|  | namespace abseil { | 
|  |  | 
|  | void DurationConversionCastCheck::registerMatchers(MatchFinder *Finder) { | 
|  | auto CallMatcher = ignoringImpCasts(callExpr( | 
|  | callee(functionDecl(DurationConversionFunction()).bind("func_decl")), | 
|  | hasArgument(0, expr().bind("arg")))); | 
|  |  | 
|  | Finder->addMatcher( | 
|  | expr(anyOf( | 
|  | cxxStaticCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"), | 
|  | cStyleCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"), | 
|  | cxxFunctionalCastExpr(hasSourceExpression(CallMatcher)) | 
|  | .bind("cast_expr"))), | 
|  | this); | 
|  | } | 
|  |  | 
|  | void DurationConversionCastCheck::check( | 
|  | const MatchFinder::MatchResult &Result) { | 
|  | const auto *MatchedCast = | 
|  | Result.Nodes.getNodeAs<ExplicitCastExpr>("cast_expr"); | 
|  |  | 
|  | if (isInMacro(Result, MatchedCast)) | 
|  | return; | 
|  |  | 
|  | const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("func_decl"); | 
|  | const auto *Arg = Result.Nodes.getNodeAs<Expr>("arg"); | 
|  | StringRef ConversionFuncName = FuncDecl->getName(); | 
|  |  | 
|  | llvm::Optional<DurationScale> Scale = | 
|  | getScaleForDurationInverse(ConversionFuncName); | 
|  | if (!Scale) | 
|  | return; | 
|  |  | 
|  | // Casting a double to an integer. | 
|  | if (MatchedCast->getTypeAsWritten()->isIntegerType() && | 
|  | ConversionFuncName.contains("Double")) { | 
|  | llvm::StringRef NewFuncName = getDurationInverseForScale(*Scale).second; | 
|  |  | 
|  | diag(MatchedCast->getBeginLoc(), | 
|  | "duration should be converted directly to an integer rather than " | 
|  | "through a type cast") | 
|  | << FixItHint::CreateReplacement( | 
|  | MatchedCast->getSourceRange(), | 
|  | (llvm::Twine(NewFuncName.substr(2)) + "(" + | 
|  | tooling::fixit::getText(*Arg, *Result.Context) + ")") | 
|  | .str()); | 
|  | } | 
|  |  | 
|  | // Casting an integer to a double. | 
|  | if (MatchedCast->getTypeAsWritten()->isRealFloatingType() && | 
|  | ConversionFuncName.contains("Int64")) { | 
|  | llvm::StringRef NewFuncName = getDurationInverseForScale(*Scale).first; | 
|  |  | 
|  | diag(MatchedCast->getBeginLoc(), "duration should be converted directly to " | 
|  | "a floating-point number rather than " | 
|  | "through a type cast") | 
|  | << FixItHint::CreateReplacement( | 
|  | MatchedCast->getSourceRange(), | 
|  | (llvm::Twine(NewFuncName.substr(2)) + "(" + | 
|  | tooling::fixit::getText(*Arg, *Result.Context) + ")") | 
|  | .str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | } // namespace abseil | 
|  | } // namespace tidy | 
|  | } // namespace clang |