Better branch detection model
For loops are now broken up into 2 branches: 1 (init) and 2 (cond + inc).
This commit is contained in:
parent
a23e5c66ab
commit
83ca2deb0e
@ -115,26 +115,19 @@ void OperationFinder::processArraySubscript(const clang::ArraySubscriptExpr* sub
|
|||||||
llvm::outs() << "\n";
|
llvm::outs() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationFinder::fallthroughBranchEntered()
|
void OperationFinder::branchEntered()
|
||||||
{
|
{
|
||||||
_in_fallthrough = true;
|
_current_branch++;
|
||||||
|
llvm::outs() << "Branch entered: " << _current_branch << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationFinder::fallthroughBranchExited()
|
void OperationFinder::branchExited()
|
||||||
{
|
{
|
||||||
_in_fallthrough = false;
|
llvm::outs() << "Branch exited: " << _current_branch << "\n";
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::forLoopEntered()
|
_current_branch--;
|
||||||
{
|
|
||||||
_for_loop_stack.push_back(_next_for_loop_id);
|
|
||||||
|
|
||||||
_next_for_loop_id++;
|
assert(_current_branch > -1);
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::forLoopExited()
|
|
||||||
{
|
|
||||||
_for_loop_stack.pop_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<OperationLog::BasicOperation>
|
std::unique_ptr<OperationLog::BasicOperation>
|
||||||
@ -167,8 +160,7 @@ std::pair<std::string, OperationLog> OperationFinder::_createBaseOperationLog(co
|
|||||||
|
|
||||||
OperationLog log;
|
OperationLog log;
|
||||||
log.line = line_number;
|
log.line = line_number;
|
||||||
log.current_for_loops = _for_loop_stack;
|
log.branch_number = _current_branch;
|
||||||
log.is_fallthrough = _in_fallthrough;
|
|
||||||
|
|
||||||
llvm::outs() << file_name << ":"
|
llvm::outs() << file_name << ":"
|
||||||
<< line_number << ":"
|
<< line_number << ":"
|
||||||
|
|||||||
@ -19,11 +19,8 @@ public:
|
|||||||
void processFunctionCall(const clang::CallExpr* call, const clang::SourceManager& source_manager);
|
void processFunctionCall(const clang::CallExpr* call, const clang::SourceManager& source_manager);
|
||||||
void processArraySubscript(const clang::ArraySubscriptExpr* subscript, const clang::SourceManager& source_manager);
|
void processArraySubscript(const clang::ArraySubscriptExpr* subscript, const clang::SourceManager& source_manager);
|
||||||
|
|
||||||
void fallthroughBranchEntered();
|
void branchEntered();
|
||||||
void fallthroughBranchExited();
|
void branchExited();
|
||||||
|
|
||||||
void forLoopEntered();
|
|
||||||
void forLoopExited();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<OperationLog::BasicOperation>
|
std::unique_ptr<OperationLog::BasicOperation>
|
||||||
@ -31,9 +28,7 @@ private:
|
|||||||
|
|
||||||
std::pair<std::string, OperationLog> _createBaseOperationLog(const clang::Stmt* stmt, const clang::SourceManager& source_manager);
|
std::pair<std::string, OperationLog> _createBaseOperationLog(const clang::Stmt* stmt, const clang::SourceManager& source_manager);
|
||||||
|
|
||||||
int _next_for_loop_id = 0;
|
int _current_branch = 0;
|
||||||
bool _in_fallthrough = false;
|
|
||||||
std::vector<int> _for_loop_stack;
|
|
||||||
IOperationOutput* _storage;
|
IOperationOutput* _storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -65,17 +65,10 @@ bool OperationFinderAstVisitor::dataTraverseStmtPre(clang::Stmt* stmt)
|
|||||||
{
|
{
|
||||||
assert(_context);
|
assert(_context);
|
||||||
|
|
||||||
if (auto* loop = clang::dyn_cast<clang::ForStmt>(stmt))
|
if (clang::Stmt* branch_entry = _isBranchEntry(stmt))
|
||||||
{
|
{
|
||||||
if (loop->getInit())
|
_branch_stack.push_back(branch_entry);
|
||||||
{
|
_op_finder->branchEntered();
|
||||||
_loop_init = loop->getInit();
|
|
||||||
_op_finder->fallthroughBranchEntered();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_op_finder->forLoopEntered();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -85,16 +78,77 @@ bool OperationFinderAstVisitor::dataTraverseStmtPost(clang::Stmt* stmt)
|
|||||||
{
|
{
|
||||||
assert(_context);
|
assert(_context);
|
||||||
|
|
||||||
if (_loop_init && _loop_init == stmt)
|
if (_loop_header.in_loop_header && (_loop_header.init == stmt || _loop_header.header_end == stmt))
|
||||||
{
|
{
|
||||||
_op_finder->forLoopEntered();
|
if (_loop_header.header_end == stmt)
|
||||||
_op_finder->fallthroughBranchExited();
|
{
|
||||||
_loop_init = nullptr;
|
assert(_branch_stack.back() == stmt);
|
||||||
|
_branch_stack.pop_back();
|
||||||
|
_op_finder->branchExited();
|
||||||
|
|
||||||
|
if (_loop_header.init)
|
||||||
|
{
|
||||||
|
assert(_branch_stack.back() == _loop_header.init);
|
||||||
|
_branch_stack.pop_back();
|
||||||
|
_op_finder->branchExited();
|
||||||
|
}
|
||||||
|
|
||||||
|
_loop_header = {};
|
||||||
|
}
|
||||||
|
else if (_loop_header.init == stmt && !_loop_header.header_end)
|
||||||
|
{
|
||||||
|
assert(_branch_stack.back() == stmt);
|
||||||
|
_branch_stack.pop_back();
|
||||||
|
_op_finder->branchExited();
|
||||||
|
|
||||||
|
_loop_header = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (clang::dyn_cast<clang::ForStmt>(stmt))
|
else if (!_branch_stack.empty() && _branch_stack.back() == stmt)
|
||||||
{
|
{
|
||||||
_op_finder->forLoopExited();
|
_branch_stack.pop_back();
|
||||||
|
_op_finder->branchExited();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(std::find(_branch_stack.cbegin(), _branch_stack.cend(), stmt)
|
||||||
|
== _branch_stack.cend());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clang::Stmt* OperationFinderAstVisitor::_isBranchEntry(clang::Stmt* stmt)
|
||||||
|
{
|
||||||
|
if (auto* loop = clang::dyn_cast<clang::ForStmt>(stmt))
|
||||||
|
{
|
||||||
|
_loop_header.init = loop->getInit();
|
||||||
|
|
||||||
|
if (loop->getCond())
|
||||||
|
{
|
||||||
|
_loop_header.header_start = loop->getCond();
|
||||||
|
_loop_header.header_end = loop->getCond();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop->getInc())
|
||||||
|
{
|
||||||
|
if (!_loop_header.header_start)
|
||||||
|
_loop_header.header_start = loop->getInc();
|
||||||
|
|
||||||
|
_loop_header.header_end = loop->getInc();
|
||||||
|
}
|
||||||
|
|
||||||
|
_loop_header.in_loop_header = _loop_header.init || _loop_header.header_end;
|
||||||
|
|
||||||
|
if (_loop_header.init)
|
||||||
|
return _loop_header.init;
|
||||||
|
else if (_loop_header.header_start)
|
||||||
|
return _loop_header.header_end;
|
||||||
|
}
|
||||||
|
else if (_loop_header.in_loop_header && _loop_header.header_start == stmt)
|
||||||
|
{
|
||||||
|
return _loop_header.header_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,19 @@ private:
|
|||||||
clang::ASTContext* _context;
|
clang::ASTContext* _context;
|
||||||
OperationFinder* _op_finder;
|
OperationFinder* _op_finder;
|
||||||
|
|
||||||
clang::Stmt* _loop_init = nullptr;
|
struct _LoopHeaderStateMachine
|
||||||
|
{
|
||||||
|
bool in_loop_header = false;
|
||||||
|
clang::Stmt* init = nullptr;
|
||||||
|
clang::Stmt* header_start = nullptr;
|
||||||
|
clang::Stmt* header_end = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
_LoopHeaderStateMachine _loop_header;
|
||||||
|
|
||||||
|
std::vector<clang::Stmt*> _branch_stack;
|
||||||
|
|
||||||
|
clang::Stmt* _isBranchEntry(clang::Stmt* stmt);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
#endif //C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
||||||
|
|||||||
@ -39,13 +39,12 @@ struct OperationLog
|
|||||||
[[nodiscard]] nlohmann::json toJson() const override;
|
[[nodiscard]] nlohmann::json toJson() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int line;
|
unsigned int line = 0;
|
||||||
|
int branch_number = 0;
|
||||||
|
|
||||||
std::string entry_type;
|
std::string entry_type;
|
||||||
std::unique_ptr<IEntry> entry;
|
std::unique_ptr<IEntry> entry;
|
||||||
|
|
||||||
bool is_fallthrough;
|
|
||||||
std::vector<int> current_for_loops;
|
|
||||||
|
|
||||||
OperationLog() = default;
|
OperationLog() = default;
|
||||||
OperationLog(const OperationLog&) = delete;
|
OperationLog(const OperationLog&) = delete;
|
||||||
OperationLog(OperationLog&&) = default;
|
OperationLog(OperationLog&&) = default;
|
||||||
@ -67,8 +66,7 @@ inline void to_json(nlohmann::json& j, const OperationLog& l)
|
|||||||
{"line", l.line},
|
{"line", l.line},
|
||||||
{"entry_type", l.entry_type},
|
{"entry_type", l.entry_type},
|
||||||
{"entry", l.entry->toJson()},
|
{"entry", l.entry->toJson()},
|
||||||
{"is_fallthrough", l.is_fallthrough},
|
{"branch_number", l.branch_number}
|
||||||
{"current_for_loops", l.current_for_loops}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,17 +76,16 @@ inline void from_json(const nlohmann::json& j, OperationLog& l)
|
|||||||
j.at("entry_type").get_to(l.entry_type);
|
j.at("entry_type").get_to(l.entry_type);
|
||||||
l.DecodeEntry(j["entry"]);
|
l.DecodeEntry(j["entry"]);
|
||||||
|
|
||||||
j.at("is_fallthrough").get_to(l.is_fallthrough);
|
j.at("branch_number").get_to(l.branch_number);
|
||||||
j.at("current_for_loops").get_to(l.current_for_loops);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void to_json(nlohmann::json& j, const OperationLog::BasicOperation& bo)
|
inline void to_json(nlohmann::json& j, const OperationLog::BasicOperation& bo)
|
||||||
{
|
{
|
||||||
j = nlohmann::json{
|
j = nlohmann::json{
|
||||||
{"operation_name", bo.operation_name},
|
{"operation_name", bo.operation_name},
|
||||||
{"type_lhs", bo.type_lhs},
|
{"type_lhs", bo.type_lhs},
|
||||||
{"type_rhs", bo.type_rhs},
|
{"type_rhs", bo.type_rhs},
|
||||||
{"type_result", bo.type_result}
|
{"type_result", bo.type_result}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user