mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Remove CharStream from SourceLocation.
This commit is contained in:
parent
57d32ca252
commit
f75b55071e
@ -76,15 +76,15 @@ namespace
|
||||
string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location)
|
||||
{
|
||||
if (!_location.hasText() || _sourceCodes.empty())
|
||||
return "";
|
||||
return {};
|
||||
|
||||
auto it = _sourceCodes.find(_location.source->name());
|
||||
auto it = _sourceCodes.find(*_location.sourceName);
|
||||
if (it == _sourceCodes.end())
|
||||
return "";
|
||||
return {};
|
||||
|
||||
string const& source = it->second;
|
||||
if (static_cast<size_t>(_location.start) >= source.size())
|
||||
return "";
|
||||
return {};
|
||||
|
||||
string cut = source.substr(static_cast<size_t>(_location.start), static_cast<size_t>(_location.end - _location.start));
|
||||
auto newLinePos = cut.find_first_of("\n");
|
||||
@ -152,8 +152,8 @@ public:
|
||||
if (!m_location.isValid())
|
||||
return;
|
||||
m_out << m_prefix << " /*";
|
||||
if (m_location.source)
|
||||
m_out << " \"" + m_location.source->name() + "\"";
|
||||
if (m_location.sourceName)
|
||||
m_out << " " + escapeAndQuoteYulString(*m_location.sourceName);
|
||||
if (m_location.hasText())
|
||||
m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end);
|
||||
m_out << " " << locationFromSources(m_sourceCodes, m_location);
|
||||
@ -235,9 +235,9 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
|
||||
for (AssemblyItem const& i: m_items)
|
||||
{
|
||||
int sourceIndex = -1;
|
||||
if (i.location().source)
|
||||
if (i.location().sourceName)
|
||||
{
|
||||
auto iter = _sourceIndices.find(i.location().source->name());
|
||||
auto iter = _sourceIndices.find(*i.location().sourceName);
|
||||
if (iter != _sourceIndices.end())
|
||||
sourceIndex = static_cast<int>(iter->second);
|
||||
}
|
||||
|
@ -350,8 +350,8 @@ std::string AssemblyItem::computeSourceMapping(
|
||||
SourceLocation const& location = item.location();
|
||||
int length = location.start != -1 && location.end != -1 ? location.end - location.start : -1;
|
||||
int sourceIndex =
|
||||
location.source && _sourceIndicesMap.count(location.source->name()) ?
|
||||
static_cast<int>(_sourceIndicesMap.at(location.source->name())) :
|
||||
(location.sourceName && _sourceIndicesMap.count(*location.sourceName)) ?
|
||||
static_cast<int>(_sourceIndicesMap.at(*location.sourceName)) :
|
||||
-1;
|
||||
char jump = '-';
|
||||
if (item.getJumpType() == evmasm::AssemblyItem::JumpType::IntoFunction)
|
||||
|
@ -13,6 +13,7 @@ set(sources
|
||||
ParserBase.h
|
||||
Scanner.cpp
|
||||
Scanner.h
|
||||
CharStreamProvider.h
|
||||
SemVerHandler.cpp
|
||||
SemVerHandler.h
|
||||
SourceLocation.h
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
@ -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
liblangutil/CharStreamProvider.h
Normal file
57
liblangutil/CharStreamProvider.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 << "]";
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 = "");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -520,9 +520,9 @@ bool DeclarationRegistrationHelper::registerDeclaration(
|
||||
Declaration const* conflictingDeclaration = _container.conflictingDeclaration(_declaration, _name);
|
||||
solAssert(conflictingDeclaration, "");
|
||||
bool const comparable =
|
||||
_errorLocation->source &&
|
||||
conflictingDeclaration->location().source &&
|
||||
_errorLocation->source->name() == conflictingDeclaration->location().source->name();
|
||||
_errorLocation->sourceName &&
|
||||
conflictingDeclaration->location().sourceName &&
|
||||
*_errorLocation->sourceName == *conflictingDeclaration->location().sourceName;
|
||||
if (comparable && _errorLocation->start < conflictingDeclaration->location().start)
|
||||
{
|
||||
firstDeclarationLocation = *_errorLocation;
|
||||
|
@ -68,7 +68,7 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit)
|
||||
string(";\"");
|
||||
|
||||
// when reporting the warning, print the source name only
|
||||
m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().source}, errorString);
|
||||
m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().sourceName}, errorString);
|
||||
}
|
||||
if (!m_sourceUnit->annotation().useABICoderV2.set())
|
||||
m_sourceUnit->annotation().useABICoderV2 = true;
|
||||
|
@ -110,8 +110,8 @@ void ASTJsonConverter::setJsonNode(
|
||||
|
||||
optional<size_t> ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location) const
|
||||
{
|
||||
if (_location.source && m_sourceIndices.count(_location.source->name()))
|
||||
return m_sourceIndices.at(_location.source->name());
|
||||
if (_location.sourceName && m_sourceIndices.count(*_location.sourceName))
|
||||
return m_sourceIndices.at(*_location.sourceName);
|
||||
else
|
||||
return nullopt;
|
||||
}
|
||||
|
@ -455,7 +455,9 @@ void CompilerContext::appendInlineAssembly(
|
||||
_assembly + "\n"
|
||||
"------------------ Errors: ----------------\n";
|
||||
for (auto const& error: errorReporter.errors())
|
||||
message += SourceReferenceFormatter::formatErrorInformation(*error);
|
||||
// TODO if we have "locationOverride", it will be the wrong char stream,
|
||||
// but we do not have access to the solidity scanner.
|
||||
message += SourceReferenceFormatter::formatErrorInformation(*error, *scanner->charStream());
|
||||
message += "-------------------------------------------\n";
|
||||
|
||||
solAssert(false, message);
|
||||
|
@ -129,8 +129,9 @@ string IRNames::zeroValue(Type const& _type, string const& _variableName)
|
||||
|
||||
string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext const& _context)
|
||||
{
|
||||
solAssert(_location.sourceName, "");
|
||||
return "/// @src "
|
||||
+ to_string(_context.sourceIndices().at(_location.source->name()))
|
||||
+ to_string(_context.sourceIndices().at(*_location.sourceName))
|
||||
+ ":"
|
||||
+ to_string(_location.start)
|
||||
+ ","
|
||||
|
@ -101,7 +101,10 @@ pair<string, string> IRGenerator::run(
|
||||
{
|
||||
string errorMessage;
|
||||
for (auto const& error: asmStack.errors())
|
||||
errorMessage += langutil::SourceReferenceFormatter::formatErrorInformation(*error);
|
||||
errorMessage += langutil::SourceReferenceFormatter::formatErrorInformation(
|
||||
*error,
|
||||
asmStack.charStream("")
|
||||
);
|
||||
solAssert(false, ir + "\n\nInvalid IR generated:\n" + errorMessage + "\n");
|
||||
}
|
||||
asmStack.optimize();
|
||||
|
@ -650,7 +650,7 @@ pair<vector<smtutil::Expression>, vector<string>> BMC::modelExpressions()
|
||||
if (uf->annotation().type->isValueType())
|
||||
{
|
||||
expressionsToEvaluate.emplace_back(expr(*uf));
|
||||
expressionNames.push_back(uf->location().text());
|
||||
// TODO expressionNames.push_back(uf->location().text());
|
||||
}
|
||||
|
||||
return {expressionsToEvaluate, expressionNames};
|
||||
|
@ -200,8 +200,9 @@ string Predicate::formatSummaryCall(vector<smtutil::Expression> const& _args) co
|
||||
{
|
||||
solAssert(isSummary(), "");
|
||||
|
||||
if (auto funCall = programFunctionCall())
|
||||
return funCall->location().text();
|
||||
//if (auto funCall = programFunctionCall())
|
||||
// return funCall->location().text();
|
||||
// TODO
|
||||
|
||||
/// The signature of a function summary predicate is: summary(error, this, abiFunctions, cryptoFunctions, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in preInputVars to format the function call,
|
||||
|
@ -926,19 +926,6 @@ map<string, unsigned> CompilerStack::sourceIndices() const
|
||||
return indices;
|
||||
}
|
||||
|
||||
map<unsigned, shared_ptr<CharStream>> CompilerStack::indicesToCharStreams() const
|
||||
{
|
||||
map<unsigned, shared_ptr<CharStream>> result;
|
||||
unsigned index = 0;
|
||||
for (auto const& s: m_sources)
|
||||
result[index++] = s.second.scanner->charStream();
|
||||
|
||||
// NB: CompilerContext::yulUtilityFileName() does not have a source,
|
||||
result[index++] = shared_ptr<CharStream>{};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Json::Value const& CompilerStack::contractABI(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState < AnalysisPerformed)
|
||||
@ -1048,12 +1035,15 @@ string const& CompilerStack::metadata(Contract const& _contract) const
|
||||
return _contract.metadata.init([&]{ return createMetadata(_contract); });
|
||||
}
|
||||
|
||||
Scanner const& CompilerStack::scanner(string const& _sourceName) const
|
||||
CharStream const& CompilerStack::charStream(string const& _sourceName) const
|
||||
{
|
||||
if (m_stackState < SourcesSet)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No sources set."));
|
||||
|
||||
return *source(_sourceName).scanner;
|
||||
solAssert(source(_sourceName).scanner, "");
|
||||
solAssert(source(_sourceName).scanner->charStream(), "");
|
||||
|
||||
return *source(_sourceName).scanner->charStream();
|
||||
}
|
||||
|
||||
SourceUnit const& CompilerStack::ast(string const& _sourceName) const
|
||||
@ -1095,19 +1085,6 @@ size_t CompilerStack::functionEntryPoint(
|
||||
return 0;
|
||||
}
|
||||
|
||||
tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocation const& _sourceLocation) const
|
||||
{
|
||||
int startLine;
|
||||
int startColumn;
|
||||
int endLine;
|
||||
int endColumn;
|
||||
tie(startLine, startColumn) = scanner(_sourceLocation.source->name()).translatePositionToLineColumn(_sourceLocation.start);
|
||||
tie(endLine, endColumn) = scanner(_sourceLocation.source->name()).translatePositionToLineColumn(_sourceLocation.end);
|
||||
|
||||
return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn);
|
||||
}
|
||||
|
||||
|
||||
h256 const& CompilerStack::Source::keccak256() const
|
||||
{
|
||||
if (keccak256HashCached == h256{})
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
|
||||
@ -57,6 +58,7 @@
|
||||
namespace solidity::langutil
|
||||
{
|
||||
class Scanner;
|
||||
class CharStream;
|
||||
}
|
||||
|
||||
|
||||
@ -87,7 +89,7 @@ class DeclarationContainer;
|
||||
* If error recovery is active, it is possible to progress through the stages even when
|
||||
* there are errors. In any case, producing code is only possible without errors.
|
||||
*/
|
||||
class CompilerStack
|
||||
class CompilerStack: public langutil::CharStreamProvider
|
||||
{
|
||||
public:
|
||||
/// Noncopyable.
|
||||
@ -120,7 +122,7 @@ public:
|
||||
/// and must not emit exceptions.
|
||||
explicit CompilerStack(ReadCallback::Callback _readFile = ReadCallback::Callback());
|
||||
|
||||
~CompilerStack();
|
||||
~CompilerStack() override;
|
||||
|
||||
/// @returns the list of errors that occurred during parsing and type checking.
|
||||
langutil::ErrorList const& errors() const { return m_errorReporter.errors(); }
|
||||
@ -239,12 +241,8 @@ public:
|
||||
/// by sourceNames().
|
||||
std::map<std::string, unsigned> sourceIndices() const;
|
||||
|
||||
/// @returns the reverse mapping of source indices to their respective
|
||||
/// CharStream instances.
|
||||
std::map<unsigned, std::shared_ptr<langutil::CharStream>> indicesToCharStreams() const;
|
||||
|
||||
/// @returns the previously used scanner, useful for counting lines during error reporting.
|
||||
langutil::Scanner const& scanner(std::string const& _sourceName) const;
|
||||
/// @returns the previously used character stream, useful for counting lines during error reporting.
|
||||
langutil::CharStream const& charStream(std::string const& _sourceName) const override;
|
||||
|
||||
/// @returns the parsed source unit with the supplied name.
|
||||
SourceUnit const& ast(std::string const& _sourceName) const;
|
||||
@ -253,11 +251,6 @@ public:
|
||||
/// does not exist.
|
||||
ContractDefinition const& contractDefinition(std::string const& _contractName) const;
|
||||
|
||||
/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
|
||||
/// line and columns are numbered starting from 1 with following order:
|
||||
/// start line, start column, end line, end column
|
||||
std::tuple<int, int, int, int> positionFromSourceLocation(langutil::SourceLocation const& _sourceLocation) const;
|
||||
|
||||
/// @returns a list of unhandled queries to the SMT solver (has to be supplied in a second run
|
||||
/// by calling @a addSMTLib2Response).
|
||||
std::vector<std::string> const& unhandledSMTLib2Queries() const { return m_unhandledSMTLib2Queries; }
|
||||
|
@ -83,9 +83,9 @@ Json::Value formatFatalError(string const& _type, string const& _message)
|
||||
Json::Value formatSourceLocation(SourceLocation const* location)
|
||||
{
|
||||
Json::Value sourceLocation;
|
||||
if (location && location->source)
|
||||
if (location && location->sourceName)
|
||||
{
|
||||
sourceLocation["file"] = location->source->name();
|
||||
sourceLocation["file"] = *location->sourceName;
|
||||
sourceLocation["start"] = location->start;
|
||||
sourceLocation["end"] = location->end;
|
||||
}
|
||||
@ -109,6 +109,7 @@ Json::Value formatSecondarySourceLocation(SecondarySourceLocation const* _second
|
||||
}
|
||||
|
||||
Json::Value formatErrorWithException(
|
||||
CharStreamProvider const& _charStreamProvider,
|
||||
util::Exception const& _exception,
|
||||
bool const& _warning,
|
||||
string const& _type,
|
||||
@ -119,7 +120,11 @@ Json::Value formatErrorWithException(
|
||||
{
|
||||
string message;
|
||||
// TODO: consider enabling color
|
||||
string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type);
|
||||
string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(
|
||||
_exception,
|
||||
_type,
|
||||
_charStreamProvider
|
||||
);
|
||||
|
||||
if (string const* description = boost::get_error_info<util::errinfo_comment>(_exception))
|
||||
message = ((_message.length() > 0) ? (_message + ":") : "") + *description;
|
||||
@ -1017,6 +1022,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
Error const& err = dynamic_cast<Error const&>(*error);
|
||||
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
*error,
|
||||
err.type() == Error::Type::Warning,
|
||||
err.typeName(),
|
||||
@ -1030,6 +1036,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
catch (Error const& _error)
|
||||
{
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
_error,
|
||||
false,
|
||||
_error.typeName(),
|
||||
@ -1050,6 +1057,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
catch (CompilerError const& _exception)
|
||||
{
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
_exception,
|
||||
false,
|
||||
"CompilerError",
|
||||
@ -1060,6 +1068,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
catch (InternalCompilerError const& _exception)
|
||||
{
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
_exception,
|
||||
false,
|
||||
"InternalCompilerError",
|
||||
@ -1070,6 +1079,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
catch (UnimplementedFeatureError const& _exception)
|
||||
{
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
_exception,
|
||||
false,
|
||||
"UnimplementedFeatureError",
|
||||
@ -1080,6 +1090,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
catch (yul::YulException const& _exception)
|
||||
{
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
_exception,
|
||||
false,
|
||||
"YulException",
|
||||
@ -1090,6 +1101,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
catch (smtutil::SMTLogicError const& _exception)
|
||||
{
|
||||
errors.append(formatErrorWithException(
|
||||
compilerStack,
|
||||
_exception,
|
||||
false,
|
||||
"SMTLogicException",
|
||||
@ -1297,6 +1309,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
||||
auto err = dynamic_pointer_cast<Error const>(error);
|
||||
|
||||
errors.append(formatErrorWithException(
|
||||
stack,
|
||||
*error,
|
||||
err->type() == Error::Type::Warning,
|
||||
err->typeName(),
|
||||
|
@ -50,7 +50,12 @@ class Parser::ASTNodeFactory
|
||||
{
|
||||
public:
|
||||
explicit ASTNodeFactory(Parser& _parser):
|
||||
m_parser(_parser), m_location{_parser.currentLocation().start, -1, _parser.currentLocation().source} {}
|
||||
m_parser(_parser), m_location{
|
||||
_parser.currentLocation().start,
|
||||
-1,
|
||||
_parser.currentLocation().sourceName
|
||||
}
|
||||
{}
|
||||
ASTNodeFactory(Parser& _parser, ASTPointer<ASTNode> const& _childNode):
|
||||
m_parser(_parser), m_location{_childNode->location()} {}
|
||||
|
||||
@ -63,7 +68,7 @@ public:
|
||||
template <class NodeType, typename... Args>
|
||||
ASTPointer<NodeType> createNode(Args&& ... _args)
|
||||
{
|
||||
solAssert(m_location.source, "");
|
||||
solAssert(m_location.sourceName, "");
|
||||
if (m_location.end < 0)
|
||||
markEndPosition();
|
||||
return make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...);
|
||||
@ -2084,7 +2089,7 @@ optional<string> Parser::findLicenseString(std::vector<ASTPointer<ASTNode>> cons
|
||||
else if (matches.empty())
|
||||
parserWarning(
|
||||
1878_error,
|
||||
{-1, -1, m_scanner->charStream()},
|
||||
{-1, -1, m_scanner->currentLocation().sourceName},
|
||||
"SPDX license identifier not provided in source file. "
|
||||
"Before publishing, consider adding a comment containing "
|
||||
"\"SPDX-License-Identifier: <SPDX-License>\" to each source file. "
|
||||
@ -2094,7 +2099,7 @@ optional<string> Parser::findLicenseString(std::vector<ASTPointer<ASTNode>> cons
|
||||
else
|
||||
parserError(
|
||||
3716_error,
|
||||
{-1, -1, m_scanner->charStream()},
|
||||
{-1, -1, m_scanner->currentLocation().sourceName},
|
||||
"Multiple SPDX license identifiers found in source file. "
|
||||
"Use \"AND\" or \"OR\" to combine multiple licenses. "
|
||||
"Please see https://spdx.org for more information."
|
||||
|
@ -53,10 +53,7 @@ T AsmJsonImporter::createAsmNode(Json::Value const& _node)
|
||||
{
|
||||
T r;
|
||||
SourceLocation location = createSourceLocation(_node);
|
||||
yulAssert(
|
||||
location.source && 0 <= location.start && location.start <= location.end,
|
||||
"Invalid source location in Asm AST"
|
||||
);
|
||||
yulAssert(location.hasText(), "Invalid source location in Asm AST");
|
||||
r.debugData = DebugData::create(location);
|
||||
return r;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ unique_ptr<Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner, bool _
|
||||
try
|
||||
{
|
||||
m_scanner = _scanner;
|
||||
if (m_charStreamMap)
|
||||
if (m_sourceNames)
|
||||
fetchSourceLocationFromComment();
|
||||
auto block = make_unique<Block>(parseBlock());
|
||||
if (!_reuseScanner)
|
||||
@ -105,7 +105,7 @@ langutil::Token Parser::advance()
|
||||
|
||||
void Parser::fetchSourceLocationFromComment()
|
||||
{
|
||||
solAssert(m_charStreamMap.has_value(), "");
|
||||
solAssert(m_sourceNames.has_value(), "");
|
||||
|
||||
if (m_scanner->currentCommentLiteral().empty())
|
||||
return;
|
||||
@ -133,13 +133,13 @@ void Parser::fetchSourceLocationFromComment()
|
||||
m_errorReporter.syntaxError(6367_error, commentLocation, "Invalid value in source location mapping. Could not parse location specification.");
|
||||
else if (sourceIndex == -1)
|
||||
m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, nullptr});
|
||||
else if (!(sourceIndex >= 0 && m_charStreamMap->count(static_cast<unsigned>(*sourceIndex))))
|
||||
else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast<unsigned>(*sourceIndex))))
|
||||
m_errorReporter.syntaxError(2674_error, commentLocation, "Invalid source mapping. Source index not defined via @use-src.");
|
||||
else
|
||||
{
|
||||
shared_ptr<CharStream> charStream = m_charStreamMap->at(static_cast<unsigned>(*sourceIndex));
|
||||
solAssert(charStream, "");
|
||||
m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, charStream});
|
||||
shared_ptr<string const> sourceName = m_sourceNames->at(static_cast<unsigned>(*sourceIndex));
|
||||
solAssert(sourceName, "");
|
||||
m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, move(sourceName)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ public:
|
||||
explicit Parser(
|
||||
langutil::ErrorReporter& _errorReporter,
|
||||
Dialect const& _dialect,
|
||||
std::map<unsigned, std::shared_ptr<langutil::CharStream>> _charStreamMap
|
||||
std::map<unsigned, std::shared_ptr<std::string const>> _sourceNames
|
||||
):
|
||||
ParserBase(_errorReporter),
|
||||
m_dialect(_dialect),
|
||||
m_charStreamMap{std::move(_charStreamMap)},
|
||||
m_sourceNames{std::move(_sourceNames)},
|
||||
m_debugDataOverride{DebugData::create()},
|
||||
m_useSourceLocationFrom{UseSourceLocationFrom::Comments}
|
||||
{}
|
||||
@ -144,7 +144,7 @@ protected:
|
||||
private:
|
||||
Dialect const& m_dialect;
|
||||
|
||||
std::optional<std::map<unsigned, std::shared_ptr<langutil::CharStream>>> m_charStreamMap;
|
||||
std::optional<std::map<unsigned, std::shared_ptr<std::string const>>> m_sourceNames;
|
||||
langutil::SourceLocation m_locationOverride;
|
||||
std::shared_ptr<DebugData const> m_debugDataOverride;
|
||||
UseSourceLocationFrom m_useSourceLocationFrom = UseSourceLocationFrom::Scanner;
|
||||
|
@ -88,18 +88,20 @@ evmasm::Assembly::OptimiserSettings translateOptimiserSettings(
|
||||
}
|
||||
|
||||
|
||||
Scanner const& AssemblyStack::scanner() const
|
||||
CharStream const& AssemblyStack::charStream(string const& _sourceName) const
|
||||
{
|
||||
yulAssert(m_scanner, "");
|
||||
return *m_scanner;
|
||||
yulAssert(m_charStream, "");
|
||||
yulAssert(m_charStream->name() == _sourceName, "");
|
||||
return *m_charStream;
|
||||
}
|
||||
|
||||
bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string const& _source)
|
||||
{
|
||||
m_errors.clear();
|
||||
m_analysisSuccessful = false;
|
||||
m_scanner = make_shared<Scanner>(CharStream(_source, _sourceName));
|
||||
m_parserResult = ObjectParser(m_errorReporter, languageToDialect(m_language, m_evmVersion)).parse(m_scanner, false);
|
||||
m_charStream = make_unique<CharStream>(_source, _sourceName);
|
||||
shared_ptr<Scanner> scanner = make_shared<Scanner>(*m_charStream);
|
||||
m_parserResult = ObjectParser(m_errorReporter, languageToDialect(m_language, m_evmVersion)).parse(scanner, false);
|
||||
if (!m_errorReporter.errors().empty())
|
||||
return false;
|
||||
yulAssert(m_parserResult, "");
|
||||
@ -132,7 +134,8 @@ void AssemblyStack::translate(AssemblyStack::Language _targetLanguage)
|
||||
);
|
||||
|
||||
*m_parserResult = EVMToEwasmTranslator(
|
||||
languageToDialect(m_language, m_evmVersion)
|
||||
languageToDialect(m_language, m_evmVersion),
|
||||
*this
|
||||
).run(*parserResult());
|
||||
|
||||
m_language = _targetLanguage;
|
||||
@ -241,6 +244,7 @@ AssemblyStack::assembleWithDeployed(optional<string_view> _deployName) const
|
||||
{
|
||||
auto [creationAssembly, deployedAssembly] = assembleEVMWithDeployed(_deployName);
|
||||
yulAssert(creationAssembly, "");
|
||||
yulAssert(m_charStream, "");
|
||||
|
||||
MachineAssemblyObject creationObject;
|
||||
creationObject.bytecode = make_shared<evmasm::LinkerObject>(creationAssembly->assemble());
|
||||
@ -249,7 +253,7 @@ AssemblyStack::assembleWithDeployed(optional<string_view> _deployName) const
|
||||
creationObject.sourceMappings = make_unique<string>(
|
||||
evmasm::AssemblyItem::computeSourceMapping(
|
||||
creationAssembly->items(),
|
||||
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
|
||||
{{m_charStream->name(), 0}}
|
||||
)
|
||||
);
|
||||
|
||||
@ -261,7 +265,7 @@ AssemblyStack::assembleWithDeployed(optional<string_view> _deployName) const
|
||||
deployedObject.sourceMappings = make_unique<string>(
|
||||
evmasm::AssemblyItem::computeSourceMapping(
|
||||
deployedAssembly->items(),
|
||||
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
|
||||
{{m_charStream->name(), 0}}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
|
||||
#include <libyul/Object.h>
|
||||
#include <libyul/ObjectParser.h>
|
||||
@ -61,7 +62,7 @@ struct MachineAssemblyObject
|
||||
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
|
||||
* Ewasm as output.
|
||||
*/
|
||||
class AssemblyStack
|
||||
class AssemblyStack: public langutil::CharStreamProvider
|
||||
{
|
||||
public:
|
||||
enum class Language { Yul, Assembly, StrictAssembly, Ewasm };
|
||||
@ -77,8 +78,8 @@ public:
|
||||
m_errorReporter(m_errors)
|
||||
{}
|
||||
|
||||
/// @returns the scanner used during parsing
|
||||
langutil::Scanner const& scanner() const;
|
||||
/// @returns the char stream used during parsing
|
||||
langutil::CharStream const& charStream(std::string const& _sourceName) const override;
|
||||
|
||||
/// Runs parsing and analysis steps, returns false if input cannot be assembled.
|
||||
/// Multiple calls overwrite the previous state.
|
||||
@ -132,7 +133,7 @@ private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
solidity::frontend::OptimiserSettings m_optimiserSettings;
|
||||
|
||||
std::shared_ptr<langutil::Scanner> m_scanner;
|
||||
std::unique_ptr<langutil::CharStream> m_charStream;
|
||||
|
||||
bool m_analysisSuccessful = false;
|
||||
std::shared_ptr<yul::Object> m_parserResult;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
|
||||
@ -106,7 +107,7 @@ Object EVMToEwasmTranslator::run(Object const& _object)
|
||||
message += ret.toString(&WasmDialect::instance());
|
||||
message += "----------------------------------\n";
|
||||
for (auto const& err: errors)
|
||||
message += langutil::SourceReferenceFormatter::formatErrorInformation(*err);
|
||||
message += langutil::SourceReferenceFormatter::formatErrorInformation(*err, m_charStreamProvider);
|
||||
yulAssert(false, message);
|
||||
}
|
||||
|
||||
@ -140,7 +141,10 @@ void EVMToEwasmTranslator::parsePolyfill()
|
||||
{
|
||||
string message;
|
||||
for (auto const& err: errors)
|
||||
message += langutil::SourceReferenceFormatter::formatErrorInformation(*err);
|
||||
message += langutil::SourceReferenceFormatter::formatErrorInformation(
|
||||
*err,
|
||||
SingletonCharStreamProvider(*scanner->charStream())
|
||||
);
|
||||
yulAssert(false, message);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/Dialect.h>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
class CharStreamProvider;
|
||||
}
|
||||
namespace solidity::yul
|
||||
{
|
||||
struct Object;
|
||||
@ -32,13 +36,17 @@ struct Object;
|
||||
class EVMToEwasmTranslator: public ASTModifier
|
||||
{
|
||||
public:
|
||||
EVMToEwasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {}
|
||||
EVMToEwasmTranslator(Dialect const& _evmDialect, langutil::CharStreamProvider const& _charStreamProvider):
|
||||
m_dialect(_evmDialect),
|
||||
m_charStreamProvider(_charStreamProvider)
|
||||
{}
|
||||
Object run(Object const& _object);
|
||||
|
||||
private:
|
||||
void parsePolyfill();
|
||||
|
||||
Dialect const& m_dialect;
|
||||
langutil::CharStreamProvider const& m_charStreamProvider;
|
||||
|
||||
std::shared_ptr<Block> m_polyfill;
|
||||
std::set<YulString> m_polyfillFunctions;
|
||||
|
@ -561,7 +561,7 @@ bool CommandLineInterface::compile()
|
||||
|
||||
m_compiler = make_unique<CompilerStack>(m_fileReader.reader());
|
||||
|
||||
SourceReferenceFormatter formatter(serr(false), coloredOutput(m_options), m_options.formatting.withErrorIds);
|
||||
SourceReferenceFormatter formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds);
|
||||
|
||||
try
|
||||
{
|
||||
@ -598,8 +598,7 @@ bool CommandLineInterface::compile()
|
||||
|
||||
if (!m_compiler->analyze())
|
||||
{
|
||||
for (auto const& error: m_compiler->errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
formatter.printErrorInformation(m_compiler->errors());
|
||||
astAssert(false, "Analysis of the AST failed");
|
||||
}
|
||||
}
|
||||
@ -974,7 +973,7 @@ bool CommandLineInterface::assemble(
|
||||
for (auto const& sourceAndStack: assemblyStacks)
|
||||
{
|
||||
auto const& stack = sourceAndStack.second;
|
||||
SourceReferenceFormatter formatter(serr(false), coloredOutput(m_options), m_options.formatting.withErrorIds);
|
||||
SourceReferenceFormatter formatter(serr(false), stack, coloredOutput(m_options), m_options.formatting.withErrorIds);
|
||||
|
||||
for (auto const& error: stack.errors())
|
||||
{
|
||||
|
@ -57,11 +57,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
||||
{ "sub.asm", 1 }
|
||||
};
|
||||
Assembly _assembly;
|
||||
auto root_asm = make_shared<CharStream>("lorem ipsum", "root.asm");
|
||||
auto root_asm = make_shared<string>("root.asm");
|
||||
_assembly.setSourceLocation({1, 3, root_asm});
|
||||
|
||||
Assembly _subAsm;
|
||||
auto sub_asm = make_shared<CharStream>("lorem ipsum", "sub.asm");
|
||||
auto sub_asm = make_shared<string>("sub.asm");
|
||||
_subAsm.setSourceLocation({6, 8, sub_asm});
|
||||
// PushImmutable
|
||||
_subAsm.appendImmutable("someImmutable");
|
||||
@ -172,11 +172,11 @@ BOOST_AUTO_TEST_CASE(immutable)
|
||||
{ "sub.asm", 1 }
|
||||
};
|
||||
Assembly _assembly;
|
||||
auto root_asm = make_shared<CharStream>("lorem ipsum", "root.asm");
|
||||
auto root_asm = make_shared<string>("root.asm");
|
||||
_assembly.setSourceLocation({1, 3, root_asm});
|
||||
|
||||
Assembly _subAsm;
|
||||
auto sub_asm = make_shared<CharStream>("lorem ipsum", "sub.asm");
|
||||
auto sub_asm = make_shared<string>("sub.asm");
|
||||
_subAsm.setSourceLocation({6, 8, sub_asm});
|
||||
_subAsm.appendImmutable("someImmutable");
|
||||
_subAsm.appendImmutable("someOtherImmutable");
|
||||
|
@ -34,9 +34,9 @@ BOOST_AUTO_TEST_SUITE(SourceLocationTest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_fail)
|
||||
{
|
||||
auto const source = std::make_shared<CharStream>("lorem ipsum", "source");
|
||||
auto const sourceA = std::make_shared<CharStream>("lorem ipsum", "sourceA");
|
||||
auto const sourceB = std::make_shared<CharStream>("lorem ipsum", "sourceB");
|
||||
auto const source = std::make_shared<std::string>("source");
|
||||
auto const sourceA = std::make_shared<std::string>("sourceA");
|
||||
auto const sourceB = std::make_shared<std::string>("sourceB");
|
||||
|
||||
BOOST_CHECK(SourceLocation{} == SourceLocation{});
|
||||
BOOST_CHECK((SourceLocation{0, 3, sourceA} != SourceLocation{0, 3, sourceB}));
|
||||
|
@ -141,9 +141,8 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi
|
||||
|
||||
if (!c.compile(CompilerStack::State::Parsed))
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, _formatted, false);
|
||||
for (auto const& error: c.errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
SourceReferenceFormatter formatter(_stream, c, _formatted, false);
|
||||
formatter.printErrorInformation(c.errors());
|
||||
return TestResult::FatalError;
|
||||
}
|
||||
|
||||
@ -167,9 +166,8 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi
|
||||
if (m_expectation.empty())
|
||||
return resultsMatch ? TestResult::Success : TestResult::Failure;
|
||||
|
||||
SourceReferenceFormatter formatter(_stream, _formatted, false);
|
||||
for (auto const& error: c.errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
SourceReferenceFormatter{_stream, c, _formatted, false}
|
||||
.printErrorInformation(c.errors());
|
||||
return TestResult::FatalError;
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ string AnalysisFramework::formatErrors() const
|
||||
|
||||
string AnalysisFramework::formatError(Error const& _error) const
|
||||
{
|
||||
return SourceReferenceFormatter::formatErrorInformation(_error);
|
||||
return SourceReferenceFormatter::formatErrorInformation(_error, *m_compiler);
|
||||
}
|
||||
|
||||
ContractDefinition const* AnalysisFramework::retrieveContractByName(SourceUnit const& _source, string const& _name)
|
||||
|
@ -109,7 +109,7 @@ void printAssemblyLocations(AssemblyItems const& _items)
|
||||
", " <<
|
||||
_loc.end <<
|
||||
", make_shared<string>(\"" <<
|
||||
_loc.source->name() <<
|
||||
*_loc.sourceName <<
|
||||
"\")}) +" << endl;
|
||||
};
|
||||
|
||||
@ -157,15 +157,16 @@ BOOST_AUTO_TEST_SUITE(Assembly)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(location_test)
|
||||
{
|
||||
auto sourceCode = make_shared<CharStream>(R"(
|
||||
string sourceCode = R"(
|
||||
pragma abicoder v1;
|
||||
contract test {
|
||||
function f() public returns (uint256 a) {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
)", "");
|
||||
AssemblyItems items = compileContract(sourceCode);
|
||||
)";
|
||||
AssemblyItems items = compileContract(make_shared<CharStream>(sourceCode, ""));
|
||||
shared_ptr<string> sourceName = make_shared<string>();
|
||||
bool hasShifts = solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting();
|
||||
|
||||
auto codegenCharStream = make_shared<CharStream>("", "--CODEGEN--");
|
||||
@ -173,18 +174,18 @@ BOOST_AUTO_TEST_CASE(location_test)
|
||||
vector<SourceLocation> locations;
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
locations =
|
||||
vector<SourceLocation>(31, SourceLocation{23, 103, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{41, 100, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{93, 95, sourceCode}) +
|
||||
vector<SourceLocation>(15, SourceLocation{41, 100, sourceCode});
|
||||
vector<SourceLocation>(31, SourceLocation{23, 103, sourceName}) +
|
||||
vector<SourceLocation>(1, SourceLocation{41, 100, sourceName}) +
|
||||
vector<SourceLocation>(1, SourceLocation{93, 95, sourceName}) +
|
||||
vector<SourceLocation>(15, SourceLocation{41, 100, sourceName});
|
||||
else
|
||||
locations =
|
||||
vector<SourceLocation>(hasShifts ? 31 : 32, SourceLocation{23, 103, sourceCode}) +
|
||||
vector<SourceLocation>(24, SourceLocation{41, 100, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{70, 79, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{93, 95, sourceCode}) +
|
||||
vector<SourceLocation>(2, SourceLocation{86, 95, sourceCode}) +
|
||||
vector<SourceLocation>(2, SourceLocation{41, 100, sourceCode});
|
||||
vector<SourceLocation>(hasShifts ? 31 : 32, SourceLocation{23, 103, sourceName}) +
|
||||
vector<SourceLocation>(24, SourceLocation{41, 100, sourceName}) +
|
||||
vector<SourceLocation>(1, SourceLocation{70, 79, sourceName}) +
|
||||
vector<SourceLocation>(1, SourceLocation{93, 95, sourceName}) +
|
||||
vector<SourceLocation>(2, SourceLocation{86, 95, sourceName}) +
|
||||
vector<SourceLocation>(2, SourceLocation{41, 100, sourceName});
|
||||
checkAssemblyLocations(items, locations);
|
||||
}
|
||||
|
||||
|
@ -118,9 +118,8 @@ TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, b
|
||||
|
||||
if (!compiler().parseAndAnalyze() || !compiler().compile())
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, _formatted, false);
|
||||
for (auto const& error: compiler().errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
SourceReferenceFormatter{_stream, compiler(), _formatted, false}
|
||||
.printErrorInformation(compiler().errors());
|
||||
return TestResult::FatalError;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ std::optional<Error> parseAndReturnFirstError(
|
||||
{
|
||||
string errors;
|
||||
for (auto const& err: stack.errors())
|
||||
errors += SourceReferenceFormatter::formatErrorInformation(*err);
|
||||
errors += SourceReferenceFormatter::formatErrorInformation(*err, stack);
|
||||
BOOST_FAIL("Found more than one error:\n" + errors);
|
||||
}
|
||||
error = e;
|
||||
|
@ -65,10 +65,8 @@ bytes SolidityExecutionFramework::multiSourceCompileContract(
|
||||
for (auto const& error: m_compiler.errors())
|
||||
if (error->type() == langutil::Error::Type::CodeGenerationError)
|
||||
BOOST_THROW_EXCEPTION(*error);
|
||||
langutil::SourceReferenceFormatter formatter(std::cerr, true, false);
|
||||
|
||||
for (auto const& error: m_compiler.errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
langutil::SourceReferenceFormatter{std::cerr, m_compiler, true, false}
|
||||
.printErrorInformation(m_compiler.errors());
|
||||
BOOST_ERROR("Compiling contract failed");
|
||||
}
|
||||
string contractName(_contractName.empty() ? m_compiler.lastContractName(_mainSourceName) : _contractName);
|
||||
|
@ -591,19 +591,21 @@ BOOST_AUTO_TEST_CASE(inline_asm_end_location)
|
||||
class CheckInlineAsmLocation: public ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
explicit CheckInlineAsmLocation(string _sourceCode): m_sourceCode(_sourceCode) {}
|
||||
bool visited = false;
|
||||
bool visit(InlineAssembly const& _inlineAsm) override
|
||||
{
|
||||
auto loc = _inlineAsm.location();
|
||||
auto asmStr = loc.source->source().substr(static_cast<size_t>(loc.start), static_cast<size_t>(loc.end - loc.start));
|
||||
auto asmStr = m_sourceCode.substr(static_cast<size_t>(loc.start), static_cast<size_t>(loc.end - loc.start));
|
||||
BOOST_CHECK_EQUAL(asmStr, "assembly { a := 0x12345678 }");
|
||||
visited = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
string m_sourceCode;
|
||||
};
|
||||
|
||||
CheckInlineAsmLocation visitor;
|
||||
CheckInlineAsmLocation visitor{sourceCode};
|
||||
contract->accept(visitor);
|
||||
|
||||
BOOST_CHECK_MESSAGE(visitor.visited, "No inline asm block found?!");
|
||||
|
@ -17,6 +17,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
#include <test/libsolidity/SyntaxTest.h>
|
||||
|
||||
#include <test/Common.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
@ -119,11 +120,13 @@ void SyntaxTest::filterObtainedErrors()
|
||||
string sourceName;
|
||||
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
||||
{
|
||||
solAssert(location->source, "");
|
||||
sourceName = location->source->name();
|
||||
|
||||
solAssert(location->sourceName, "");
|
||||
sourceName = *location->sourceName;
|
||||
solAssert(m_sources.sources.count(sourceName) == 1, "");
|
||||
int preambleSize = static_cast<int>(location->source->source().size()) - static_cast<int>(m_sources.sources[sourceName].size());
|
||||
|
||||
int preambleSize =
|
||||
static_cast<int>(compiler().charStream(sourceName).size()) -
|
||||
static_cast<int>(m_sources.sources[sourceName].size());
|
||||
solAssert(preambleSize >= 0, "");
|
||||
|
||||
// ignore the version & license pragma inserted by the testing tool when calculating locations.
|
||||
|
@ -53,15 +53,6 @@ Dialect const& defaultDialect(bool _yul)
|
||||
}
|
||||
}
|
||||
|
||||
void yul::test::printErrors(ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(cout, true, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
||||
|
||||
pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(string const& _source, bool _yul)
|
||||
{
|
||||
AssemblyStack stack(
|
||||
|
@ -44,8 +44,6 @@ struct Dialect;
|
||||
namespace solidity::yul::test
|
||||
{
|
||||
|
||||
void printErrors(langutil::ErrorList const& _errors);
|
||||
|
||||
std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>>
|
||||
parse(std::string const& _source, bool _yul = true);
|
||||
|
||||
|
@ -51,9 +51,8 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _
|
||||
if (!stack.parseAndAnalyze("", m_source))
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
SourceReferenceFormatter formatter(_stream, true, false);
|
||||
for (auto const& error: stack.errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
SourceReferenceFormatter{_stream, stack, true, false}
|
||||
.printErrorInformation(stack.errors());
|
||||
return TestResult::FatalError;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,8 @@ TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _
|
||||
return TestResult::FatalError;
|
||||
|
||||
*m_object = EVMToEwasmTranslator(
|
||||
EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion())
|
||||
EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()),
|
||||
m_stack
|
||||
).run(*m_object);
|
||||
|
||||
// Add call to "main()".
|
||||
@ -78,20 +79,21 @@ TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _
|
||||
|
||||
bool EwasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||
{
|
||||
AssemblyStack stack(
|
||||
m_stack = AssemblyStack(
|
||||
solidity::test::CommonOptions::get().evmVersion(),
|
||||
AssemblyStack::Language::StrictAssembly,
|
||||
solidity::frontend::OptimiserSettings::none()
|
||||
);
|
||||
if (stack.parseAndAnalyze("", m_source))
|
||||
if (m_stack.parseAndAnalyze("", m_source))
|
||||
{
|
||||
m_object = stack.parserResult();
|
||||
m_object = m_stack.parserResult();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
printErrors(_stream, stack.errors());
|
||||
SourceReferenceFormatter{_stream, m_stack, true, false}
|
||||
.printErrorInformation(m_stack.errors());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -114,11 +116,3 @@ string EwasmTranslationTest::interpret()
|
||||
state.dumpTraceAndState(result);
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void EwasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, true, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
@ -20,16 +20,12 @@
|
||||
|
||||
#include <test/TestCase.h>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
class Scanner;
|
||||
class Error;
|
||||
using ErrorList = std::vector<std::shared_ptr<Error const>>;
|
||||
}
|
||||
#include <libyul/AssemblyStack.h>
|
||||
|
||||
namespace solidity::yul
|
||||
{
|
||||
struct Object;
|
||||
class AssemblyStack;
|
||||
}
|
||||
|
||||
namespace solidity::yul::test
|
||||
@ -51,9 +47,8 @@ private:
|
||||
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
|
||||
std::string interpret();
|
||||
|
||||
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
|
||||
|
||||
std::shared_ptr<Object> m_object;
|
||||
AssemblyStack m_stack;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -69,7 +69,8 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li
|
||||
if (!stack.parseAndAnalyze("source", m_source))
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
printErrors(_stream, stack.errors());
|
||||
SourceReferenceFormatter{_stream, stack, true, false}
|
||||
.printErrorInformation(stack.errors());
|
||||
return TestResult::FatalError;
|
||||
}
|
||||
stack.optimize();
|
||||
@ -104,11 +105,3 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li
|
||||
|
||||
return checkResult(_stream, _linePrefix, _formatted);
|
||||
}
|
||||
|
||||
void ObjectCompilerTest::printErrors(ostream& _stream, ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, true, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
@ -54,8 +54,6 @@ private:
|
||||
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
|
||||
void disambiguate();
|
||||
|
||||
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
|
||||
|
||||
frontend::OptimisationPreset m_optimisationPreset;
|
||||
bool m_wasm = false;
|
||||
};
|
||||
|
@ -51,24 +51,19 @@ namespace solidity::yul::test
|
||||
namespace
|
||||
{
|
||||
|
||||
string_view constexpr g_strAlternateSourceText = "{}";
|
||||
|
||||
shared_ptr<Block> parse(string const& _source, Dialect const& _dialect, ErrorReporter& errorReporter)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto scanner = make_shared<Scanner>(CharStream(_source, ""));
|
||||
map<unsigned, shared_ptr<CharStream>> indicesToCharStreams;
|
||||
indicesToCharStreams[0] = scanner->charStream();
|
||||
indicesToCharStreams[1] = make_shared<CharStream>(
|
||||
string(g_strAlternateSourceText.data(), g_strAlternateSourceText.size()),
|
||||
"alternate.sol"
|
||||
);
|
||||
map<unsigned, shared_ptr<string const>> indicesToSourceNames;
|
||||
indicesToSourceNames[0] = make_shared<string const>("source0");
|
||||
indicesToSourceNames[1] = make_shared<string const>("source1");
|
||||
|
||||
auto parserResult = yul::Parser(
|
||||
errorReporter,
|
||||
_dialect,
|
||||
move(indicesToCharStreams)
|
||||
move(indicesToSourceNames)
|
||||
).parse(scanner, false);
|
||||
if (parserResult)
|
||||
{
|
||||
@ -200,9 +195,9 @@ BOOST_AUTO_TEST_CASE(default_types_set)
|
||||
);
|
||||
}
|
||||
|
||||
#define CHECK_LOCATION(_actual, _sourceText, _start, _end) \
|
||||
#define CHECK_LOCATION(_actual, _sourceName, _start, _end) \
|
||||
do { \
|
||||
BOOST_CHECK_EQUAL((_sourceText), ((_actual).source ? (_actual).source->source() : "")); \
|
||||
BOOST_CHECK_EQUAL((_sourceName), ((_actual).sourceName ? *(_actual).sourceName : "")); \
|
||||
BOOST_CHECK_EQUAL((_start), (_actual).start); \
|
||||
BOOST_CHECK_EQUAL((_end), (_actual).end); \
|
||||
} while (0)
|
||||
@ -217,7 +212,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_empty_block)
|
||||
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 234, 543);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 234, 543);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_block_with_children)
|
||||
@ -235,12 +230,12 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_with_children)
|
||||
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 234, 543);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 234, 543);
|
||||
BOOST_REQUIRE_EQUAL(3, result->statements.size());
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), sourceText, 234, 543);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 234, 543);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 123, 432);
|
||||
// [2] is inherited source location
|
||||
CHECK_LOCATION(locationOf(result->statements.at(2)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(2)), "source0", 123, 432);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_block_different_sources)
|
||||
@ -258,12 +253,12 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_different_sources)
|
||||
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 234, 543);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 234, 543);
|
||||
BOOST_REQUIRE_EQUAL(3, result->statements.size());
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), sourceText, 234, 543);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), g_strAlternateSourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 234, 543);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), "source1", 123, 432);
|
||||
// [2] is inherited source location
|
||||
CHECK_LOCATION(locationOf(result->statements.at(2)), g_strAlternateSourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(2)), "source1", 123, 432);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_block_nested)
|
||||
@ -280,9 +275,9 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_nested)
|
||||
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 234, 543);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 234, 543);
|
||||
BOOST_REQUIRE_EQUAL(2, result->statements.size());
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), sourceText, 343, 434);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 343, 434);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_block_switch_case)
|
||||
@ -304,19 +299,19 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_switch_case)
|
||||
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 234, 543);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 234, 543);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(2, result->statements.size());
|
||||
BOOST_REQUIRE(holds_alternative<Switch>(result->statements.at(1)));
|
||||
auto const& switchStmt = get<Switch>(result->statements.at(1));
|
||||
|
||||
CHECK_LOCATION(switchStmt.debugData->location, sourceText, 343, 434);
|
||||
CHECK_LOCATION(switchStmt.debugData->location, "source0", 343, 434);
|
||||
BOOST_REQUIRE_EQUAL(1, switchStmt.cases.size());
|
||||
CHECK_LOCATION(switchStmt.cases.at(0).debugData->location, sourceText, 3141, 59265);
|
||||
CHECK_LOCATION(switchStmt.cases.at(0).debugData->location, "source0", 3141, 59265);
|
||||
|
||||
auto const& caseBody = switchStmt.cases.at(0).body;
|
||||
BOOST_REQUIRE_EQUAL(1, caseBody.statements.size());
|
||||
CHECK_LOCATION(locationOf(caseBody.statements.at(0)), sourceText, 271, 828);
|
||||
CHECK_LOCATION(locationOf(caseBody.statements.at(0)), "source0", 271, 828);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_inherit_into_outer_scope)
|
||||
@ -337,19 +332,19 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_inherit_into_outer_scope)
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 1, 100);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 1, 100);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(3, result->statements.size());
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), sourceText, 1, 100);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 1, 100);
|
||||
|
||||
// First child element must be a block itself with one statement.
|
||||
BOOST_REQUIRE(holds_alternative<Block>(result->statements.at(0)));
|
||||
BOOST_REQUIRE_EQUAL(get<Block>(result->statements.at(0)).statements.size(), 1);
|
||||
CHECK_LOCATION(locationOf(get<Block>(result->statements.at(0)).statements.at(0)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(get<Block>(result->statements.at(0)).statements.at(0)), "source0", 123, 432);
|
||||
|
||||
// The next two elements have an inherited source location from the prior inner scope.
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(2)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(2)), "source0", 123, 432);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_assign_empty)
|
||||
@ -368,8 +363,8 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_assign_empty)
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result); // should still parse
|
||||
BOOST_REQUIRE_EQUAL(2, result->statements.size());
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), g_strAlternateSourceText, 1, 10);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(1)), "source1", 1, 10);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_source_index)
|
||||
@ -407,10 +402,10 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_1)
|
||||
BOOST_REQUIRE(!!result);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(1, result->statements.size());
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), sourceText, 123, 432);
|
||||
CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 123, 432);
|
||||
BOOST_REQUIRE(holds_alternative<VariableDeclaration>(result->statements.at(0)));
|
||||
VariableDeclaration const& varDecl = get<VariableDeclaration>(result->statements.at(0));
|
||||
CHECK_LOCATION(locationOf(*varDecl.value), sourceText, 234, 2026);
|
||||
CHECK_LOCATION(locationOf(*varDecl.value), "source0", 234, 2026);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_2)
|
||||
@ -429,20 +424,20 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_2)
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
BOOST_REQUIRE_EQUAL(1, result->statements.size());
|
||||
CHECK_LOCATION(result->debugData->location, sourceText, 0, 5);
|
||||
CHECK_LOCATION(result->debugData->location, "source0", 0, 5);
|
||||
|
||||
// `let x := add(1, `
|
||||
BOOST_REQUIRE(holds_alternative<VariableDeclaration>(result->statements.at(0)));
|
||||
VariableDeclaration const& varDecl = get<VariableDeclaration>(result->statements.at(0));
|
||||
CHECK_LOCATION(varDecl.debugData->location, sourceText, 0, 5);
|
||||
CHECK_LOCATION(varDecl.debugData->location, "source0", 0, 5);
|
||||
BOOST_REQUIRE(!!varDecl.value);
|
||||
BOOST_REQUIRE(holds_alternative<FunctionCall>(*varDecl.value));
|
||||
FunctionCall const& call = get<FunctionCall>(*varDecl.value);
|
||||
CHECK_LOCATION(call.debugData->location, g_strAlternateSourceText, 2, 3);
|
||||
CHECK_LOCATION(call.debugData->location, "source1", 2, 3);
|
||||
|
||||
// `2`
|
||||
BOOST_REQUIRE_EQUAL(2, call.arguments.size());
|
||||
CHECK_LOCATION(locationOf(call.arguments.at(1)), sourceText, 4, 8);
|
||||
CHECK_LOCATION(locationOf(call.arguments.at(1)), "source0", 4, 8);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_3)
|
||||
@ -463,24 +458,24 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_3)
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
BOOST_REQUIRE_EQUAL(2, result->statements.size());
|
||||
CHECK_LOCATION(result->debugData->location, g_strAlternateSourceText, 23, 45);
|
||||
CHECK_LOCATION(result->debugData->location, "source1", 23, 45);
|
||||
|
||||
BOOST_REQUIRE(holds_alternative<Block>(result->statements.at(0)));
|
||||
Block const& innerBlock = get<Block>(result->statements.at(0));
|
||||
CHECK_LOCATION(innerBlock.debugData->location, g_strAlternateSourceText, 23, 45);
|
||||
CHECK_LOCATION(innerBlock.debugData->location, "source1", 23, 45);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(1, innerBlock.statements.size());
|
||||
BOOST_REQUIRE(holds_alternative<ExpressionStatement>(result->statements.at(1)));
|
||||
ExpressionStatement const& sstoreStmt = get<ExpressionStatement>(innerBlock.statements.at(0));
|
||||
BOOST_REQUIRE(holds_alternative<FunctionCall>(sstoreStmt.expression));
|
||||
FunctionCall const& sstoreCall = get<FunctionCall>(sstoreStmt.expression);
|
||||
CHECK_LOCATION(sstoreCall.debugData->location, g_strAlternateSourceText, 23, 45);
|
||||
CHECK_LOCATION(sstoreCall.debugData->location, "source1", 23, 45);
|
||||
|
||||
BOOST_REQUIRE(holds_alternative<ExpressionStatement>(result->statements.at(1)));
|
||||
ExpressionStatement mstoreStmt = get<ExpressionStatement>(result->statements.at(1));
|
||||
BOOST_REQUIRE(holds_alternative<FunctionCall>(mstoreStmt.expression));
|
||||
FunctionCall const& mstoreCall = get<FunctionCall>(mstoreStmt.expression);
|
||||
CHECK_LOCATION(mstoreCall.debugData->location, sourceText, 420, 680);
|
||||
CHECK_LOCATION(mstoreCall.debugData->location, "source0", 420, 680);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_comments_after_valid)
|
||||
@ -499,11 +494,11 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_comments_after_valid)
|
||||
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
|
||||
BOOST_REQUIRE(!!result);
|
||||
BOOST_REQUIRE_EQUAL(1, result->statements.size());
|
||||
CHECK_LOCATION(result->debugData->location, g_strAlternateSourceText, 23, 45);
|
||||
CHECK_LOCATION(result->debugData->location, "source1", 23, 45);
|
||||
|
||||
BOOST_REQUIRE(holds_alternative<VariableDeclaration>(result->statements.at(0)));
|
||||
VariableDeclaration const& varDecl = get<VariableDeclaration>(result->statements.at(0));
|
||||
CHECK_LOCATION(varDecl.debugData->location, sourceText, 420, 680);
|
||||
CHECK_LOCATION(varDecl.debugData->location, "source0", 420, 680);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_suffix)
|
||||
@ -553,7 +548,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_ensure_last_match)
|
||||
VariableDeclaration const& varDecl = get<VariableDeclaration>(result->statements.at(0));
|
||||
|
||||
// Ensure the latest @src per documentation-comment is used (0:30:40).
|
||||
CHECK_LOCATION(varDecl.debugData->location, sourceText, 30, 40);
|
||||
CHECK_LOCATION(varDecl.debugData->location, "source0", 30, 40);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc)
|
||||
@ -573,6 +568,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc)
|
||||
BOOST_REQUIRE(holds_alternative<VariableDeclaration>(result->statements.at(0)));
|
||||
VariableDeclaration const& varDecl = get<VariableDeclaration>(result->statements.at(0));
|
||||
|
||||
// -1 points to original source code, which in this case is `"source0"` (which is also
|
||||
CHECK_LOCATION(varDecl.debugData->location, "", 10, 20);
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,8 @@ bool YulInterpreterTest::parse(ostream& _stream, string const& _linePrefix, bool
|
||||
else
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
printErrors(_stream, stack.errors());
|
||||
SourceReferenceFormatter{_stream, stack, true, false}
|
||||
.printErrorInformation(stack.errors());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -101,11 +102,3 @@ string YulInterpreterTest::interpret()
|
||||
state.dumpTraceAndState(result);
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void YulInterpreterTest::printErrors(ostream& _stream, ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, true, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
@ -20,13 +20,6 @@
|
||||
|
||||
#include <test/TestCase.h>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
class Scanner;
|
||||
class Error;
|
||||
using ErrorList = std::vector<std::shared_ptr<Error const>>;
|
||||
}
|
||||
|
||||
namespace solidity::yul
|
||||
{
|
||||
struct AsmAnalysisInfo;
|
||||
@ -52,8 +45,6 @@ private:
|
||||
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
|
||||
std::string interpret();
|
||||
|
||||
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
|
||||
|
||||
std::shared_ptr<Block> m_ast;
|
||||
std::shared_ptr<AsmAnalysisInfo> m_analysisInfo;
|
||||
};
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <libyul/AsmPrinter.h>
|
||||
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
@ -115,16 +116,10 @@ std::pair<std::shared_ptr<Object>, std::shared_ptr<AsmAnalysisInfo>> YulOptimize
|
||||
if (!object || !analysisInfo || !Error::containsOnlyWarnings(errors))
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
printErrors(_stream, errors);
|
||||
CharStream charStream(_source, "");
|
||||
SourceReferenceFormatter{_stream, SingletonCharStreamProvider(charStream), true, false}
|
||||
.printErrorInformation(errors);
|
||||
return {};
|
||||
}
|
||||
return {std::move(object), std::move(analysisInfo)};
|
||||
}
|
||||
|
||||
void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, true, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ private:
|
||||
std::pair<std::shared_ptr<Object>, std::shared_ptr<AsmAnalysisInfo>> parse(
|
||||
std::ostream& _stream, std::string const& _linePrefix, bool const _formatted, std::string const& _source
|
||||
);
|
||||
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
|
||||
|
||||
std::string m_optimizerStep;
|
||||
|
||||
|
@ -41,13 +41,11 @@ optional<CompilerOutput> SolidityCompilationFramework::compileContract()
|
||||
{
|
||||
if (m_compilerInput.debugFailure)
|
||||
{
|
||||
SourceReferenceFormatter formatter(cerr, false, false);
|
||||
|
||||
cerr << "Compiling contract failed" << endl;
|
||||
for (auto const& error: m_compiler.errors())
|
||||
formatter.printExceptionInformation(
|
||||
cerr << SourceReferenceFormatter::formatErrorInformation(
|
||||
*error,
|
||||
formatter.formatErrorInformation(*error)
|
||||
m_compiler
|
||||
);
|
||||
}
|
||||
return {};
|
||||
|
@ -43,20 +43,6 @@ using namespace solidity::yul;
|
||||
using namespace solidity::yul::test;
|
||||
using namespace solidity::yul::test::yul_fuzzer;
|
||||
|
||||
namespace
|
||||
{
|
||||
void printErrors(ostream& _stream, ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(_stream, false, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printExceptionInformation(
|
||||
*error,
|
||||
(error->type() == Error::Type::Warning) ? "Warning" : "Error"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||
{
|
||||
ProtoConverter converter;
|
||||
@ -88,7 +74,13 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
||||
!Error::containsOnlyWarnings(stack.errors())
|
||||
)
|
||||
{
|
||||
printErrors(std::cout, stack.errors());
|
||||
SourceReferenceFormatter formatter(std::cout, stack, false, false);
|
||||
|
||||
for (auto const& error: stack.errors())
|
||||
formatter.printExceptionInformation(
|
||||
*error,
|
||||
(error->type() == Error::Type::Warning) ? "Warning" : "Error"
|
||||
);
|
||||
yulAssert(false, "Proto fuzzer generated malformed program");
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,8 @@
|
||||
#include <libsolutil/JSON.h>
|
||||
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
@ -78,17 +80,19 @@ class YulOpti
|
||||
public:
|
||||
void printErrors()
|
||||
{
|
||||
SourceReferenceFormatter formatter(cerr, true, false);
|
||||
|
||||
for (auto const& error: m_errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
SourceReferenceFormatter{
|
||||
cerr,
|
||||
SingletonCharStreamProvider(*m_scanner->charStream()),
|
||||
true,
|
||||
false
|
||||
}.printErrorInformation(m_errors);
|
||||
}
|
||||
|
||||
bool parse(string const& _input)
|
||||
{
|
||||
ErrorReporter errorReporter(m_errors);
|
||||
shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(_input, ""));
|
||||
m_ast = yul::Parser(errorReporter, m_dialect).parse(scanner, false);
|
||||
m_scanner = make_shared<Scanner>(CharStream(_input, ""));
|
||||
m_ast = yul::Parser(errorReporter, m_dialect).parse(m_scanner, false);
|
||||
if (!m_ast || !errorReporter.errors().empty())
|
||||
{
|
||||
cerr << "Error parsing source." << endl;
|
||||
@ -230,6 +234,7 @@ public:
|
||||
|
||||
private:
|
||||
ErrorList m_errors;
|
||||
shared_ptr<Scanner> m_scanner;
|
||||
shared_ptr<yul::Block> m_ast;
|
||||
Dialect const& m_dialect{EVMDialect::strictAssemblyForEVMObjects(EVMVersion{})};
|
||||
shared_ptr<AsmAnalysisInfo> m_analysisInfo;
|
||||
|
@ -53,12 +53,6 @@ namespace po = boost::program_options;
|
||||
namespace
|
||||
{
|
||||
|
||||
void printErrors(ErrorList const& _errors)
|
||||
{
|
||||
for (auto const& error: _errors)
|
||||
SourceReferenceFormatter(cout, true, false).printErrorInformation(*error);
|
||||
}
|
||||
|
||||
pair<shared_ptr<Block>, shared_ptr<AsmAnalysisInfo>> parse(string const& _source)
|
||||
{
|
||||
AssemblyStack stack(
|
||||
@ -73,7 +67,7 @@ pair<shared_ptr<Block>, shared_ptr<AsmAnalysisInfo>> parse(string const& _source
|
||||
}
|
||||
else
|
||||
{
|
||||
printErrors(stack.errors());
|
||||
SourceReferenceFormatter(cout, stack, true, false).printErrorInformation(stack.errors());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
|
||||
@ -47,42 +50,57 @@ public:
|
||||
operator std::string() { return m_stream.str(); }
|
||||
};
|
||||
|
||||
class SourceTextRetriever
|
||||
{
|
||||
public:
|
||||
explicit SourceTextRetriever(langutil::CharStreamProvider const& _charStreamProvider):
|
||||
m_charStreamProvider(_charStreamProvider) {}
|
||||
std::string text(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
solAssert(_location.hasText(), "");
|
||||
return std::string{m_charStreamProvider.charStream(*_location.sourceName).text(_location)};
|
||||
}
|
||||
protected:
|
||||
langutil::CharStreamProvider const& m_charStreamProvider;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper that provides functions which analyze certain source locations
|
||||
* on a textual base. They utilize regular expression to search for
|
||||
* keywords or to determine formatting.
|
||||
*/
|
||||
class SourceAnalysis
|
||||
class SourceAnalysis: public SourceTextRetriever
|
||||
{
|
||||
public:
|
||||
static bool isMultilineKeyword(
|
||||
using SourceTextRetriever::SourceTextRetriever;
|
||||
|
||||
bool isMultilineKeyword(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _keyword
|
||||
)
|
||||
) const
|
||||
{
|
||||
return regex_search(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
std::regex{"(\\b" + _keyword + "\\b\\n|\\r|\\r\\n)"}
|
||||
);
|
||||
}
|
||||
|
||||
static bool hasMutabilityKeyword(langutil::SourceLocation const& _location)
|
||||
bool hasMutabilityKeyword(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
return regex_search(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
std::regex{"(\\b(pure|view|nonpayable|payable)\\b)"}
|
||||
);
|
||||
}
|
||||
|
||||
static bool hasVirtualKeyword(langutil::SourceLocation const& _location)
|
||||
bool hasVirtualKeyword(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
return regex_search(_location.text(), std::regex{"(\\b(virtual)\\b)"});
|
||||
return regex_search(text(_location), std::regex{"(\\b(virtual)\\b)"});
|
||||
}
|
||||
|
||||
static bool hasVisibilityKeyword(langutil::SourceLocation const& _location)
|
||||
bool hasVisibilityKeyword(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
return regex_search(_location.text(), std::regex{"\\bpublic\\b"});
|
||||
return regex_search(text(_location), std::regex{"\\bpublic\\b"});
|
||||
}
|
||||
};
|
||||
|
||||
@ -117,21 +135,23 @@ public:
|
||||
* on a textual base. In general, these utilize regular expressions applied
|
||||
* to the given source location.
|
||||
*/
|
||||
class SourceTransform
|
||||
class SourceTransform: public SourceTextRetriever
|
||||
{
|
||||
public:
|
||||
using SourceTextRetriever::SourceTextRetriever;
|
||||
|
||||
/// Searches for the keyword given and prepends the expression.
|
||||
/// E.g. `function f() view;` -> `function f() public view;`
|
||||
static std::string insertBeforeKeyword(
|
||||
std::string insertBeforeKeyword(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _keyword,
|
||||
std::string const& _expression
|
||||
)
|
||||
) const
|
||||
{
|
||||
auto _regex = std::regex{"(\\b" + _keyword + "\\b)"};
|
||||
if (regex_search(_location.text(), _regex))
|
||||
if (regex_search(text(_location), _regex))
|
||||
return regex_replace(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
_regex,
|
||||
_expression + " " + _keyword,
|
||||
std::regex_constants::format_first_only
|
||||
@ -139,7 +159,7 @@ public:
|
||||
else
|
||||
solAssert(
|
||||
false,
|
||||
LocationHelper() << "Could not fix: " << _location.text() << " at " << _location <<
|
||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
||||
"\nNeeds to be fixed manually."
|
||||
);
|
||||
|
||||
@ -148,22 +168,22 @@ public:
|
||||
|
||||
/// Searches for the keyword given and appends the expression.
|
||||
/// E.g. `function f() public {}` -> `function f() public override {}`
|
||||
static std::string insertAfterKeyword(
|
||||
std::string insertAfterKeyword(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _keyword,
|
||||
std::string const& _expression
|
||||
)
|
||||
) const
|
||||
{
|
||||
bool isMultiline = SourceAnalysis::isMultilineKeyword(_location, _keyword);
|
||||
bool isMultiline = SourceAnalysis{m_charStreamProvider}.isMultilineKeyword(_location, _keyword);
|
||||
std::string toAppend = isMultiline ? ("\n " + _expression) : (" " + _expression);
|
||||
std::regex keyword{"(\\b" + _keyword + "\\b)"};
|
||||
|
||||
if (regex_search(_location.text(), keyword))
|
||||
return regex_replace(_location.text(), keyword, _keyword + toAppend);
|
||||
if (regex_search(text(_location), keyword))
|
||||
return regex_replace(text(_location), keyword, _keyword + toAppend);
|
||||
else
|
||||
solAssert(
|
||||
false,
|
||||
LocationHelper() << "Could not fix: " << _location.text() << " at " << _location <<
|
||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
||||
"\nNeeds to be fixed manually."
|
||||
);
|
||||
|
||||
@ -174,22 +194,22 @@ public:
|
||||
/// Searches for the first right parenthesis and appends the expression
|
||||
/// given.
|
||||
/// E.g. `function f() {}` -> `function f() public {}`
|
||||
static std::string insertAfterRightParenthesis(
|
||||
std::string insertAfterRightParenthesis(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _expression
|
||||
)
|
||||
) const
|
||||
{
|
||||
auto _regex = std::regex{"(\\))"};
|
||||
if (regex_search(_location.text(), _regex))
|
||||
if (regex_search(text(_location), _regex))
|
||||
return regex_replace(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
std::regex{"(\\))"},
|
||||
") " + _expression
|
||||
);
|
||||
else
|
||||
solAssert(
|
||||
false,
|
||||
LocationHelper() << "Could not fix: " << _location.text() << " at " << _location <<
|
||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
||||
"\nNeeds to be fixed manually."
|
||||
);
|
||||
|
||||
@ -199,38 +219,38 @@ public:
|
||||
/// Searches for the `function` keyword and its identifier and replaces
|
||||
/// both by the expression given.
|
||||
/// E.g. `function Storage() {}` -> `constructor() {}`
|
||||
static std::string replaceFunctionName(
|
||||
std::string replaceFunctionName(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _name,
|
||||
std::string const& _expression
|
||||
)
|
||||
) const
|
||||
{
|
||||
auto _regex = std::regex{ "(\\bfunction\\s*" + _name + "\\b)"};
|
||||
if (regex_search(_location.text(), _regex))
|
||||
if (regex_search(text(_location), _regex))
|
||||
return regex_replace(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
_regex,
|
||||
_expression
|
||||
);
|
||||
else
|
||||
solAssert(
|
||||
false,
|
||||
LocationHelper() << "Could not fix: " << _location.text() << " at " << _location <<
|
||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
||||
"\nNeeds to be fixed manually."
|
||||
);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string gasUpdate(langutil::SourceLocation const& _location)
|
||||
std::string gasUpdate(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
// dot, "gas", any number of whitespaces, left bracket
|
||||
std::regex gasReg{"\\.gas\\s*\\("};
|
||||
|
||||
if (regex_search(_location.text(), gasReg))
|
||||
if (regex_search(text(_location), gasReg))
|
||||
{
|
||||
std::string out = regex_replace(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
gasReg,
|
||||
"{gas: ",
|
||||
std::regex_constants::format_first_only
|
||||
@ -240,22 +260,22 @@ public:
|
||||
else
|
||||
solAssert(
|
||||
false,
|
||||
LocationHelper() << "Could not fix: " << _location.text() << " at " << _location <<
|
||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
||||
"\nNeeds to be fixed manually."
|
||||
);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string valueUpdate(langutil::SourceLocation const& _location)
|
||||
std::string valueUpdate(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
// dot, "value", any number of whitespaces, left bracket
|
||||
std::regex valueReg{"\\.value\\s*\\("};
|
||||
|
||||
if (regex_search(_location.text(), valueReg))
|
||||
if (regex_search(text(_location), valueReg))
|
||||
{
|
||||
std::string out = regex_replace(
|
||||
_location.text(),
|
||||
text(_location),
|
||||
valueReg,
|
||||
"{value: ",
|
||||
std::regex_constants::format_first_only
|
||||
@ -265,21 +285,21 @@ public:
|
||||
else
|
||||
solAssert(
|
||||
false,
|
||||
LocationHelper() << "Could not fix: " << _location.text() << " at " << _location <<
|
||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
||||
"\nNeeds to be fixed manually."
|
||||
);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string nowUpdate(langutil::SourceLocation const& _location)
|
||||
std::string nowUpdate(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
return regex_replace(_location.text(), std::regex{"now"}, "block.timestamp");
|
||||
return regex_replace(text(_location), std::regex{"now"}, "block.timestamp");
|
||||
}
|
||||
|
||||
static std::string removeVisibility(langutil::SourceLocation const& _location)
|
||||
std::string removeVisibility(langutil::SourceLocation const& _location) const
|
||||
{
|
||||
std::string replacement = _location.text();
|
||||
std::string replacement = text(_location);
|
||||
for (auto const& replace: {"public ", "public", "internal ", "internal", "external ", "external"})
|
||||
replacement = regex_replace(replacement, std::regex{replace}, "");
|
||||
return replacement;
|
||||
|
@ -347,14 +347,14 @@ bool SourceUpgrade::analyzeAndUpgrade(pair<string, string> const& _sourceCode)
|
||||
log() << "Analyzing and upgrading " << _sourceCode.first << "." << endl;
|
||||
|
||||
if (m_compiler->state() >= CompilerStack::State::AnalysisPerformed)
|
||||
m_suite.analyze(m_compiler->ast(_sourceCode.first));
|
||||
m_suite.analyze(*m_compiler, m_compiler->ast(_sourceCode.first));
|
||||
|
||||
if (!m_suite.changes().empty())
|
||||
{
|
||||
auto& change = m_suite.changes().front();
|
||||
|
||||
if (verbose)
|
||||
change.log(true);
|
||||
change.log(*m_compiler, true);
|
||||
|
||||
if (change.level() == UpgradeChange::Level::Safe)
|
||||
{
|
||||
@ -388,20 +388,19 @@ void SourceUpgrade::applyChange(
|
||||
log() << _change.patch();
|
||||
}
|
||||
|
||||
_change.apply();
|
||||
m_sourceCodes[_sourceCode.first] = _change.source();
|
||||
m_sourceCodes[_sourceCode.first] = _change.apply(_sourceCode.second);
|
||||
|
||||
if (!dryRun)
|
||||
writeInputFile(_sourceCode.first, _change.source());
|
||||
writeInputFile(_sourceCode.first, m_sourceCodes[_sourceCode.first]);
|
||||
}
|
||||
|
||||
void SourceUpgrade::printErrors() const
|
||||
{
|
||||
auto formatter = make_unique<langutil::SourceReferenceFormatter>(cout, true, false);
|
||||
langutil::SourceReferenceFormatter formatter{cout, *m_compiler, true, false};
|
||||
|
||||
for (auto const& error: m_compiler->errors())
|
||||
if (error->type() != langutil::Error::Type::Warning)
|
||||
formatter->printErrorInformation(*error);
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
||||
void SourceUpgrade::printStatistics() const
|
||||
|
@ -68,29 +68,29 @@ private:
|
||||
class Suite: public UpgradeSuite
|
||||
{
|
||||
public:
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit)
|
||||
void analyze(langutil::CharStreamProvider const& _charStreamProvider, frontend::SourceUnit const& _sourceUnit)
|
||||
{
|
||||
/// Solidity 0.5.0
|
||||
if (isActivated(Module::ConstructorKeyword))
|
||||
ConstructorKeyword{m_changes}.analyze(_sourceUnit);
|
||||
ConstructorKeyword{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::VisibilitySpecifier))
|
||||
VisibilitySpecifier{m_changes}.analyze(_sourceUnit);
|
||||
VisibilitySpecifier{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
|
||||
/// Solidity 0.6.0
|
||||
if (isActivated(Module::AbstractContract))
|
||||
AbstractContract{m_changes}.analyze(_sourceUnit);
|
||||
AbstractContract{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::OverridingFunction))
|
||||
OverridingFunction{m_changes}.analyze(_sourceUnit);
|
||||
OverridingFunction{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::VirtualFunction))
|
||||
VirtualFunction{m_changes}.analyze(_sourceUnit);
|
||||
VirtualFunction{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
|
||||
/// Solidity 0.7.0
|
||||
if (isActivated(Module::DotSyntax))
|
||||
DotSyntax{m_changes}.analyze(_sourceUnit);
|
||||
DotSyntax{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::NowKeyword))
|
||||
NowKeyword{m_changes}.analyze(_sourceUnit);
|
||||
NowKeyword{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::ConstrutorVisibility))
|
||||
ConstructorVisibility{m_changes}.analyze(_sourceUnit);
|
||||
ConstructorVisibility{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
||||
}
|
||||
|
||||
void activateModule(Module _module) { m_modules.insert(_module); }
|
||||
|
@ -36,7 +36,7 @@ void ConstructorKeyword::endVisit(ContractDefinition const& _contract)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
SourceTransform::replaceFunctionName(
|
||||
SourceTransform{m_charStreamProvider}.replaceFunctionName(
|
||||
function->location(),
|
||||
function->name(),
|
||||
"constructor"
|
||||
@ -50,6 +50,6 @@ void VisibilitySpecifier::endVisit(FunctionDefinition const& _function)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
_function.location(),
|
||||
SourceTransform::insertAfterRightParenthesis(_function.location(), "public")
|
||||
SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis(_function.location(), "public")
|
||||
);
|
||||
}
|
||||
|
@ -29,75 +29,6 @@ using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::tools;
|
||||
|
||||
using Contracts = set<ContractDefinition const*, OverrideChecker::CompareByID>;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline string appendOverride(
|
||||
FunctionDefinition const& _function,
|
||||
Contracts const& _expectedContracts
|
||||
)
|
||||
{
|
||||
auto location = _function.location();
|
||||
string upgradedCode;
|
||||
string overrideExpression = SourceGeneration::functionOverride(_expectedContracts);
|
||||
|
||||
if (SourceAnalysis::hasVirtualKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
"virtual",
|
||||
overrideExpression
|
||||
);
|
||||
else if (SourceAnalysis::hasMutabilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
stateMutabilityToString(_function.stateMutability()),
|
||||
overrideExpression
|
||||
);
|
||||
else if (SourceAnalysis::hasVisibilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
Declaration::visibilityToString(_function.visibility()),
|
||||
overrideExpression
|
||||
);
|
||||
else
|
||||
upgradedCode = SourceTransform::insertAfterRightParenthesis(
|
||||
location,
|
||||
overrideExpression
|
||||
);
|
||||
|
||||
return upgradedCode;
|
||||
}
|
||||
|
||||
inline string appendVirtual(FunctionDefinition const& _function)
|
||||
{
|
||||
auto location = _function.location();
|
||||
string upgradedCode;
|
||||
|
||||
if (SourceAnalysis::hasMutabilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
stateMutabilityToString(_function.stateMutability()),
|
||||
"virtual"
|
||||
);
|
||||
else if (SourceAnalysis::hasVisibilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
Declaration::visibilityToString(_function.visibility()),
|
||||
"virtual"
|
||||
);
|
||||
else
|
||||
upgradedCode = SourceTransform::insertAfterRightParenthesis(
|
||||
_function.location(),
|
||||
"virtual"
|
||||
);
|
||||
|
||||
return upgradedCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AbstractContract::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
bool isFullyImplemented = _contract.annotation().unimplementedDeclarations->empty();
|
||||
@ -110,7 +41,7 @@ void AbstractContract::endVisit(ContractDefinition const& _contract)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
_contract.location(),
|
||||
SourceTransform::insertBeforeKeyword(_contract.location(), "contract", "abstract")
|
||||
SourceTransform{m_charStreamProvider}.insertBeforeKeyword(_contract.location(), "contract", "abstract")
|
||||
);
|
||||
}
|
||||
|
||||
@ -159,6 +90,42 @@ void OverridingFunction::endVisit(ContractDefinition const& _contract)
|
||||
}
|
||||
}
|
||||
|
||||
string OverridingFunction::appendOverride(
|
||||
FunctionDefinition const& _function,
|
||||
Contracts const& _expectedContracts
|
||||
)
|
||||
{
|
||||
auto location = _function.location();
|
||||
string upgradedCode;
|
||||
string overrideExpression = SourceGeneration::functionOverride(_expectedContracts);
|
||||
|
||||
if (SourceAnalysis{m_charStreamProvider}.hasVirtualKeyword(location))
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
||||
location,
|
||||
"virtual",
|
||||
overrideExpression
|
||||
);
|
||||
else if (SourceAnalysis{m_charStreamProvider}.hasMutabilityKeyword(location))
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
||||
location,
|
||||
stateMutabilityToString(_function.stateMutability()),
|
||||
overrideExpression
|
||||
);
|
||||
else if (SourceAnalysis{m_charStreamProvider}.hasVisibilityKeyword(location))
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
||||
location,
|
||||
Declaration::visibilityToString(_function.visibility()),
|
||||
overrideExpression
|
||||
);
|
||||
else
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis(
|
||||
location,
|
||||
overrideExpression
|
||||
);
|
||||
|
||||
return upgradedCode;
|
||||
}
|
||||
|
||||
void VirtualFunction::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
auto const& inheritedFunctions = m_overrideChecker.inheritedFunctions(_contract);
|
||||
@ -192,12 +159,39 @@ void VirtualFunction::endVisit(ContractDefinition const& _contract)
|
||||
)
|
||||
{
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
appendVirtual(*function)
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
appendVirtual(*function)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string VirtualFunction::appendVirtual(FunctionDefinition const& _function) const
|
||||
{
|
||||
auto location = _function.location();
|
||||
string upgradedCode;
|
||||
|
||||
if (SourceAnalysis{m_charStreamProvider}.hasMutabilityKeyword(location))
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
||||
location,
|
||||
stateMutabilityToString(_function.stateMutability()),
|
||||
"virtual"
|
||||
);
|
||||
else if (SourceAnalysis{m_charStreamProvider}.hasVisibilityKeyword(location))
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
||||
location,
|
||||
Declaration::visibilityToString(_function.visibility()),
|
||||
"virtual"
|
||||
);
|
||||
else
|
||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis(
|
||||
_function.location(),
|
||||
"virtual"
|
||||
);
|
||||
|
||||
return upgradedCode;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,14 @@ public:
|
||||
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
using Contracts = std::set<frontend::ContractDefinition const*, frontend::OverrideChecker::CompareByID>;
|
||||
|
||||
void endVisit(frontend::ContractDefinition const& _contract) override;
|
||||
|
||||
std::string appendOverride(
|
||||
frontend::FunctionDefinition const& _function,
|
||||
Contracts const& _expectedContracts
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -65,6 +72,8 @@ public:
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
void endVisit(frontend::ContractDefinition const& _function) override;
|
||||
|
||||
std::string appendVirtual(frontend::FunctionDefinition const& _function) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -29,14 +29,14 @@ void DotSyntax::endVisit(FunctionCall const& _functionCall)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
_functionCall.location(),
|
||||
SourceTransform::valueUpdate(_functionCall.location())
|
||||
SourceTransform{m_charStreamProvider}.valueUpdate(_functionCall.location())
|
||||
);
|
||||
|
||||
if (funcType->gasSet())
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
_functionCall.location(),
|
||||
SourceTransform::gasUpdate(_functionCall.location())
|
||||
SourceTransform{m_charStreamProvider}.gasUpdate(_functionCall.location())
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ void NowKeyword::endVisit(Identifier const& _identifier)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
_identifier.location(),
|
||||
SourceTransform::nowUpdate(_identifier.location())
|
||||
SourceTransform{m_charStreamProvider}.nowUpdate(_identifier.location())
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ void ConstructorVisibility::endVisit(ContractDefinition const& _contract)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
_contract.location(),
|
||||
SourceTransform::insertBeforeKeyword(_contract.location(), "contract", "abstract")
|
||||
SourceTransform{m_charStreamProvider}.insertBeforeKeyword(_contract.location(), "contract", "abstract")
|
||||
);
|
||||
|
||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||
@ -80,6 +80,6 @@ void ConstructorVisibility::endVisit(ContractDefinition const& _contract)
|
||||
m_changes.emplace_back(
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
SourceTransform::removeVisibility(function->location())
|
||||
SourceTransform{m_charStreamProvider}.removeVisibility(function->location())
|
||||
);
|
||||
}
|
||||
|
@ -26,18 +26,20 @@ using namespace solidity::langutil;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::tools;
|
||||
|
||||
void UpgradeChange::apply()
|
||||
string UpgradeChange::apply(string _source) const
|
||||
{
|
||||
m_source.replace(
|
||||
_source.replace(
|
||||
static_cast<size_t>(m_location.start),
|
||||
static_cast<size_t>(m_location.end - m_location.start), m_patch
|
||||
static_cast<size_t>(m_location.end - m_location.start),
|
||||
m_patch
|
||||
);
|
||||
return _source;
|
||||
}
|
||||
|
||||
void UpgradeChange::log(bool const _shorten) const
|
||||
void UpgradeChange::log(CharStreamProvider const& _charStreamProvider, bool const _shorten) const
|
||||
{
|
||||
stringstream os;
|
||||
SourceReferenceFormatter formatter{os, true, false};
|
||||
SourceReferenceFormatter formatter{os, _charStreamProvider, true, false};
|
||||
|
||||
string start = to_string(m_location.start);
|
||||
string end = to_string(m_location.end);
|
||||
@ -48,10 +50,10 @@ void UpgradeChange::log(bool const _shorten) const
|
||||
os << endl;
|
||||
AnsiColorized(os, true, {formatting::BOLD, color}) << "Upgrade change (" << level << ")" << endl;
|
||||
os << "=======================" << endl;
|
||||
formatter.printSourceLocation(SourceReferenceExtractor::extract(&m_location));
|
||||
formatter.printSourceLocation(SourceReferenceExtractor::extract(_charStreamProvider, &m_location));
|
||||
os << endl;
|
||||
|
||||
LineColumn lineEnd = m_location.source->translatePositionToLineColumn(m_location.end);
|
||||
LineColumn lineEnd = _charStreamProvider.charStream(*m_location.sourceName).translatePositionToLineColumn(m_location.end);
|
||||
int const leftpad = static_cast<int>(log10(max(lineEnd.line, 1))) + 2;
|
||||
|
||||
stringstream output;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
@ -47,32 +48,27 @@ public:
|
||||
Level _level,
|
||||
langutil::SourceLocation _location,
|
||||
std::string _patch
|
||||
)
|
||||
:
|
||||
):
|
||||
m_location(_location),
|
||||
m_source(_location.source->source()),
|
||||
m_patch(std::move(_patch)),
|
||||
m_level(_level) {}
|
||||
m_level(_level)
|
||||
{}
|
||||
|
||||
~UpgradeChange() {}
|
||||
|
||||
langutil::SourceLocation const& location() { return m_location; }
|
||||
std::string source() const { return m_source; }
|
||||
std::string patch() { return m_patch; }
|
||||
langutil::SourceLocation const& location() const { return m_location; }
|
||||
std::string patch() const { return m_patch; }
|
||||
Level level() const { return m_level; }
|
||||
|
||||
/// Does the actual replacement of code under at current source location.
|
||||
/// The change is applied on the upgrade-specific copy of source code.
|
||||
/// The altered code is then requested by the upgrade routine later on.
|
||||
void apply();
|
||||
/// Does a pretty-print of this upgrade change. It uses a source formatter
|
||||
/// provided by the compiler in order to print affected code. Since the patch
|
||||
/// Performs the actual replacement on the provided original source code
|
||||
/// and returns the modified source code.
|
||||
std::string apply(std::string _source) const;
|
||||
/// Does a pretty-print of this upgrade change. Since the patch
|
||||
/// can contain a lot of code lines, it can be shortened, which is signaled
|
||||
/// by setting the flag.
|
||||
void log(bool const _shorten = true) const;
|
||||
void log(langutil::CharStreamProvider const& _charStreamProvider, bool const _shorten = true) const;
|
||||
private:
|
||||
langutil::SourceLocation m_location;
|
||||
std::string m_source;
|
||||
std::string m_patch;
|
||||
Level m_level;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
||||
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/CharStreamProvider.h>
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
#include <libsolidity/analysis/OverrideChecker.h>
|
||||
@ -37,13 +38,17 @@ namespace solidity::tools
|
||||
class Upgrade
|
||||
{
|
||||
public:
|
||||
Upgrade(std::vector<UpgradeChange>& _changes): m_changes(_changes) {}
|
||||
Upgrade(
|
||||
langutil::CharStreamProvider const& _charStreamProvider,
|
||||
std::vector<UpgradeChange>& _changes
|
||||
): m_changes(_changes), m_charStreamProvider(_charStreamProvider) {}
|
||||
|
||||
protected:
|
||||
/// A reference to a suite-specific set of changes.
|
||||
/// It is passed to all upgrade modules and meant to collect
|
||||
/// reported changes.
|
||||
std::vector<UpgradeChange>& m_changes;
|
||||
langutil::CharStreamProvider const& m_charStreamProvider;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -53,8 +58,11 @@ protected:
|
||||
class AnalysisUpgrade: public Upgrade, public frontend::ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
AnalysisUpgrade(std::vector<UpgradeChange>& _changes):
|
||||
Upgrade(_changes),
|
||||
AnalysisUpgrade(
|
||||
langutil::CharStreamProvider const& _charStreamProvider,
|
||||
std::vector<UpgradeChange>& _changes
|
||||
):
|
||||
Upgrade(_charStreamProvider, _changes),
|
||||
m_errorReporter(m_errors),
|
||||
m_overrideChecker(m_errorReporter)
|
||||
{}
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <tools/yulPhaser/SimulationRNG.h>
|
||||
|
||||
#include <liblangutil/CharStream.h>
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
|
||||
#include <libsolutil/Assertions.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
@ -389,7 +391,9 @@ vector<Program> ProgramFactory::build(Options const& _options)
|
||||
variant<Program, ErrorList> programOrErrors = Program::load(sourceCode);
|
||||
if (holds_alternative<ErrorList>(programOrErrors))
|
||||
{
|
||||
cerr << get<ErrorList>(programOrErrors) << endl;
|
||||
SourceReferenceFormatter{cerr, SingletonCharStreamProvider(sourceCode), true, false}
|
||||
.printErrorInformation(get<ErrorList>(programOrErrors));
|
||||
cerr << endl;
|
||||
assertThrow(false, InvalidProgram, "Failed to load program " + path);
|
||||
}
|
||||
|
||||
|
@ -60,16 +60,6 @@ ostream& operator<<(ostream& _stream, Program const& _program);
|
||||
|
||||
}
|
||||
|
||||
ostream& std::operator<<(ostream& _outputStream, ErrorList const& _errors)
|
||||
{
|
||||
SourceReferenceFormatter formatter(_outputStream, true, false);
|
||||
|
||||
for (auto const& error: _errors)
|
||||
formatter.printErrorInformation(*error);
|
||||
|
||||
return _outputStream;
|
||||
}
|
||||
|
||||
Program::Program(Program const& program):
|
||||
m_ast(make_unique<Block>(get<Block>(ASTCopier{}(*program.m_ast)))),
|
||||
m_dialect{program.m_dialect},
|
||||
|
@ -35,6 +35,7 @@ namespace solidity::langutil
|
||||
{
|
||||
|
||||
class CharStream;
|
||||
class Scanner;
|
||||
|
||||
}
|
||||
|
||||
@ -47,13 +48,6 @@ struct CodeWeights;
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
std::ostream& operator<<(std::ostream& _outputStream, solidity::langutil::ErrorList const& _errors);
|
||||
|
||||
}
|
||||
|
||||
namespace solidity::phaser
|
||||
{
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user