| //===--- MisplacedOperatorInStrlenInAllocCheck.cpp - clang-tidy------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MisplacedOperatorInStrlenInAllocCheck.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/ASTMatchers/ASTMatchFinder.h" |
| |
| using namespace clang::ast_matchers; |
| |
| namespace clang { |
| namespace tidy { |
| namespace bugprone { |
| |
| void MisplacedOperatorInStrlenInAllocCheck::registerMatchers( |
| MatchFinder *Finder) { |
| const auto StrLenFunc = functionDecl(anyOf( |
| hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"), |
| hasName("::std::strnlen"), hasName("::strnlen_s"), |
| hasName("::std::strnlen_s"), hasName("::wcslen"), |
| hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"), |
| hasName("::wcsnlen_s"), hasName("std::wcsnlen_s"))); |
| |
| const auto BadUse = |
| callExpr(callee(StrLenFunc), |
| hasAnyArgument(ignoringImpCasts( |
| binaryOperator(allOf(hasOperatorName("+"), |
| hasRHS(ignoringParenImpCasts( |
| integerLiteral(equals(1)))))) |
| .bind("BinOp")))) |
| .bind("StrLen"); |
| |
| const auto BadArg = anyOf( |
| allOf(hasDescendant(BadUse), |
| unless(binaryOperator(allOf( |
| hasOperatorName("+"), hasLHS(BadUse), |
| hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))))), |
| BadUse); |
| |
| const auto Alloc0Func = |
| functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"), |
| hasName("::alloca"), hasName("std::alloca"))); |
| const auto Alloc1Func = |
| functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"), |
| hasName("::realloc"), hasName("std::realloc"))); |
| |
| const auto Alloc0FuncPtr = |
| varDecl(hasType(isConstQualified()), |
| hasInitializer(ignoringParenImpCasts( |
| declRefExpr(hasDeclaration(Alloc0Func))))); |
| const auto Alloc1FuncPtr = |
| varDecl(hasType(isConstQualified()), |
| hasInitializer(ignoringParenImpCasts( |
| declRefExpr(hasDeclaration(Alloc1Func))))); |
| |
| Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))), |
| hasArgument(0, BadArg)) |
| .bind("Alloc"), |
| this); |
| Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))), |
| hasArgument(1, BadArg)) |
| .bind("Alloc"), |
| this); |
| Finder->addMatcher( |
| cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this); |
| } |
| |
| void MisplacedOperatorInStrlenInAllocCheck::check( |
| const MatchFinder::MatchResult &Result) { |
| const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc"); |
| if (!Alloc) |
| Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc"); |
| assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'" |
| " or 'CXXNewExpr'"); |
| |
| const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen"); |
| const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp"); |
| |
| const StringRef StrLenText = Lexer::getSourceText( |
| CharSourceRange::getTokenRange(StrLen->getSourceRange()), |
| *Result.SourceManager, getLangOpts()); |
| const StringRef Arg0Text = Lexer::getSourceText( |
| CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()), |
| *Result.SourceManager, getLangOpts()); |
| const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text)); |
| const StringRef StrLenEnd = StrLenText.substr( |
| StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size()); |
| |
| const StringRef LHSText = Lexer::getSourceText( |
| CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()), |
| *Result.SourceManager, getLangOpts()); |
| const StringRef RHSText = Lexer::getSourceText( |
| CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()), |
| *Result.SourceManager, getLangOpts()); |
| |
| auto Hint = FixItHint::CreateReplacement( |
| StrLen->getSourceRange(), |
| (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str()); |
| |
| diag(Alloc->getLocStart(), |
| "addition operator is applied to the argument of %0 instead of its " |
| "result") << StrLen->getDirectCallee()->getName() << Hint; |
| } |
| |
| } // namespace bugprone |
| } // namespace tidy |
| } // namespace clang |