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