85 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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(callExpr(22 callee(functionDecl(durationConversionFunction()).bind("func_decl")),23 hasArgument(0, expr().bind("arg"))));24 25 Finder->addMatcher(26 expr(anyOf(27 cxxStaticCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"),28 cStyleCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"),29 cxxFunctionalCastExpr(hasSourceExpression(CallMatcher))30 .bind("cast_expr"))),31 this);32}33 34void DurationConversionCastCheck::check(35 const MatchFinder::MatchResult &Result) {36 const auto *MatchedCast =37 Result.Nodes.getNodeAs<ExplicitCastExpr>("cast_expr");38 39 if (isInMacro(Result, MatchedCast))40 return;41 42 const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");43 const auto *Arg = Result.Nodes.getNodeAs<Expr>("arg");44 const StringRef ConversionFuncName = FuncDecl->getName();45 46 std::optional<DurationScale> Scale =47 getScaleForDurationInverse(ConversionFuncName);48 if (!Scale)49 return;50 51 // Casting a double to an integer.52 if (MatchedCast->getTypeAsWritten()->isIntegerType() &&53 ConversionFuncName.contains("Double")) {54 const llvm::StringRef NewFuncName =55 getDurationInverseForScale(*Scale).second;56 57 diag(MatchedCast->getBeginLoc(),58 "duration should be converted directly to an integer rather than "59 "through a type cast")60 << FixItHint::CreateReplacement(61 MatchedCast->getSourceRange(),62 (llvm::Twine(NewFuncName.substr(2)) + "(" +63 tooling::fixit::getText(*Arg, *Result.Context) + ")")64 .str());65 }66 67 // Casting an integer to a double.68 if (MatchedCast->getTypeAsWritten()->isRealFloatingType() &&69 ConversionFuncName.contains("Int64")) {70 const llvm::StringRef NewFuncName =71 getDurationInverseForScale(*Scale).first;72 73 diag(MatchedCast->getBeginLoc(), "duration should be converted directly to "74 "a floating-point number rather than "75 "through a type cast")76 << FixItHint::CreateReplacement(77 MatchedCast->getSourceRange(),78 (llvm::Twine(NewFuncName.substr(2)) + "(" +79 tooling::fixit::getText(*Arg, *Result.Context) + ")")80 .str());81 }82}83 84} // namespace clang::tidy::abseil85