brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.3 KiB · 5925e28 Raw
110 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 "MisplacedOperatorInStrlenInAllocCheck.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 MisplacedOperatorInStrlenInAllocCheck::registerMatchers(19    MatchFinder *Finder) {20  const auto StrLenFunc = functionDecl(hasAnyName(21      "::strlen", "::std::strlen", "::strnlen", "::std::strnlen", "::strnlen_s",22      "::std::strnlen_s", "::wcslen", "::std::wcslen", "::wcsnlen",23      "::std::wcsnlen", "::wcsnlen_s", "std::wcsnlen_s"));24 25  const auto BadUse =26      callExpr(callee(StrLenFunc),27               hasAnyArgument(ignoringImpCasts(28                   binaryOperator(29                       hasOperatorName("+"),30                       hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))31                       .bind("BinOp"))))32          .bind("StrLen");33 34  const auto BadArg = anyOf(35      allOf(unless(binaryOperator(36                hasOperatorName("+"), hasLHS(BadUse),37                hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))),38            hasDescendant(BadUse)),39      BadUse);40 41  const auto Alloc0Func = functionDecl(42      hasAnyName("::malloc", "std::malloc", "::alloca", "std::alloca"));43  const auto Alloc1Func = functionDecl(44      hasAnyName("::calloc", "std::calloc", "::realloc", "std::realloc"));45 46  const auto Alloc0FuncPtr =47      varDecl(hasType(isConstQualified()),48              hasInitializer(ignoringParenImpCasts(49                  declRefExpr(hasDeclaration(Alloc0Func)))));50  const auto Alloc1FuncPtr =51      varDecl(hasType(isConstQualified()),52              hasInitializer(ignoringParenImpCasts(53                  declRefExpr(hasDeclaration(Alloc1Func)))));54 55  Finder->addMatcher(56      traverse(TK_AsIs, callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))),57                                 hasArgument(0, BadArg))58                            .bind("Alloc")),59      this);60  Finder->addMatcher(61      traverse(TK_AsIs, callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))),62                                 hasArgument(1, BadArg))63                            .bind("Alloc")),64      this);65  Finder->addMatcher(66      traverse(TK_AsIs,67               cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc")),68      this);69}70 71void MisplacedOperatorInStrlenInAllocCheck::check(72    const MatchFinder::MatchResult &Result) {73  const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc");74  if (!Alloc)75    Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc");76  assert(Alloc && "Matched node bound by 'Alloc' should be either 'CallExpr'"77                  " or 'CXXNewExpr'");78 79  const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen");80  const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp");81 82  const StringRef StrLenText = Lexer::getSourceText(83      CharSourceRange::getTokenRange(StrLen->getSourceRange()),84      *Result.SourceManager, getLangOpts());85  const StringRef Arg0Text = Lexer::getSourceText(86      CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()),87      *Result.SourceManager, getLangOpts());88  const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text));89  const StringRef StrLenEnd = StrLenText.substr(90      StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size());91 92  const StringRef LHSText = Lexer::getSourceText(93      CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()),94      *Result.SourceManager, getLangOpts());95  const StringRef RHSText = Lexer::getSourceText(96      CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()),97      *Result.SourceManager, getLangOpts());98 99  auto Hint = FixItHint::CreateReplacement(100      StrLen->getSourceRange(),101      (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str());102 103  diag(Alloc->getBeginLoc(),104       "addition operator is applied to the argument of %0 instead of its "105       "result")106      << StrLen->getDirectCallee()->getName() << Hint;107}108 109} // namespace clang::tidy::bugprone110