1 //===--- MisplacedPointerArithmeticInAllocCheck.cpp - clang-tidy-----------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MisplacedPointerArithmeticInAllocCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
14 using namespace clang::ast_matchers
;
16 namespace clang::tidy::bugprone
{
18 void MisplacedPointerArithmeticInAllocCheck::registerMatchers(
19 MatchFinder
*Finder
) {
20 const auto AllocFunc
=
21 functionDecl(hasAnyName("::malloc", "std::malloc", "::alloca", "::calloc",
22 "std::calloc", "::realloc", "std::realloc"));
24 const auto AllocFuncPtr
=
25 varDecl(hasType(isConstQualified()),
26 hasInitializer(ignoringParenImpCasts(
27 declRefExpr(hasDeclaration(AllocFunc
)))));
29 const auto AdditiveOperator
= binaryOperator(hasAnyOperatorName("+", "-"));
31 const auto IntExpr
= expr(hasType(isInteger()));
33 const auto AllocCall
= callExpr(callee(decl(anyOf(AllocFunc
, AllocFuncPtr
))));
38 hasLHS(anyOf(AllocCall
, castExpr(hasSourceExpression(AllocCall
)))),
43 const auto New
= cxxNewExpr(unless(isArray()));
45 Finder
->addMatcher(binaryOperator(AdditiveOperator
,
46 hasLHS(anyOf(New
, castExpr(New
))),
51 const auto ArrayNew
= cxxNewExpr(isArray());
53 Finder
->addMatcher(binaryOperator(AdditiveOperator
,
54 hasLHS(anyOf(ArrayNew
, castExpr(ArrayNew
))),
60 void MisplacedPointerArithmeticInAllocCheck::check(
61 const MatchFinder::MatchResult
&Result
) {
62 const auto *PtrArith
= Result
.Nodes
.getNodeAs
<BinaryOperator
>("PtrArith");
63 const Expr
*AllocExpr
= PtrArith
->getLHS()->IgnoreParenCasts();
66 if (const auto *Call
= dyn_cast
<CallExpr
>(AllocExpr
)) {
67 const NamedDecl
*Func
= Call
->getDirectCallee();
69 Func
= cast
<NamedDecl
>(Call
->getCalleeDecl());
71 CallName
= Func
->getName().str();
73 const auto *New
= cast
<CXXNewExpr
>(AllocExpr
);
75 CallName
= "operator new[]";
77 const auto *CtrE
= New
->getConstructExpr();
78 if (!CtrE
|| !CtrE
->getArg(CtrE
->getNumArgs() - 1)
80 ->isIntegralOrEnumerationType())
82 CallName
= "operator new";
86 const SourceRange OldRParen
= SourceRange(PtrArith
->getLHS()->getEndLoc());
87 const StringRef RParen
=
88 Lexer::getSourceText(CharSourceRange::getTokenRange(OldRParen
),
89 *Result
.SourceManager
, getLangOpts());
90 const SourceLocation NewRParen
= Lexer::getLocForEndOfToken(
91 PtrArith
->getEndLoc(), 0, *Result
.SourceManager
, getLangOpts());
93 diag(PtrArith
->getBeginLoc(),
94 "arithmetic operation is applied to the result of %0() instead of its "
96 << CallName
<< FixItHint::CreateRemoval(OldRParen
)
97 << FixItHint::CreateInsertion(NewRParen
, RParen
);
100 } // namespace clang::tidy::bugprone