MisplacedPointerArithmeticInAllocCheck.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //===--- MisplacedPointerArithmeticInAllocCheck.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 "MisplacedPointerArithmeticInAllocCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/Lex/Lexer.h"
  12. using namespace clang::ast_matchers;
  13. namespace clang::tidy::bugprone {
  14. void MisplacedPointerArithmeticInAllocCheck::registerMatchers(
  15. MatchFinder *Finder) {
  16. const auto AllocFunc =
  17. functionDecl(hasAnyName("::malloc", "std::malloc", "::alloca", "::calloc",
  18. "std::calloc", "::realloc", "std::realloc"));
  19. const auto AllocFuncPtr =
  20. varDecl(hasType(isConstQualified()),
  21. hasInitializer(ignoringParenImpCasts(
  22. declRefExpr(hasDeclaration(AllocFunc)))));
  23. const auto AdditiveOperator = binaryOperator(hasAnyOperatorName("+", "-"));
  24. const auto IntExpr = expr(hasType(isInteger()));
  25. const auto AllocCall = callExpr(callee(decl(anyOf(AllocFunc, AllocFuncPtr))));
  26. Finder->addMatcher(
  27. binaryOperator(
  28. AdditiveOperator,
  29. hasLHS(anyOf(AllocCall, castExpr(hasSourceExpression(AllocCall)))),
  30. hasRHS(IntExpr))
  31. .bind("PtrArith"),
  32. this);
  33. const auto New = cxxNewExpr(unless(isArray()));
  34. Finder->addMatcher(binaryOperator(AdditiveOperator,
  35. hasLHS(anyOf(New, castExpr(New))),
  36. hasRHS(IntExpr))
  37. .bind("PtrArith"),
  38. this);
  39. const auto ArrayNew = cxxNewExpr(isArray());
  40. Finder->addMatcher(binaryOperator(AdditiveOperator,
  41. hasLHS(anyOf(ArrayNew, castExpr(ArrayNew))),
  42. hasRHS(IntExpr))
  43. .bind("PtrArith"),
  44. this);
  45. }
  46. void MisplacedPointerArithmeticInAllocCheck::check(
  47. const MatchFinder::MatchResult &Result) {
  48. const auto *PtrArith = Result.Nodes.getNodeAs<BinaryOperator>("PtrArith");
  49. const Expr *AllocExpr = PtrArith->getLHS()->IgnoreParenCasts();
  50. std::string CallName;
  51. if (const auto *Call = dyn_cast<CallExpr>(AllocExpr)) {
  52. const NamedDecl *Func = Call->getDirectCallee();
  53. if (!Func) {
  54. Func = cast<NamedDecl>(Call->getCalleeDecl());
  55. }
  56. CallName = Func->getName().str();
  57. } else {
  58. const auto *New = cast<CXXNewExpr>(AllocExpr);
  59. if (New->isArray()) {
  60. CallName = "operator new[]";
  61. } else {
  62. const auto *CtrE = New->getConstructExpr();
  63. if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
  64. ->getType()
  65. ->isIntegralOrEnumerationType())
  66. return;
  67. CallName = "operator new";
  68. }
  69. }
  70. const SourceRange OldRParen = SourceRange(PtrArith->getLHS()->getEndLoc());
  71. const StringRef RParen =
  72. Lexer::getSourceText(CharSourceRange::getTokenRange(OldRParen),
  73. *Result.SourceManager, getLangOpts());
  74. const SourceLocation NewRParen = Lexer::getLocForEndOfToken(
  75. PtrArith->getEndLoc(), 0, *Result.SourceManager, getLangOpts());
  76. diag(PtrArith->getBeginLoc(),
  77. "arithmetic operation is applied to the result of %0() instead of its "
  78. "size-like argument")
  79. << CallName << FixItHint::CreateRemoval(OldRParen)
  80. << FixItHint::CreateInsertion(NewRParen, RParen);
  81. }
  82. } // namespace clang::tidy::bugprone