1 //===--- MisplacedOperatorInStrlenInAllocCheck.cpp - clang-tidy------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MisplacedOperatorInStrlenInAllocCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace bugprone { 19 20 void MisplacedOperatorInStrlenInAllocCheck::registerMatchers( 21 MatchFinder *Finder) { 22 const auto StrLenFunc = functionDecl(anyOf( 23 hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"), 24 hasName("::std::strnlen"), hasName("::strnlen_s"), 25 hasName("::std::strnlen_s"), hasName("::wcslen"), 26 hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"), 27 hasName("::wcsnlen_s"), hasName("std::wcsnlen_s"))); 28 29 const auto BadUse = 30 callExpr(callee(StrLenFunc), 31 hasAnyArgument(ignoringImpCasts( 32 binaryOperator(allOf(hasOperatorName("+"), 33 hasRHS(ignoringParenImpCasts( 34 integerLiteral(equals(1)))))) 35 .bind("BinOp")))) 36 .bind("StrLen"); 37 38 const auto BadArg = anyOf( 39 allOf(hasDescendant(BadUse), 40 unless(binaryOperator(allOf( 41 hasOperatorName("+"), hasLHS(BadUse), 42 hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))))), 43 BadUse); 44 45 const auto Alloc0Func = 46 functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"), 47 hasName("::alloca"), hasName("std::alloca"))); 48 const auto Alloc1Func = 49 functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"), 50 hasName("::realloc"), hasName("std::realloc"))); 51 52 const auto Alloc0FuncPtr = 53 varDecl(hasType(isConstQualified()), 54 hasInitializer(ignoringParenImpCasts( 55 declRefExpr(hasDeclaration(Alloc0Func))))); 56 const auto Alloc1FuncPtr = 57 varDecl(hasType(isConstQualified()), 58 hasInitializer(ignoringParenImpCasts( 59 declRefExpr(hasDeclaration(Alloc1Func))))); 60 61 Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))), 62 hasArgument(0, BadArg)) 63 .bind("Alloc"), 64 this); 65 Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))), 66 hasArgument(1, BadArg)) 67 .bind("Alloc"), 68 this); 69 Finder->addMatcher( 70 cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this); 71 } 72 73 void MisplacedOperatorInStrlenInAllocCheck::check( 74 const MatchFinder::MatchResult &Result) { 75 const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc"); 76 if (!Alloc) 77 Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc"); 78 assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'" 79 " or 'CXXNewExpr'"); 80 81 const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen"); 82 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp"); 83 84 const StringRef StrLenText = Lexer::getSourceText( 85 CharSourceRange::getTokenRange(StrLen->getSourceRange()), 86 *Result.SourceManager, getLangOpts()); 87 const StringRef Arg0Text = Lexer::getSourceText( 88 CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()), 89 *Result.SourceManager, getLangOpts()); 90 const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text)); 91 const StringRef StrLenEnd = StrLenText.substr( 92 StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size()); 93 94 const StringRef LHSText = Lexer::getSourceText( 95 CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()), 96 *Result.SourceManager, getLangOpts()); 97 const StringRef RHSText = Lexer::getSourceText( 98 CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()), 99 *Result.SourceManager, getLangOpts()); 100 101 auto Hint = FixItHint::CreateReplacement( 102 StrLen->getSourceRange(), 103 (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str()); 104 105 diag(Alloc->getLocStart(), 106 "addition operator is applied to the argument of %0 instead of its " 107 "result") << StrLen->getDirectCallee()->getName() << Hint; 108 } 109 110 } // namespace bugprone 111 } // namespace tidy 112 } // namespace clang 113