mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #11596 from ethereum/simplifySourceLocation
Remove CharStream from SourceLocation.
This commit is contained in:
		
						commit
						41e06eab4e
					
				| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -22,15 +22,15 @@ | ||||
| #include <boost/algorithm/string.hpp> | ||||
| 
 | ||||
| using namespace solidity; | ||||
| namespace solidity::langutil | ||||
| { | ||||
| using namespace solidity::langutil; | ||||
| using namespace std; | ||||
| 
 | ||||
| SourceLocation const parseSourceLocation(std::string const& _input, std::string const& _sourceName, size_t _maxIndex) | ||||
| SourceLocation solidity::langutil::parseSourceLocation(string const& _input, vector<shared_ptr<string const>> const& _sourceNames) | ||||
| { | ||||
| 	// Expected input: "start:length:sourceindex"
 | ||||
| 	enum SrcElem : size_t { Start, Length, Index }; | ||||
| 	enum SrcElem: size_t { Start, Length, Index }; | ||||
| 
 | ||||
| 	std::vector<std::string> pos; | ||||
| 	vector<string> pos; | ||||
| 
 | ||||
| 	boost::algorithm::split(pos, _input, boost::is_any_of(":")); | ||||
| 
 | ||||
| @ -38,19 +38,15 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string | ||||
| 	auto const sourceIndex = stoi(pos[Index]); | ||||
| 
 | ||||
| 	astAssert( | ||||
| 		sourceIndex == -1 || _maxIndex >= static_cast<size_t>(sourceIndex), | ||||
| 		sourceIndex == -1 || (0 <= sourceIndex && static_cast<size_t>(sourceIndex) < _sourceNames.size()), | ||||
| 		"'src'-field ill-formatted or src-index too high" | ||||
| 	); | ||||
| 
 | ||||
| 	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; | ||||
| 	SourceLocation result{start, end, {}}; | ||||
| 	if (sourceIndex != -1) | ||||
| 		source = std::make_shared<langutil::CharStream>("", _sourceName); | ||||
| 
 | ||||
| 	return SourceLocation{start, end, source}; | ||||
| } | ||||
| 
 | ||||
| 		result.sourceName = _sourceNames.at(static_cast<size_t>(sourceIndex)); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| @ -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,13 +103,12 @@ struct SourceLocation | ||||
| 
 | ||||
| 	int start = -1; | ||||
| 	int end = -1; | ||||
| 	std::shared_ptr<CharStream> source; | ||||
| 	std::shared_ptr<std::string const> sourceName; | ||||
| }; | ||||
| 
 | ||||
| SourceLocation const parseSourceLocation( | ||||
| SourceLocation parseSourceLocation( | ||||
| 	std::string const& _input, | ||||
| 	std::string const& _sourceName, | ||||
| 	size_t _maxIndex = std::numeric_limits<size_t>::max() | ||||
| 	std::vector<std::shared_ptr<std::string const>> const& _sourceNames | ||||
| ); | ||||
| 
 | ||||
| /// Stream output for Location (used e.g. in boost exceptions).
 | ||||
| @ -127,8 +117,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; | ||||
| } | ||||
|  | ||||
| @ -57,14 +57,12 @@ ASTPointer<T> ASTJsonImporter::nullOrCast(Json::Value const& _json) | ||||
| 
 | ||||
| map<string, ASTPointer<SourceUnit>> ASTJsonImporter::jsonToSourceUnit(map<string, Json::Value> const& _sourceList) | ||||
| { | ||||
| 	m_sourceList = _sourceList; | ||||
| 	for (auto const& src: _sourceList) | ||||
| 		m_sourceLocations.emplace_back(make_shared<string const>(src.first)); | ||||
| 	for (auto const& srcPair: m_sourceList) | ||||
| 		m_sourceNames.emplace_back(make_shared<string const>(src.first)); | ||||
| 	for (auto const& srcPair: _sourceList) | ||||
| 	{ | ||||
| 		astAssert(!srcPair.second.isNull(), ""); | ||||
| 		astAssert(member(srcPair.second,"nodeType") == "SourceUnit", "The 'nodeType' of the highest node must be 'SourceUnit'."); | ||||
| 		m_currentSourceName = srcPair.first; | ||||
| 		m_sourceUnits[srcPair.first] = createSourceUnit(srcPair.second, srcPair.first); | ||||
| 	} | ||||
| 	return m_sourceUnits; | ||||
| @ -94,14 +92,14 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n | ||||
| { | ||||
| 	astAssert(member(_node, "src").isString(), "'src' must be a string"); | ||||
| 
 | ||||
| 	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size()); | ||||
| 	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceNames); | ||||
| } | ||||
| 
 | ||||
| SourceLocation ASTJsonImporter::createNameSourceLocation(Json::Value const& _node) | ||||
| { | ||||
| 	astAssert(member(_node, "nameLocation").isString(), "'nameLocation' must be a string"); | ||||
| 
 | ||||
| 	return solidity::langutil::parseSourceLocation(_node["nameLocation"].asString(), m_currentSourceName, m_sourceLocations.size()); | ||||
| 	return solidity::langutil::parseSourceLocation(_node["nameLocation"].asString(), m_sourceNames); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| @ -616,7 +614,7 @@ ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json::Value con | ||||
| 	astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!"); | ||||
| 
 | ||||
| 	yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value()); | ||||
| 	shared_ptr<yul::Block> operations = make_shared<yul::Block>(yul::AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST"))); | ||||
| 	shared_ptr<yul::Block> operations = make_shared<yul::Block>(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST"))); | ||||
| 	return createASTNode<InlineAssembly>( | ||||
| 		_node, | ||||
| 		nullOrASTString(_node, "documentation"), | ||||
|  | ||||
| @ -152,13 +152,10 @@ private: | ||||
| 	///@}
 | ||||
| 
 | ||||
| 	// =========== member variables ===============
 | ||||
| 	/// Stores filepath as sourcenames to AST in JSON format
 | ||||
| 	std::map<std::string, Json::Value> m_sourceList; | ||||
| 	/// list of filepaths (used as sourcenames)
 | ||||
| 	std::vector<std::shared_ptr<std::string const>> m_sourceLocations; | ||||
| 	/// list of source names, order by source index
 | ||||
| 	std::vector<std::shared_ptr<std::string const>> m_sourceNames; | ||||
| 	/// filepath to AST
 | ||||
| 	std::map<std::string, ASTPointer<SourceUnit>> m_sourceUnits; | ||||
| 	std::string m_currentSourceName; | ||||
| 	/// IDs already used by the nodes
 | ||||
| 	std::set<int64_t> m_usedIDs; | ||||
| 	/// Configured EVM version
 | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -22,6 +22,9 @@ | ||||
| 
 | ||||
| #include <libsmtutil/SMTPortfolio.h> | ||||
| 
 | ||||
| #include <liblangutil/CharStream.h> | ||||
| #include <liblangutil/CharStreamProvider.h> | ||||
| 
 | ||||
| #ifdef HAVE_Z3_DLOPEN | ||||
| #include <z3_version.h> | ||||
| #endif | ||||
| @ -38,9 +41,10 @@ BMC::BMC( | ||||
| 	map<h256, string> const& _smtlib2Responses, | ||||
| 	ReadCallback::Callback const& _smtCallback, | ||||
| 	smtutil::SMTSolverChoice _enabledSolvers, | ||||
| 	ModelCheckerSettings const& _settings | ||||
| 	ModelCheckerSettings const& _settings, | ||||
| 	CharStreamProvider const& _charStreamProvider | ||||
| ): | ||||
| 	SMTEncoder(_context, _settings), | ||||
| 	SMTEncoder(_context, _settings, _charStreamProvider), | ||||
| 	m_interface(make_unique<smtutil::SMTPortfolio>(_smtlib2Responses, _smtCallback, _enabledSolvers, _settings.timeout)), | ||||
| 	m_outerErrorReporter(_errorReporter) | ||||
| { | ||||
| @ -650,7 +654,12 @@ pair<vector<smtutil::Expression>, vector<string>> BMC::modelExpressions() | ||||
| 		if (uf->annotation().type->isValueType()) | ||||
| 		{ | ||||
| 			expressionsToEvaluate.emplace_back(expr(*uf)); | ||||
| 			expressionNames.push_back(uf->location().text()); | ||||
| 			string expressionName; | ||||
| 			if (uf->location().hasText()) | ||||
| 				expressionName = m_charStreamProvider.charStream(*uf->location().sourceName).text( | ||||
| 					uf->location() | ||||
| 				); | ||||
| 			expressionNames.push_back(move(expressionName)); | ||||
| 		} | ||||
| 
 | ||||
| 	return {expressionsToEvaluate, expressionNames}; | ||||
|  | ||||
| @ -63,7 +63,8 @@ public: | ||||
| 		std::map<h256, std::string> const& _smtlib2Responses, | ||||
| 		ReadCallback::Callback const& _smtCallback, | ||||
| 		smtutil::SMTSolverChoice _enabledSolvers, | ||||
| 		ModelCheckerSettings const& _settings | ||||
| 		ModelCheckerSettings const& _settings, | ||||
| 		langutil::CharStreamProvider const& _charStreamProvider | ||||
| 	); | ||||
| 
 | ||||
| 	void analyze(SourceUnit const& _sources, std::map<ASTNode const*, std::set<VerificationTargetType>> _solvedTargets); | ||||
|  | ||||
| @ -57,9 +57,10 @@ CHC::CHC( | ||||
| 	[[maybe_unused]] map<util::h256, string> const& _smtlib2Responses, | ||||
| 	[[maybe_unused]] ReadCallback::Callback const& _smtCallback, | ||||
| 	SMTSolverChoice _enabledSolvers, | ||||
| 	ModelCheckerSettings const& _settings | ||||
| 	ModelCheckerSettings const& _settings, | ||||
| 	CharStreamProvider const& _charStreamProvider | ||||
| ): | ||||
| 	SMTEncoder(_context, _settings), | ||||
| 	SMTEncoder(_context, _settings, _charStreamProvider), | ||||
| 	m_outerErrorReporter(_errorReporter), | ||||
| 	m_enabledSolvers(_enabledSolvers) | ||||
| { | ||||
| @ -1741,7 +1742,7 @@ optional<string> CHC::generateCounterexample(CHCSolverInterface::CexGraph const& | ||||
| 				path.emplace_back("State: " + modelMsg); | ||||
| 		} | ||||
| 
 | ||||
| 		string txCex = summaryPredicate->formatSummaryCall(summaryArgs); | ||||
| 		string txCex = summaryPredicate->formatSummaryCall(summaryArgs, m_charStreamProvider); | ||||
| 
 | ||||
| 		list<string> calls; | ||||
| 		auto dfs = [&](unsigned parent, unsigned node, unsigned depth, auto&& _dfs) -> void { | ||||
| @ -1753,7 +1754,7 @@ optional<string> CHC::generateCounterexample(CHCSolverInterface::CexGraph const& | ||||
| 			if (!pred->isConstructorSummary()) | ||||
| 				for (unsigned v: callGraph[node]) | ||||
| 					_dfs(node, v, depth + 1, _dfs); | ||||
| 			calls.push_front(string(depth * 4, ' ') + pred->formatSummaryCall(nodeArgs(node))); | ||||
| 			calls.push_front(string(depth * 4, ' ') + pred->formatSummaryCall(nodeArgs(node), m_charStreamProvider)); | ||||
| 			if (pred->isInternalCall()) | ||||
| 				calls.front() += " -- internal call"; | ||||
| 			else if (pred->isExternalCallTrusted()) | ||||
|  | ||||
| @ -57,7 +57,8 @@ public: | ||||
| 		std::map<util::h256, std::string> const& _smtlib2Responses, | ||||
| 		ReadCallback::Callback const& _smtCallback, | ||||
| 		smtutil::SMTSolverChoice _enabledSolvers, | ||||
| 		ModelCheckerSettings const& _settings | ||||
| 		ModelCheckerSettings const& _settings, | ||||
| 		langutil::CharStreamProvider const& _charStreamProvider | ||||
| 	); | ||||
| 
 | ||||
| 	void analyze(SourceUnit const& _sources); | ||||
|  | ||||
| @ -32,6 +32,7 @@ using namespace solidity::frontend; | ||||
| 
 | ||||
| ModelChecker::ModelChecker( | ||||
| 	ErrorReporter& _errorReporter, | ||||
| 	langutil::CharStreamProvider const& _charStreamProvider, | ||||
| 	map<h256, string> const& _smtlib2Responses, | ||||
| 	ModelCheckerSettings _settings, | ||||
| 	ReadCallback::Callback const& _smtCallback, | ||||
| @ -40,8 +41,8 @@ ModelChecker::ModelChecker( | ||||
| 	m_errorReporter(_errorReporter), | ||||
| 	m_settings(_settings), | ||||
| 	m_context(), | ||||
| 	m_bmc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers, m_settings), | ||||
| 	m_chc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers, m_settings) | ||||
| 	m_bmc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers, m_settings, _charStreamProvider), | ||||
| 	m_chc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers, m_settings, _charStreamProvider) | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -49,6 +49,7 @@ public: | ||||
| 	/// should be used, even if all are available. The default choice is to use all.
 | ||||
| 	ModelChecker( | ||||
| 		langutil::ErrorReporter& _errorReporter, | ||||
| 		langutil::CharStreamProvider const& _charStreamProvider, | ||||
| 		std::map<solidity::util::h256, std::string> const& _smtlib2Responses, | ||||
| 		ModelCheckerSettings _settings = ModelCheckerSettings{}, | ||||
| 		ReadCallback::Callback const& _smtCallback = ReadCallback::Callback(), | ||||
|  | ||||
| @ -20,6 +20,8 @@ | ||||
| 
 | ||||
| #include <libsolidity/formal/SMTEncoder.h> | ||||
| 
 | ||||
| #include <liblangutil/CharStreamProvider.h> | ||||
| #include <liblangutil/CharStream.h> | ||||
| #include <libsolidity/ast/AST.h> | ||||
| #include <libsolidity/ast/TypeProvider.h> | ||||
| 
 | ||||
| @ -196,12 +198,20 @@ bool Predicate::isInterface() const | ||||
| 	return m_type == PredicateType::Interface; | ||||
| } | ||||
| 
 | ||||
| string Predicate::formatSummaryCall(vector<smtutil::Expression> const& _args) const | ||||
| string Predicate::formatSummaryCall( | ||||
| 	vector<smtutil::Expression> const& _args, | ||||
| 	langutil::CharStreamProvider const& _charStreamProvider | ||||
| ) const | ||||
| { | ||||
| 	solAssert(isSummary(), ""); | ||||
| 
 | ||||
| 	if (auto funCall = programFunctionCall()) | ||||
| 		return funCall->location().text(); | ||||
| 	{ | ||||
| 		if (funCall->location().hasText()) | ||||
| 			return string(_charStreamProvider.charStream(*funCall->location().sourceName).text(funCall->location())); | ||||
| 		else | ||||
| 			return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	/// 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,
 | ||||
|  | ||||
| @ -27,6 +27,11 @@ | ||||
| #include <optional> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace solidity::langutil | ||||
| { | ||||
| class CharStreamProvider; | ||||
| } | ||||
| 
 | ||||
| namespace solidity::frontend | ||||
| { | ||||
| 
 | ||||
| @ -142,7 +147,10 @@ public: | ||||
| 
 | ||||
| 	/// @returns a formatted string representing a call to this predicate
 | ||||
| 	/// with _args.
 | ||||
| 	std::string formatSummaryCall(std::vector<smtutil::Expression> const& _args) const; | ||||
| 	std::string formatSummaryCall( | ||||
| 		std::vector<smtutil::Expression> const& _args, | ||||
| 		langutil::CharStreamProvider const& _charStreamProvider | ||||
| 	) const; | ||||
| 
 | ||||
| 	/// @returns the values of the state variables from _args at the point
 | ||||
| 	/// where this summary was reached.
 | ||||
|  | ||||
| @ -30,6 +30,8 @@ | ||||
| #include <libsmtutil/SMTPortfolio.h> | ||||
| #include <libsmtutil/Helpers.h> | ||||
| 
 | ||||
| #include <liblangutil/CharStreamProvider.h> | ||||
| 
 | ||||
| #include <range/v3/view.hpp> | ||||
| 
 | ||||
| #include <boost/range/adaptors.hpp> | ||||
| @ -45,11 +47,13 @@ using namespace solidity::frontend; | ||||
| 
 | ||||
| SMTEncoder::SMTEncoder( | ||||
| 	smt::EncodingContext& _context, | ||||
| 	ModelCheckerSettings const& _settings | ||||
| 	ModelCheckerSettings const& _settings, | ||||
| 	langutil::CharStreamProvider const& _charStreamProvider | ||||
| ): | ||||
| 	m_errorReporter(m_smtErrors), | ||||
| 	m_context(_context), | ||||
| 	m_settings(_settings) | ||||
| 	m_settings(_settings), | ||||
| 	m_charStreamProvider(_charStreamProvider) | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -43,6 +43,7 @@ namespace solidity::langutil | ||||
| { | ||||
| class ErrorReporter; | ||||
| struct SourceLocation; | ||||
| class CharStreamProvider; | ||||
| } | ||||
| 
 | ||||
| namespace solidity::frontend | ||||
| @ -53,7 +54,8 @@ class SMTEncoder: public ASTConstVisitor | ||||
| public: | ||||
| 	SMTEncoder( | ||||
| 		smt::EncodingContext& _context, | ||||
| 		ModelCheckerSettings const& _settings | ||||
| 		ModelCheckerSettings const& _settings, | ||||
| 		langutil::CharStreamProvider const& _charStreamProvider | ||||
| 	); | ||||
| 
 | ||||
| 	/// @returns true if engine should proceed with analysis.
 | ||||
| @ -469,6 +471,10 @@ protected: | ||||
| 
 | ||||
| 	ModelCheckerSettings const& m_settings; | ||||
| 
 | ||||
| 	/// Character stream for each source,
 | ||||
| 	/// used for retrieving source text of expressions for e.g. counter-examples.
 | ||||
| 	langutil::CharStreamProvider const& m_charStreamProvider; | ||||
| 
 | ||||
| 	smt::SymbolicState& state(); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -555,7 +555,7 @@ bool CompilerStack::analyze() | ||||
| 
 | ||||
| 		if (noErrors) | ||||
| 		{ | ||||
| 			ModelChecker modelChecker(m_errorReporter, m_smtlib2Responses, m_modelCheckerSettings, m_readFile, m_enabledSMTSolvers); | ||||
| 			ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile, m_enabledSMTSolvers); | ||||
| 			auto allSources = applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); | ||||
| 			modelChecker.enableAllEnginesIfPragmaPresent(allSources); | ||||
| 			modelChecker.checkRequestedSourcesAndContracts(allSources); | ||||
| @ -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." | ||||
|  | ||||
| @ -45,7 +45,7 @@ SourceLocation const AsmJsonImporter::createSourceLocation(Json::Value const& _n | ||||
| { | ||||
| 	yulAssert(member(_node, "src").isString(), "'src' must be a string"); | ||||
| 
 | ||||
| 	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceName); | ||||
| 	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceNames); | ||||
| } | ||||
| 
 | ||||
| template <class T> | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -38,7 +38,9 @@ namespace solidity::yul | ||||
| class AsmJsonImporter | ||||
| { | ||||
| public: | ||||
| 	explicit AsmJsonImporter(std::string _sourceName) : m_sourceName(std::move(_sourceName)) {} | ||||
| 	explicit AsmJsonImporter(std::vector<std::shared_ptr<std::string const>> const& _sourceNames): | ||||
| 		m_sourceNames(_sourceNames) | ||||
| 	{} | ||||
| 	yul::Block createBlock(Json::Value const& _node); | ||||
| 
 | ||||
| private: | ||||
| @ -70,8 +72,7 @@ private: | ||||
| 	yul::Break createBreak(Json::Value const& _node); | ||||
| 	yul::Continue createContinue(Json::Value const& _node); | ||||
| 
 | ||||
| 	std::string m_sourceName; | ||||
| 
 | ||||
| 	std::vector<std::shared_ptr<std::string const>> const& m_sourceNames; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| @ -201,3 +168,30 @@ void VirtualFunction::endVisit(ContractDefinition const& _contract) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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