//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/CFG.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Tooling/Tooling.h"
+#include <memory>
namespace clang {
namespace analysis {
BuiltCFG,
};
- BuildResult(Status S, std::unique_ptr<CFG> Cfg = nullptr)
- : S(S), Cfg(std::move(Cfg)) {}
+ BuildResult(Status S, std::unique_ptr<CFG> Cfg = nullptr,
+ std::unique_ptr<ASTUnit> 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> Cfg;
+ std::unique_ptr<ASTUnit> AST;
};
class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
public:
+ CFGCallback(std::unique_ptr<ASTUnit> AST) : AST(std::move(AST)) {}
+
+ std::unique_ptr<ASTUnit> AST;
BuildResult TheBuildResult = BuildResult::ToolRan;
+ CFG::BuildOptions Options;
void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
if (!Body)
return;
TheBuildResult = BuildResult::SawFunctionBody;
- CFG::BuildOptions Options;
Options.AddImplicitDtors = true;
if (std::unique_ptr<CFG> 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<tooling::FrontendActionFactory> Factory(
- tooling::newFrontendActionFactory(&Finder));
+inline BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}) {
std::vector<std::string> Args = {"-std=c++11",
"-fno-delayed-template-parsing"};
- if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ std::unique_ptr<ASTUnit> 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);
}
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<DeclStmt>(Block->getTerminatorStmt()));
+ EXPECT_EQ(nullptr, Block->getLastCondition());
+}
+
// Constructing a CFG containing a delete expression on a dependent type should
// not crash.
TEST(CFG, DeleteExpressionOnDependentType) {