1 | //===- unittests/Analysis/CFGBuildResult.h - CFG tests --------------------===// |
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 "clang/ASTMatchers/ASTMatchFinder.h" |
10 | #include "clang/Analysis/CFG.h" |
11 | #include "clang/Tooling/Tooling.h" |
12 | #include <memory> |
13 | |
14 | namespace clang { |
15 | namespace analysis { |
16 | |
17 | class BuildResult { |
18 | public: |
19 | enum Status { |
20 | ToolFailed, |
21 | ToolRan, |
22 | SawFunctionBody, |
23 | BuiltCFG, |
24 | }; |
25 | |
26 | BuildResult(Status S, const FunctionDecl *Func = nullptr, |
27 | std::unique_ptr<CFG> Cfg = nullptr, |
28 | std::unique_ptr<ASTUnit> AST = nullptr) |
29 | : S(S), Cfg(std::move(Cfg)), AST(std::move(AST)), Func(Func) {} |
30 | |
31 | Status getStatus() const { return S; } |
32 | CFG *getCFG() const { return Cfg.get(); } |
33 | ASTUnit *getAST() const { return AST.get(); } |
34 | const FunctionDecl *getFunc() const { return Func; } |
35 | |
36 | private: |
37 | Status S; |
38 | std::unique_ptr<CFG> Cfg; |
39 | std::unique_ptr<ASTUnit> AST; |
40 | const FunctionDecl *Func; |
41 | }; |
42 | |
43 | class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { |
44 | public: |
45 | CFGCallback(std::unique_ptr<ASTUnit> AST) : AST(std::move(AST)) {} |
46 | |
47 | std::unique_ptr<ASTUnit> AST; |
48 | BuildResult TheBuildResult = BuildResult::ToolRan; |
49 | CFG::BuildOptions Options; |
50 | |
51 | void run(const ast_matchers::MatchFinder::MatchResult &Result) override { |
52 | const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(ID: "func" ); |
53 | Stmt *Body = Func->getBody(); |
54 | if (!Body) |
55 | return; |
56 | TheBuildResult = BuildResult::SawFunctionBody; |
57 | Options.AddImplicitDtors = true; |
58 | if (std::unique_ptr<CFG> Cfg = |
59 | CFG::buildCFG(Func, Body, Result.Context, Options)) |
60 | TheBuildResult = {BuildResult::BuiltCFG, Func, std::move(Cfg), |
61 | std::move(AST)}; |
62 | } |
63 | }; |
64 | |
65 | template <typename FuncMatcherT = ast_matchers::internal::TrueMatcher> |
66 | BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}, |
67 | FuncMatcherT FuncMatcher = ast_matchers::anything()) { |
68 | std::vector<std::string> Args = {"-std=c++11" , |
69 | "-fno-delayed-template-parsing" }; |
70 | std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs(Code, Args); |
71 | if (!AST) |
72 | return BuildResult::ToolFailed; |
73 | |
74 | CFGCallback Callback(std::move(AST)); |
75 | Callback.Options = Options; |
76 | ast_matchers::MatchFinder Finder; |
77 | Finder.addMatcher(ast_matchers::functionDecl(FuncMatcher).bind("func" ), |
78 | &Callback); |
79 | |
80 | Finder.matchAST(Context&: Callback.AST->getASTContext()); |
81 | return std::move(Callback.TheBuildResult); |
82 | } |
83 | |
84 | } // namespace analysis |
85 | } // namespace clang |
86 | |