1 //===--- NoMallocCheck.cpp - clang-tidy------------------------------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NoMallocCheck.h" 10 #include "../utils/Matchers.h" 11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include <algorithm> 15 #include <string> 16 #include <vector> 17 18 using namespace clang::ast_matchers; 19 using namespace clang::ast_matchers::internal; 20 21 namespace clang { 22 namespace tidy { 23 namespace cppcoreguidelines { 24 25 namespace { 26 Matcher<FunctionDecl> hasAnyListedName(const std::string &FunctionNames) { 27 const std::vector<std::string> NameList = 28 utils::options::parseStringList(FunctionNames); 29 return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end())); 30 } 31 } // namespace 32 33 void NoMallocCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 34 Options.store(Opts, "Allocations", AllocList); 35 Options.store(Opts, "Reallocations", ReallocList); 36 Options.store(Opts, "Deallocations", DeallocList); 37 } 38 39 void NoMallocCheck::registerMatchers(MatchFinder *Finder) { 40 // C-style memory management is only problematic in C++. 41 if (!getLangOpts().CPlusPlus) 42 return; 43 44 // Registering malloc, will suggest RAII. 45 Finder->addMatcher(callExpr(callee(functionDecl(hasAnyListedName(AllocList)))) 46 .bind("allocation"), 47 this); 48 49 // Registering realloc calls, suggest std::vector or std::string. 50 Finder->addMatcher( 51 callExpr(callee(functionDecl(hasAnyListedName(ReallocList)))) 52 .bind("realloc"), 53 this); 54 55 // Registering free calls, will suggest RAII instead. 56 Finder->addMatcher( 57 callExpr(callee(functionDecl(hasAnyListedName(DeallocList)))) 58 .bind("free"), 59 this); 60 } 61 62 void NoMallocCheck::check(const MatchFinder::MatchResult &Result) { 63 const CallExpr *Call = nullptr; 64 StringRef Recommendation; 65 66 if ((Call = Result.Nodes.getNodeAs<CallExpr>("allocation"))) 67 Recommendation = "consider a container or a smart pointer"; 68 else if ((Call = Result.Nodes.getNodeAs<CallExpr>("realloc"))) 69 Recommendation = "consider std::vector or std::string"; 70 else if ((Call = Result.Nodes.getNodeAs<CallExpr>("free"))) 71 Recommendation = "use RAII"; 72 73 assert(Call && "Unhandled binding in the Matcher"); 74 75 diag(Call->getBeginLoc(), "do not manage memory manually; %0") 76 << Recommendation << SourceRange(Call->getBeginLoc(), Call->getEndLoc()); 77 } 78 79 } // namespace cppcoreguidelines 80 } // namespace tidy 81 } // namespace clang 82