Replaced SourceLocation::isEmpty() with isValid() and hasText().

The function SourceLocation::isEmpty() had somewhat dual role.
Sometimes it indicates that the SourceLocation is invalid.
Sometimes it means that there is no corresponding source text.

Hence the proposal is to replace it with two functions, isValid() and hasText().

I also removed Scanner::sourceAt(). (Do we have a rule of thumb to remove unused code?)

Since hasText() checks that start and end are valid indices for source, I adjusted a couple of tests to avoid empty source strings.
This commit is contained in:
alex 2020-02-03 08:04:21 +01:00 committed by alex
parent b6190e06a5
commit e4b18e85e6
11 changed files with 31 additions and 29 deletions

View File

@ -43,7 +43,7 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i)
assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow."); assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
m_deposit += _i.deposit(); m_deposit += _i.deposit();
m_items.emplace_back(_i); m_items.emplace_back(_i);
if (m_items.back().location().isEmpty() && !m_currentSourceLocation.isEmpty()) if (!m_items.back().location().isValid() && m_currentSourceLocation.isValid())
m_items.back().setLocation(m_currentSourceLocation); m_items.back().setLocation(m_currentSourceLocation);
m_items.back().m_modifierDepth = m_currentModifierDepth; m_items.back().m_modifierDepth = m_currentModifierDepth;
return m_items.back(); return m_items.back();
@ -69,7 +69,7 @@ namespace
string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location)
{ {
if (_location.isEmpty() || !_location.source.get() || _sourceCodes.empty() || _location.start >= _location.end || _location.start < 0) if (!_location.hasText() || _sourceCodes.empty())
return ""; return "";
auto it = _sourceCodes.find(_location.source->name()); auto it = _sourceCodes.find(_location.source->name());
@ -97,7 +97,7 @@ public:
void feed(AssemblyItem const& _item) void feed(AssemblyItem const& _item)
{ {
if (!_item.location().isEmpty() && _item.location() != m_location) if (_item.location().isValid() && _item.location() != m_location)
{ {
flush(); flush();
m_location = _item.location(); m_location = _item.location();
@ -141,12 +141,12 @@ public:
void printLocation() void printLocation()
{ {
if (!m_location.source && m_location.isEmpty()) if (!m_location.isValid())
return; return;
m_out << m_prefix << " /*"; m_out << m_prefix << " /*";
if (m_location.source) if (m_location.source)
m_out << " \"" + m_location.source->name() + "\""; m_out << " \"" + m_location.source->name() + "\"";
if (!m_location.isEmpty()) if (m_location.hasText())
m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end); m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end);
m_out << " " << locationFromSources(m_sourceCodes, m_location); m_out << " " << locationFromSources(m_sourceCodes, m_location);
m_out << " */" << endl; m_out << " */" << endl;

View File

@ -51,7 +51,7 @@ Error::Error(Type _type, SourceLocation const& _location, string const& _descrip
break; break;
} }
if (!_location.isEmpty()) if (_location.isValid())
*this << errinfo_sourceLocation(_location); *this << errinfo_sourceLocation(_location);
if (!_description.empty()) if (!_description.empty())
*this << util::errinfo_comment(_description); *this << util::errinfo_comment(_description);
@ -60,7 +60,7 @@ Error::Error(Type _type, SourceLocation const& _location, string const& _descrip
Error::Error(Error::Type _type, std::string const& _description, SourceLocation const& _location): Error::Error(Error::Type _type, std::string const& _description, SourceLocation const& _location):
Error(_type) Error(_type)
{ {
if (!_location.isEmpty()) if (_location.isValid())
*this << errinfo_sourceLocation(_location); *this << errinfo_sourceLocation(_location);
*this << util::errinfo_comment(_description); *this << util::errinfo_comment(_description);
} }

View File

@ -167,12 +167,6 @@ public:
/// Do only use in error cases, they are quite expensive. /// Do only use in error cases, they are quite expensive.
std::string lineAtPosition(int _position) const { return m_source->lineAtPosition(_position); } std::string lineAtPosition(int _position) const { return m_source->lineAtPosition(_position); }
std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source->translatePositionToLineColumn(_position); } std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source->translatePositionToLineColumn(_position); }
std::string sourceAt(SourceLocation const& _location) const
{
solAssert(!_location.isEmpty(), "");
solAssert(m_source.get() == _location.source.get(), "CharStream memory locations must match.");
return m_source->source().substr(_location.start, _location.end - _location.start);
}
///@} ///@}
private: private:

View File

@ -56,24 +56,32 @@ struct SourceLocation
inline bool contains(SourceLocation const& _other) const inline bool contains(SourceLocation const& _other) const
{ {
if (isEmpty() || _other.isEmpty() || source.get() != _other.source.get()) if (!hasText() || !_other.hasText() || source.get() != _other.source.get())
return false; return false;
return start <= _other.start && _other.end <= end; return start <= _other.start && _other.end <= end;
} }
inline bool intersects(SourceLocation const& _other) const inline bool intersects(SourceLocation const& _other) const
{ {
if (isEmpty() || _other.isEmpty() || source.get() != _other.source.get()) if (!hasText() || !_other.hasText() || source.get() != _other.source.get())
return false; return false;
return _other.start < end && start < _other.end; return _other.start < end && start < _other.end;
} }
bool isEmpty() const { return start == -1 && end == -1; } bool isValid() const { return source || start != -1 || end != -1; }
bool hasText() const
{
return source
&& 0 <= start
&& start <= end
&& end <= int(source->source().length());
}
std::string text() const std::string text() const
{ {
assertThrow(source, SourceLocationError, "Requested text from null source."); assertThrow(source, SourceLocationError, "Requested text from null source.");
assertThrow(!isEmpty(), SourceLocationError, "Requested text from empty source location."); assertThrow(0 <= start, SourceLocationError, "Invalid source location.");
assertThrow(start <= end, SourceLocationError, "Invalid source location."); assertThrow(start <= end, SourceLocationError, "Invalid source location.");
assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location."); assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location.");
return source->source().substr(start, end - start); return source->source().substr(start, end - start);
@ -109,13 +117,13 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string
/// Stream output for Location (used e.g. in boost exceptions). /// Stream output for Location (used e.g. in boost exceptions).
inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location) inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location)
{ {
if (_location.isEmpty()) if (!_location.isValid())
return _out << "NO_LOCATION_SPECIFIED"; return _out << "NO_LOCATION_SPECIFIED";
if (_location.source) if (_location.source)
_out << _location.source->name(); _out << _location.source->name();
_out << "[" << _location.start << "," << _location.end << ")"; _out << "[" << _location.start << "," << _location.end << "]";
return _out; return _out;
} }

View File

@ -163,7 +163,7 @@ void ControlFlowAnalyzer::checkUnreachable(CFGNode const* _entry, CFGNode const*
std::set<SourceLocation> unreachable; std::set<SourceLocation> unreachable;
util::BreadthFirstSearch<CFGNode const*>{{_exit, _revert}}.run( util::BreadthFirstSearch<CFGNode const*>{{_exit, _revert}}.run(
[&](CFGNode const* _node, auto&& _addChild) { [&](CFGNode const* _node, auto&& _addChild) {
if (!reachable.count(_node) && !_node->location.isEmpty()) if (!reachable.count(_node) && _node->location.isValid())
unreachable.insert(_node->location); unreachable.insert(_node->location);
for (CFGNode const* entry: _node->entries) for (CFGNode const* entry: _node->entries)
_addChild(entry); _addChild(entry);

View File

@ -2762,7 +2762,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
SecondarySourceLocation ssl; SecondarySourceLocation ssl;
for (Declaration const* declaration: annotation.overloadedDeclarations) for (Declaration const* declaration: annotation.overloadedDeclarations)
if (declaration->location().isEmpty()) if (!declaration->location().isValid())
{ {
// Try to re-construct function definition // Try to re-construct function definition
string description; string description;

View File

@ -54,7 +54,7 @@ T AsmJsonImporter::createAsmNode(Json::Value const& _node)
{ {
T r; T r;
r.location = createSourceLocation(_node); r.location = createSourceLocation(_node);
astAssert(!r.location.isEmpty() || !r.location.source, "Invalid source location in Asm AST"); astAssert(!r.location.isValid() || r.location.hasText(), "Invalid source location in Asm AST");
return r; return r;
} }

View File

@ -65,7 +65,7 @@ protected:
{ {
T r; T r;
r.location = _loc; r.location = _loc;
if (r.location.isEmpty()) if (!r.location.hasText())
{ {
r.location.start = position(); r.location.start = position();
r.location.end = endPosition(); r.location.end = endPosition();

View File

@ -51,11 +51,11 @@ BOOST_AUTO_TEST_SUITE(Assembler)
BOOST_AUTO_TEST_CASE(all_assembly_items) BOOST_AUTO_TEST_CASE(all_assembly_items)
{ {
Assembly _assembly; Assembly _assembly;
auto root_asm = make_shared<CharStream>("", "root.asm"); auto root_asm = make_shared<CharStream>("lorem ipsum", "root.asm");
_assembly.setSourceLocation({1, 3, root_asm}); _assembly.setSourceLocation({1, 3, root_asm});
Assembly _subAsm; Assembly _subAsm;
auto sub_asm = make_shared<CharStream>("", "sub.asm"); auto sub_asm = make_shared<CharStream>("lorem ipsum", "sub.asm");
_subAsm.setSourceLocation({6, 8, sub_asm}); _subAsm.setSourceLocation({6, 8, sub_asm});
_subAsm.append(Instruction::INVALID); _subAsm.append(Instruction::INVALID);
shared_ptr<Assembly> _subAsmPtr = make_shared<Assembly>(_subAsm); shared_ptr<Assembly> _subAsmPtr = make_shared<Assembly>(_subAsm);

View File

@ -72,7 +72,7 @@ namespace
for (AssemblyItem const& item: output) for (AssemblyItem const& item: output)
{ {
BOOST_CHECK(item == Instruction::POP || !item.location().isEmpty()); BOOST_CHECK(item == Instruction::POP || item.location().isValid());
} }
return output; return output;
} }

View File

@ -33,9 +33,9 @@ BOOST_AUTO_TEST_SUITE(SourceLocationTest)
BOOST_AUTO_TEST_CASE(test_fail) BOOST_AUTO_TEST_CASE(test_fail)
{ {
auto const source = std::make_shared<CharStream>("", "source"); auto const source = std::make_shared<CharStream>("lorem ipsum", "source");
auto const sourceA = std::make_shared<CharStream>("", "sourceA"); auto const sourceA = std::make_shared<CharStream>("lorem ipsum", "sourceA");
auto const sourceB = std::make_shared<CharStream>("", "sourceB"); auto const sourceB = std::make_shared<CharStream>("lorem ipsum", "sourceB");
BOOST_CHECK(SourceLocation{} == SourceLocation{}); BOOST_CHECK(SourceLocation{} == SourceLocation{});
BOOST_CHECK((SourceLocation{0, 3, sourceA} != SourceLocation{0, 3, sourceB})); BOOST_CHECK((SourceLocation{0, 3, sourceA} != SourceLocation{0, 3, sourceB}));