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) S(S)29 : S(S), Cfg(std::move(Cfg)), AST(std::move(AST)), Func(Func) {} 30 getStatus()31 Status getStatus() const { return S; } getCFG()32 CFG *getCFG() const { return Cfg.get(); } getAST()33 ASTUnit *getAST() const { return AST.get(); } getFunc()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: CFGCallback(std::unique_ptr<ASTUnit> AST)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 run(const ast_matchers::MatchFinder::MatchResult & Result)51 void run(const ast_matchers::MatchFinder::MatchResult &Result) override { 52 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("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(nullptr, Body, Result.Context, Options)) 60 TheBuildResult = {BuildResult::BuiltCFG, Func, std::move(Cfg), 61 std::move(AST)}; 62 } 63 }; 64 65 inline BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}) { 66 std::vector<std::string> Args = {"-std=c++11", 67 "-fno-delayed-template-parsing"}; 68 std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs(Code, Args); 69 if (!AST) 70 return BuildResult::ToolFailed; 71 72 CFGCallback Callback(std::move(AST)); 73 Callback.Options = Options; 74 ast_matchers::MatchFinder Finder; 75 Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback); 76 77 Finder.matchAST(Callback.AST->getASTContext()); 78 return std::move(Callback.TheBuildResult); 79 } 80 81 } // namespace analysis 82 } // namespace clang 83