Remove CharStream from SourceLocation.

This commit is contained in:
chriseth
2021-07-14 15:12:07 +02:00
parent 57d32ca252
commit f75b55071e
73 changed files with 613 additions and 560 deletions
+1
View File
@@ -13,6 +13,7 @@ set(sources
ParserBase.h
Scanner.cpp
Scanner.h
CharStreamProvider.h
SemVerHandler.cpp
SemVerHandler.h
SourceLocation.h
+13 -3
View File
@@ -45,9 +45,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity scanner.
* Character stream / input file.
*/
#include <liblangutil/CharStream.h>
@@ -118,3 +116,15 @@ tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
}
return tuple<int, int>(lineNumber, searchPosition - lineStart);
}
string_view CharStream::text(SourceLocation const& _location) const
{
if (!_location.hasText())
return {};
solAssert(_location.sourceName && *_location.sourceName == m_name, "");
solAssert(static_cast<size_t>(_location.end) <= m_source.size(), "");
return string_view{m_source}.substr(
static_cast<size_t>(_location.start),
static_cast<size_t>(_location.end - _location.start)
);
}
+11 -5
View File
@@ -45,9 +45,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity scanner.
* Character stream / input file.
*/
#pragma once
@@ -60,6 +58,8 @@
namespace solidity::langutil
{
struct SourceLocation;
/**
* Bidirectional stream of characters.
*
@@ -69,8 +69,8 @@ class CharStream
{
public:
CharStream() = default;
explicit CharStream(std::string _source, std::string name):
m_source(std::move(_source)), m_name(std::move(name)) {}
CharStream(std::string _source, std::string _name):
m_source(std::move(_source)), m_name(std::move(_name)) {}
size_t position() const { return m_position; }
bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_position + _charsForward) >= m_source.size(); }
@@ -90,6 +90,8 @@ public:
std::string const& source() const noexcept { return m_source; }
std::string const& name() const noexcept { return m_name; }
size_t size() const { return m_source.size(); }
///@{
///@name Error printing helper functions
/// Functions that help pretty-printing parse errors
@@ -112,6 +114,10 @@ public:
return true;
}
/// @returns the substring of the source that the source location references.
/// Returns an empty string view if the source location does not `hasText()`.
std::string_view text(SourceLocation const& _location) const;
private:
std::string m_source;
std::string m_name;
+57
View File
@@ -0,0 +1,57 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Interface to retrieve the character stream by a source name.
*/
#pragma once
#include <liblangutil/CharStream.h>
#include <liblangutil/Exceptions.h>
#include <string>
namespace solidity::langutil
{
/**
* Interface to retrieve a CharStream (source) from a source name.
* Used especially for printing error information.
*/
class CharStreamProvider
{
public:
virtual ~CharStreamProvider() = default;
virtual CharStream const& charStream(std::string const& _sourceName) const = 0;
};
class SingletonCharStreamProvider: public CharStreamProvider
{
public:
explicit SingletonCharStreamProvider(CharStream const& _charStream):
m_charStream(_charStream) {}
CharStream const& charStream(std::string const& _sourceName) const override
{
solAssert(m_charStream.name() == _sourceName, "");
return m_charStream;
}
private:
CharStream const& m_charStream;
};
}
+5 -3
View File
@@ -138,6 +138,7 @@ private:
void Scanner::reset(CharStream _source)
{
m_source = make_shared<CharStream>(std::move(_source));
m_sourceName = make_shared<string>(m_source->name());
reset();
}
@@ -145,6 +146,7 @@ void Scanner::reset(shared_ptr<CharStream> _source)
{
solAssert(_source.get() != nullptr, "You MUST provide a CharStream when resetting.");
m_source = std::move(_source);
m_sourceName = make_shared<string>(m_source->name());
reset();
}
@@ -497,7 +499,7 @@ Token Scanner::scanSlash()
return skipSingleLineComment();
// doxygen style /// comment
m_skippedComments[NextNext].location.start = firstSlashPosition;
m_skippedComments[NextNext].location.source = m_source;
m_skippedComments[NextNext].location.sourceName = m_sourceName;
m_skippedComments[NextNext].token = Token::CommentLiteral;
m_skippedComments[NextNext].location.end = static_cast<int>(scanSingleLineDocComment());
return Token::Whitespace;
@@ -526,7 +528,7 @@ Token Scanner::scanSlash()
return skipMultiLineComment();
// we actually have a multiline documentation comment
m_skippedComments[NextNext].location.start = firstSlashPosition;
m_skippedComments[NextNext].location.source = m_source;
m_skippedComments[NextNext].location.sourceName = m_sourceName;
Token comment = scanMultiLineDocComment();
m_skippedComments[NextNext].location.end = static_cast<int>(sourcePos());
m_skippedComments[NextNext].token = comment;
@@ -766,7 +768,7 @@ void Scanner::scanToken()
}
while (token == Token::Whitespace);
m_tokens[NextNext].location.end = static_cast<int>(sourcePos());
m_tokens[NextNext].location.source = m_source;
m_tokens[NextNext].location.sourceName = m_sourceName;
m_tokens[NextNext].token = token;
m_tokens[NextNext].extendedTokenInfo = make_tuple(m, n);
}
+1 -8
View File
@@ -177,14 +177,6 @@ public:
Token peekNextNextToken() const { return m_tokens[NextNext].token; }
///@}
///@{
///@name Error printing helper functions
/// Functions that help pretty-printing parse errors
/// Do only use in error cases, they are quite expensive.
std::string lineAtPosition(int _position) const { return m_source->lineAtPosition(_position); }
std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source->translatePositionToLineColumn(_position); }
///@}
private:
inline Token setError(ScannerError _error) noexcept
@@ -270,6 +262,7 @@ private:
TokenDesc m_tokens[3] = {}; // desc for the current, next and nextnext token
std::shared_ptr<CharStream> m_source;
std::shared_ptr<std::string const> m_sourceName;
ScannerKind m_kind = ScannerKind::Solidity;
+2 -6
View File
@@ -34,6 +34,7 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string
boost::algorithm::split(pos, _input, boost::is_any_of(":"));
// TODO What to do with sourceIndex?
solAssert(pos.size() == 3, "SourceLocation string must have 3 colon separated numeric fields.");
auto const sourceIndex = stoi(pos[Index]);
@@ -45,12 +46,7 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string
int start = stoi(pos[Start]);
int end = start + stoi(pos[Length]);
// ASSUMPTION: only the name of source is used from here on, the m_source of the CharStream-Object can be empty
std::shared_ptr<langutil::CharStream> source;
if (sourceIndex != -1)
source = std::make_shared<langutil::CharStream>("", _sourceName);
return SourceLocation{start, end, source};
return SourceLocation{start, end, std::make_shared<std::string>(_sourceName)};
}
}
+23 -32
View File
@@ -26,8 +26,6 @@
#include <libsolutil/Assertions.h>
#include <libsolutil/Exceptions.h>
#include <liblangutil/CharStream.h>
#include <limits>
#include <memory>
#include <string>
@@ -44,51 +42,44 @@ struct SourceLocation
{
bool operator==(SourceLocation const& _other) const
{
return source.get() == _other.source.get() && start == _other.start && end == _other.end;
return start == _other.start && end == _other.end && equalSources(_other);
}
bool operator!=(SourceLocation const& _other) const { return !operator==(_other); }
inline bool operator<(SourceLocation const& _other) const
bool operator<(SourceLocation const& _other) const
{
if (!source|| !_other.source)
return std::make_tuple(int(!!source), start, end) < std::make_tuple(int(!!_other.source), _other.start, _other.end);
if (!sourceName || !_other.sourceName)
return std::make_tuple(int(!!sourceName), start, end) < std::make_tuple(int(!!_other.sourceName), _other.start, _other.end);
else
return std::make_tuple(source->name(), start, end) < std::make_tuple(_other.source->name(), _other.start, _other.end);
return std::make_tuple(*sourceName, start, end) < std::make_tuple(*_other.sourceName, _other.start, _other.end);
}
inline bool contains(SourceLocation const& _other) const
bool contains(SourceLocation const& _other) const
{
if (!hasText() || !_other.hasText() || source.get() != _other.source.get())
if (!hasText() || !_other.hasText() || !equalSources(_other))
return false;
return start <= _other.start && _other.end <= end;
}
inline bool intersects(SourceLocation const& _other) const
bool intersects(SourceLocation const& _other) const
{
if (!hasText() || !_other.hasText() || source.get() != _other.source.get())
if (!hasText() || !_other.hasText() || !equalSources(_other))
return false;
return _other.start < end && start < _other.end;
}
bool isValid() const { return source || start != -1 || end != -1; }
bool hasText() const
bool equalSources(SourceLocation const& _other) const
{
return
source &&
0 <= start &&
start <= end &&
end <= int(source->source().length());
if (!!sourceName != !!_other.sourceName)
return false;
if (sourceName && *sourceName != *_other.sourceName)
return false;
return true;
}
std::string text() const
{
assertThrow(source, SourceLocationError, "Requested text from null source.");
assertThrow(0 <= start, SourceLocationError, "Invalid source location.");
assertThrow(start <= end, SourceLocationError, "Invalid source location.");
assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location.");
return source->source().substr(size_t(start), size_t(end - start));
}
bool isValid() const { return sourceName || start != -1 || end != -1; }
bool hasText() const { return sourceName && 0 <= start && start <= end; }
/// @returns the smallest SourceLocation that contains both @param _a and @param _b.
/// Assumes that @param _a and @param _b refer to the same source (exception: if the source of either one
@@ -97,8 +88,8 @@ struct SourceLocation
/// @param _b, then start resp. end of the result will be -1 as well).
static SourceLocation smallestCovering(SourceLocation _a, SourceLocation const& _b)
{
if (!_a.source)
_a.source = _b.source;
if (!_a.sourceName)
_a.sourceName = _b.sourceName;
if (_a.start < 0)
_a.start = _b.start;
@@ -112,7 +103,7 @@ struct SourceLocation
int start = -1;
int end = -1;
std::shared_ptr<CharStream> source;
std::shared_ptr<std::string const> sourceName;
};
SourceLocation const parseSourceLocation(
@@ -127,8 +118,8 @@ inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _locat
if (!_location.isValid())
return _out << "NO_LOCATION_SPECIFIED";
if (_location.source)
_out << _location.source->name();
if (_location.sourceName)
_out << *_location.sourceName;
_out << "[" << _location.start << "," << _location.end << "]";
+26 -14
View File
@@ -16,8 +16,9 @@
*/
// SPDX-License-Identifier: GPL-3.0
#include <liblangutil/SourceReferenceExtractor.h>
#include <liblangutil/CharStream.h>
#include <liblangutil/Exceptions.h>
#include <liblangutil/CharStreamProvider.h>
#include <liblangutil/CharStream.h>
#include <algorithm>
#include <cmath>
@@ -26,46 +27,57 @@ using namespace std;
using namespace solidity;
using namespace solidity::langutil;
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Exception const& _exception, string _category)
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
CharStreamProvider const& _charStreamProvider,
util::Exception const& _exception,
string _category
)
{
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
string const* message = boost::get_error_info<util::errinfo_comment>(_exception);
SourceReference primary = extract(location, message ? *message : "");
SourceReference primary = extract(_charStreamProvider, location, message ? *message : "");
std::vector<SourceReference> secondary;
auto secondaryLocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
if (secondaryLocation && !secondaryLocation->infos.empty())
for (auto const& info: secondaryLocation->infos)
secondary.emplace_back(extract(&info.second, info.first));
secondary.emplace_back(extract(_charStreamProvider, &info.second, info.first));
return Message{std::move(primary), _category, std::move(secondary), nullopt};
}
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Error const& _error)
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
CharStreamProvider const& _charStreamProvider,
Error const& _error
)
{
string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error";
Message message = extract(_error, category);
Message message = extract(_charStreamProvider, _error, category);
message.errorId = _error.errorId();
return message;
}
SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message)
SourceReference SourceReferenceExtractor::extract(
CharStreamProvider const& _charStreamProvider,
SourceLocation const* _location,
std::string message
)
{
if (!_location || !_location->source.get()) // Nothing we can extract here
if (!_location || !_location->sourceName) // Nothing we can extract here
return SourceReference::MessageOnly(std::move(message));
if (!_location->hasText()) // No source text, so we can only extract the source name
return SourceReference::MessageOnly(std::move(message), _location->source->name());
return SourceReference::MessageOnly(std::move(message), *_location->sourceName);
shared_ptr<CharStream> const& source = _location->source;
CharStream const& charStream = _charStreamProvider.charStream(*_location->sourceName);
LineColumn const interest = source->translatePositionToLineColumn(_location->start);
LineColumn const interest = charStream.translatePositionToLineColumn(_location->start);
LineColumn start = interest;
LineColumn end = source->translatePositionToLineColumn(_location->end);
LineColumn end = charStream.translatePositionToLineColumn(_location->end);
bool const isMultiline = start.line != end.line;
string line = source->lineAtPosition(_location->start);
string line = charStream.lineAtPosition(_location->start);
int locationLength =
isMultiline ?
@@ -102,7 +114,7 @@ SourceReference SourceReferenceExtractor::extract(SourceLocation const* _locatio
return SourceReference{
std::move(message),
source->name(),
*_location->sourceName,
interest,
isMultiline,
line,
+5 -3
View File
@@ -28,6 +28,8 @@
namespace solidity::langutil
{
class CharStreamProvider;
struct LineColumn
{
int line = {-1};
@@ -67,9 +69,9 @@ namespace SourceReferenceExtractor
std::optional<ErrorId> errorId;
};
Message extract(util::Exception const& _exception, std::string _category);
Message extract(Error const& _error);
SourceReference extract(SourceLocation const* _location, std::string message = "");
Message extract(CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, std::string _category);
Message extract(CharStreamProvider const& _charStreamProvider, Error const& _error);
SourceReference extract(CharStreamProvider const& _charStreamProvider, SourceLocation const* _location, std::string message = "");
}
}
+8 -2
View File
@@ -173,10 +173,16 @@ void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtracto
void SourceReferenceFormatter::printExceptionInformation(util::Exception const& _exception, std::string const& _category)
{
printExceptionInformation(SourceReferenceExtractor::extract(_exception, _category));
printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _exception, _category));
}
void SourceReferenceFormatter::printErrorInformation(ErrorList const& _errors)
{
for (auto const& error: _errors)
printErrorInformation(*error);
}
void SourceReferenceFormatter::printErrorInformation(Error const& _error)
{
printExceptionInformation(SourceReferenceExtractor::extract(_error));
printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _error));
}
+26 -5
View File
@@ -23,6 +23,7 @@
#include <liblangutil/Exceptions.h>
#include <liblangutil/SourceReferenceExtractor.h>
#include <liblangutil/CharStreamProvider.h>
#include <libsolutil/AnsiColorized.h>
@@ -37,34 +38,53 @@ struct SourceLocation;
class SourceReferenceFormatter
{
public:
SourceReferenceFormatter(std::ostream& _stream, bool _colored, bool _withErrorIds):
m_stream(_stream), m_colored(_colored), m_withErrorIds(_withErrorIds)
SourceReferenceFormatter(
std::ostream& _stream,
CharStreamProvider const& _charStreamProvider,
bool _colored,
bool _withErrorIds
):
m_stream(_stream), m_charStreamProvider(_charStreamProvider), m_colored(_colored), m_withErrorIds(_withErrorIds)
{}
/// Prints source location if it is given.
void printSourceLocation(SourceReference const& _ref);
void printExceptionInformation(SourceReferenceExtractor::Message const& _msg);
void printExceptionInformation(util::Exception const& _exception, std::string const& _category);
void printErrorInformation(langutil::ErrorList const& _errors);
void printErrorInformation(Error const& _error);
static std::string formatExceptionInformation(
util::Exception const& _exception,
std::string const& _name,
CharStreamProvider const& _charStreamProvider,
bool _colored = false,
bool _withErrorIds = false
)
{
std::ostringstream errorOutput;
SourceReferenceFormatter formatter(errorOutput, _colored, _withErrorIds);
SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds);
formatter.printExceptionInformation(_exception, _name);
return errorOutput.str();
}
static std::string formatErrorInformation(Error const& _error)
static std::string formatErrorInformation(
Error const& _error,
CharStreamProvider const& _charStreamProvider
)
{
return formatExceptionInformation(
_error,
(_error.type() == Error::Type::Warning) ? "Warning" : "Error"
(_error.type() == Error::Type::Warning) ? "Warning" : "Error",
_charStreamProvider
);
}
static std::string formatErrorInformation(Error const& _error, CharStream const& _charStream)
{
return formatErrorInformation(
_error,
SingletonCharStreamProvider(_charStream)
);
}
@@ -79,6 +99,7 @@ private:
private:
std::ostream& m_stream;
CharStreamProvider const& m_charStreamProvider;
bool m_colored;
bool m_withErrorIds;
};