| 194 | } |
| 195 | |
| 196 | void ControlFlowAnalyzer::checkUnreachable(CFGNode const* _entry, CFGNode const* _exit, CFGNode const* _revert, CFGNode const* _transactionReturn) |
| 197 | { |
| 198 | // collect all nodes reachable from the entry point |
| 199 | std::set<CFGNode const*> reachable = util::BreadthFirstSearch<CFGNode const*>{{_entry}}.run( |
| 200 | [](CFGNode const* _node, auto&& _addChild) { |
| 201 | for (CFGNode const* exit: _node->exits) |
| 202 | _addChild(exit); |
| 203 | } |
| 204 | ).visited; |
| 205 | |
| 206 | // traverse all paths backwards from exit, revert and transaction return |
| 207 | // and extract (valid) source locations of unreachable nodes into sorted set |
| 208 | std::set<SourceLocation> unreachable; |
| 209 | util::BreadthFirstSearch<CFGNode const*>{{_exit, _revert, _transactionReturn}}.run( |
| 210 | [&](CFGNode const* _node, auto&& _addChild) { |
| 211 | if (!reachable.count(_node) && _node->location.isValid()) |
| 212 | unreachable.insert(_node->location); |
| 213 | for (CFGNode const* entry: _node->entries) |
| 214 | _addChild(entry); |
| 215 | } |
| 216 | ); |
| 217 | |
| 218 | for (auto it = unreachable.begin(); it != unreachable.end();) |
| 219 | { |
| 220 | SourceLocation location = *it++; |
| 221 | // Extend the location, as long as the next location overlaps (unreachable is sorted). |
| 222 | for (; it != unreachable.end() && it->start <= location.end; ++it) |
| 223 | location.end = std::max(location.end, it->end); |
| 224 | |
| 225 | if (m_unreachableLocationsAlreadyWarnedFor.emplace(location).second) |
| 226 | m_errorReporter.warning(5740_error, location, "Unreachable code."); |
| 227 | } |
| 228 | } |