blob: 5a2b882466504b9318a57b8afa0051fbdaa62c5d [file] [log] [blame]
Alexander Kornienkoffbc2382018-01-25 15:09:33 +00001//===--- NoMallocCheck.cpp - clang-tidy------------------------------------===//
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +00002//
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 "NoMallocCheck.h"
Alexander Kornienkod993e762017-03-02 08:28:55 +000011#include "../utils/Matchers.h"
12#include "../utils/OptionsUtils.h"
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000013#include "clang/AST/ASTContext.h"
14#include "clang/ASTMatchers/ASTMatchFinder.h"
Alexander Kornienkod993e762017-03-02 08:28:55 +000015#include <algorithm>
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000016#include <string>
Alexander Kornienkod993e762017-03-02 08:28:55 +000017#include <vector>
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000018
19using namespace clang::ast_matchers;
Alexander Kornienkod993e762017-03-02 08:28:55 +000020using namespace clang::ast_matchers::internal;
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000021
22namespace clang {
23namespace tidy {
24namespace cppcoreguidelines {
25
Alexander Kornienkod993e762017-03-02 08:28:55 +000026namespace {
27Matcher<FunctionDecl> hasAnyListedName(const std::string &FunctionNames) {
28 const std::vector<std::string> NameList =
29 utils::options::parseStringList(FunctionNames);
30 return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
31}
Jonas Totha88abd52017-08-30 07:50:28 +000032} // namespace
Alexander Kornienkod993e762017-03-02 08:28:55 +000033
34void NoMallocCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
35 Options.store(Opts, "Allocations", AllocList);
36 Options.store(Opts, "Reallocations", ReallocList);
37 Options.store(Opts, "Deallocations", DeallocList);
38}
39
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000040void NoMallocCheck::registerMatchers(MatchFinder *Finder) {
41 // C-style memory management is only problematic in C++.
42 if (!getLangOpts().CPlusPlus)
43 return;
44
45 // Registering malloc, will suggest RAII.
Alexander Kornienkod993e762017-03-02 08:28:55 +000046 Finder->addMatcher(callExpr(callee(functionDecl(hasAnyListedName(AllocList))))
47 .bind("allocation"),
48 this);
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000049
50 // Registering realloc calls, suggest std::vector or std::string.
51 Finder->addMatcher(
Alexander Kornienkod993e762017-03-02 08:28:55 +000052 callExpr(callee(functionDecl(hasAnyListedName(ReallocList))))
53 .bind("realloc"),
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000054 this);
55
56 // Registering free calls, will suggest RAII instead.
57 Finder->addMatcher(
Alexander Kornienkod993e762017-03-02 08:28:55 +000058 callExpr(callee(functionDecl(hasAnyListedName(DeallocList))))
59 .bind("free"),
60 this);
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000061}
62
63void NoMallocCheck::check(const MatchFinder::MatchResult &Result) {
64 const CallExpr *Call = nullptr;
65 StringRef Recommendation;
66
Alexander Kornienkod993e762017-03-02 08:28:55 +000067 if ((Call = Result.Nodes.getNodeAs<CallExpr>("allocation")))
Alexander Kornienkoebdfb9c2016-12-13 16:38:18 +000068 Recommendation = "consider a container or a smart pointer";
69 else if ((Call = Result.Nodes.getNodeAs<CallExpr>("realloc")))
70 Recommendation = "consider std::vector or std::string";
71 else if ((Call = Result.Nodes.getNodeAs<CallExpr>("free")))
72 Recommendation = "use RAII";
73
74 assert(Call && "Unhandled binding in the Matcher");
75
76 diag(Call->getLocStart(), "do not manage memory manually; %0")
77 << Recommendation << SourceRange(Call->getLocStart(), Call->getLocEnd());
78}
79
80} // namespace cppcoreguidelines
81} // namespace tidy
82} // namespace clang