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::tidy::cppcoreguidelines { |
22 | |
23 | void NoMallocCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { |
24 | Options.store(Options&: Opts, LocalName: "Allocations" , Value: AllocList); |
25 | Options.store(Options&: Opts, LocalName: "Reallocations" , Value: ReallocList); |
26 | Options.store(Options&: Opts, LocalName: "Deallocations" , Value: DeallocList); |
27 | } |
28 | |
29 | void NoMallocCheck::registerMatchers(MatchFinder *Finder) { |
30 | // Registering malloc, will suggest RAII. |
31 | Finder->addMatcher(NodeMatch: callExpr(callee(InnerMatcher: functionDecl(hasAnyName( |
32 | utils::options::parseStringList(Option: AllocList))))) |
33 | .bind(ID: "allocation" ), |
34 | Action: this); |
35 | |
36 | // Registering realloc calls, suggest std::vector or std::string. |
37 | Finder->addMatcher( |
38 | NodeMatch: callExpr(callee(InnerMatcher: functionDecl( |
39 | hasAnyName(utils::options::parseStringList(Option: (ReallocList)))))) |
40 | .bind(ID: "realloc" ), |
41 | Action: this); |
42 | |
43 | // Registering free calls, will suggest RAII instead. |
44 | Finder->addMatcher( |
45 | NodeMatch: callExpr(callee(InnerMatcher: functionDecl( |
46 | hasAnyName(utils::options::parseStringList(Option: (DeallocList)))))) |
47 | .bind(ID: "free" ), |
48 | Action: this); |
49 | } |
50 | |
51 | void NoMallocCheck::check(const MatchFinder::MatchResult &Result) { |
52 | const CallExpr *Call = nullptr; |
53 | StringRef Recommendation; |
54 | |
55 | if ((Call = Result.Nodes.getNodeAs<CallExpr>(ID: "allocation" ))) |
56 | Recommendation = "consider a container or a smart pointer" ; |
57 | else if ((Call = Result.Nodes.getNodeAs<CallExpr>(ID: "realloc" ))) |
58 | Recommendation = "consider std::vector or std::string" ; |
59 | else if ((Call = Result.Nodes.getNodeAs<CallExpr>(ID: "free" ))) |
60 | Recommendation = "use RAII" ; |
61 | |
62 | assert(Call && "Unhandled binding in the Matcher" ); |
63 | |
64 | diag(Loc: Call->getBeginLoc(), Description: "do not manage memory manually; %0" ) |
65 | << Recommendation << SourceRange(Call->getBeginLoc(), Call->getEndLoc()); |
66 | } |
67 | |
68 | } // namespace clang::tidy::cppcoreguidelines |
69 | |