diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -5919,7 +5919,7 @@ return nullptr; const Stmt *Cond = StmtElem->getStmt(); - if (isa(Cond)) + if (isa(Cond) || isa(Cond)) return nullptr; // Only ObjCForCollectionStmt is known not to be a non-Expr terminator, hence diff --git a/clang/unittests/Analysis/CFGBuildResult.h b/clang/unittests/Analysis/CFGBuildResult.h --- a/clang/unittests/Analysis/CFGBuildResult.h +++ b/clang/unittests/Analysis/CFGBuildResult.h @@ -6,9 +6,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/CFG.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Analysis/CFG.h" #include "clang/Tooling/Tooling.h" +#include namespace clang { namespace analysis { @@ -22,20 +23,27 @@ BuiltCFG, }; - BuildResult(Status S, std::unique_ptr Cfg = nullptr) - : S(S), Cfg(std::move(Cfg)) {} + BuildResult(Status S, std::unique_ptr Cfg = nullptr, + std::unique_ptr AST = nullptr) + : S(S), Cfg(std::move(Cfg)), AST(std::move(AST)) {} Status getStatus() const { return S; } CFG *getCFG() const { return Cfg.get(); } + ASTUnit *getAST() const { return AST.get(); } private: Status S; std::unique_ptr Cfg; + std::unique_ptr AST; }; class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { public: + CFGCallback(std::unique_ptr AST) : AST(std::move(AST)) {} + + std::unique_ptr AST; BuildResult TheBuildResult = BuildResult::ToolRan; + CFG::BuildOptions Options; void run(const ast_matchers::MatchFinder::MatchResult &Result) override { const auto *Func = Result.Nodes.getNodeAs("func"); @@ -43,25 +51,26 @@ if (!Body) return; TheBuildResult = BuildResult::SawFunctionBody; - CFG::BuildOptions Options; Options.AddImplicitDtors = true; if (std::unique_ptr Cfg = CFG::buildCFG(nullptr, Body, Result.Context, Options)) - TheBuildResult = {BuildResult::BuiltCFG, std::move(Cfg)}; + TheBuildResult = {BuildResult::BuiltCFG, std::move(Cfg), std::move(AST)}; } }; -inline BuildResult BuildCFG(const char *Code) { - CFGCallback Callback; - - ast_matchers::MatchFinder Finder; - Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback); - std::unique_ptr Factory( - tooling::newFrontendActionFactory(&Finder)); +inline BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}) { std::vector Args = {"-std=c++11", "-fno-delayed-template-parsing"}; - if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args)) + std::unique_ptr AST = tooling::buildASTFromCodeWithArgs(Code, Args); + if (!AST) return BuildResult::ToolFailed; + + CFGCallback Callback(std::move(AST)); + Callback.Options = Options; + ast_matchers::MatchFinder Finder; + Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback); + + Finder.matchAST(Callback.AST->getASTContext()); return std::move(Callback.TheBuildResult); } diff --git a/clang/unittests/Analysis/CFGTest.cpp b/clang/unittests/Analysis/CFGTest.cpp --- a/clang/unittests/Analysis/CFGTest.cpp +++ b/clang/unittests/Analysis/CFGTest.cpp @@ -30,6 +30,22 @@ EXPECT_EQ(BuildResult::SawFunctionBody, BuildCFG(Code).getStatus()); } +TEST(CFG, StaticInitializerLastCondition) { + const char *Code = "void f() {\n" + " int i = 5 ;\n" + " static int j = 3 ;\n" + "}\n"; + CFG::BuildOptions Options; + Options.AddStaticInitBranches = true; + Options.setAllAlwaysAdd(); + BuildResult B = BuildCFG(Code, Options); + EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus()); + EXPECT_EQ(1u, B.getCFG()->getEntry().succ_size()); + CFGBlock *Block = *B.getCFG()->getEntry().succ_begin(); + EXPECT_TRUE(isa(Block->getTerminatorStmt())); + EXPECT_EQ(nullptr, Block->getLastCondition()); +} + // Constructing a CFG containing a delete expression on a dependent type should // not crash. TEST(CFG, DeleteExpressionOnDependentType) {