DurationConversionCastCheck.cpp 3.0 KB

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