diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index f63f3ede6..13bb63dfe 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -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(_location.start) >= source.size()) - return ""; + return {}; string cut = source.substr(static_cast(_location.start), static_cast(_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 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(iter->second); } diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index b4acf6f87..75c0e4dca 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -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(_sourceIndicesMap.at(location.source->name())) : + (location.sourceName && _sourceIndicesMap.count(*location.sourceName)) ? + static_cast(_sourceIndicesMap.at(*location.sourceName)) : -1; char jump = '-'; if (item.getJumpType() == evmasm::AssemblyItem::JumpType::IntoFunction) diff --git a/liblangutil/CMakeLists.txt b/liblangutil/CMakeLists.txt index 477d3695c..c98877963 100644 --- a/liblangutil/CMakeLists.txt +++ b/liblangutil/CMakeLists.txt @@ -13,6 +13,7 @@ set(sources ParserBase.h Scanner.cpp Scanner.h + CharStreamProvider.h SemVerHandler.cpp SemVerHandler.h SourceLocation.h diff --git a/liblangutil/CharStream.cpp b/liblangutil/CharStream.cpp index 12e4f642c..8ab99fca8 100644 --- a/liblangutil/CharStream.cpp +++ b/liblangutil/CharStream.cpp @@ -45,9 +45,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * @author Christian - * @date 2014 - * Solidity scanner. + * Character stream / input file. */ #include @@ -118,3 +116,15 @@ tuple CharStream::translatePositionToLineColumn(int _position) const } return tuple(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(_location.end) <= m_source.size(), ""); + return string_view{m_source}.substr( + static_cast(_location.start), + static_cast(_location.end - _location.start) + ); +} diff --git a/liblangutil/CharStream.h b/liblangutil/CharStream.h index 23a0781fc..4b729771f 100644 --- a/liblangutil/CharStream.h +++ b/liblangutil/CharStream.h @@ -45,9 +45,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** - * @author Christian - * @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; diff --git a/liblangutil/CharStreamProvider.h b/liblangutil/CharStreamProvider.h new file mode 100644 index 000000000..1f645f7ef --- /dev/null +++ b/liblangutil/CharStreamProvider.h @@ -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 . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Interface to retrieve the character stream by a source name. + */ + +#pragma once + +#include +#include + +#include + +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; +}; + +} diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index 5dbc2529c..760b4803a 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -138,6 +138,7 @@ private: void Scanner::reset(CharStream _source) { m_source = make_shared(std::move(_source)); + m_sourceName = make_shared(m_source->name()); reset(); } @@ -145,6 +146,7 @@ void Scanner::reset(shared_ptr _source) { solAssert(_source.get() != nullptr, "You MUST provide a CharStream when resetting."); m_source = std::move(_source); + m_sourceName = make_shared(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(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(sourcePos()); m_skippedComments[NextNext].token = comment; @@ -766,7 +768,7 @@ void Scanner::scanToken() } while (token == Token::Whitespace); m_tokens[NextNext].location.end = static_cast(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); } diff --git a/liblangutil/Scanner.h b/liblangutil/Scanner.h index 97f60bbda..ef12703ef 100644 --- a/liblangutil/Scanner.h +++ b/liblangutil/Scanner.h @@ -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 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 m_source; + std::shared_ptr m_sourceName; ScannerKind m_kind = ScannerKind::Solidity; diff --git a/liblangutil/SourceLocation.cpp b/liblangutil/SourceLocation.cpp index 8f3187437..76270829d 100644 --- a/liblangutil/SourceLocation.cpp +++ b/liblangutil/SourceLocation.cpp @@ -34,6 +34,7 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string boost::algorithm::split(pos, _input, boost::is_any_of(":")); + // TODO What to do with sourceIndex? solAssert(pos.size() == 3, "SourceLocation string must have 3 colon separated numeric fields."); auto const sourceIndex = stoi(pos[Index]); @@ -45,12 +46,7 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string int start = stoi(pos[Start]); int end = start + stoi(pos[Length]); - // ASSUMPTION: only the name of source is used from here on, the m_source of the CharStream-Object can be empty - std::shared_ptr source; - if (sourceIndex != -1) - source = std::make_shared("", _sourceName); - - return SourceLocation{start, end, source}; + return SourceLocation{start, end, std::make_shared(_sourceName)}; } } diff --git a/liblangutil/SourceLocation.h b/liblangutil/SourceLocation.h index eb858bd06..71e5ad711 100644 --- a/liblangutil/SourceLocation.h +++ b/liblangutil/SourceLocation.h @@ -26,8 +26,6 @@ #include #include -#include - #include #include #include @@ -44,51 +42,44 @@ struct SourceLocation { bool operator==(SourceLocation const& _other) const { - return source.get() == _other.source.get() && start == _other.start && end == _other.end; + return start == _other.start && end == _other.end && equalSources(_other); } bool operator!=(SourceLocation const& _other) const { return !operator==(_other); } - inline bool operator<(SourceLocation const& _other) const + bool operator<(SourceLocation const& _other) const { - if (!source|| !_other.source) - return std::make_tuple(int(!!source), start, end) < std::make_tuple(int(!!_other.source), _other.start, _other.end); + if (!sourceName || !_other.sourceName) + return std::make_tuple(int(!!sourceName), start, end) < std::make_tuple(int(!!_other.sourceName), _other.start, _other.end); else - return std::make_tuple(source->name(), start, end) < std::make_tuple(_other.source->name(), _other.start, _other.end); + return std::make_tuple(*sourceName, start, end) < std::make_tuple(*_other.sourceName, _other.start, _other.end); } - inline bool contains(SourceLocation const& _other) const + bool contains(SourceLocation const& _other) const { - if (!hasText() || !_other.hasText() || source.get() != _other.source.get()) + if (!hasText() || !_other.hasText() || !equalSources(_other)) return false; return start <= _other.start && _other.end <= end; } - inline bool intersects(SourceLocation const& _other) const + bool intersects(SourceLocation const& _other) const { - if (!hasText() || !_other.hasText() || source.get() != _other.source.get()) + if (!hasText() || !_other.hasText() || !equalSources(_other)) return false; return _other.start < end && start < _other.end; } - bool isValid() const { return source || start != -1 || end != -1; } - - bool hasText() const + bool equalSources(SourceLocation const& _other) const { - return - source && - 0 <= start && - start <= end && - end <= int(source->source().length()); + if (!!sourceName != !!_other.sourceName) + return false; + if (sourceName && *sourceName != *_other.sourceName) + return false; + return true; } - std::string text() const - { - assertThrow(source, SourceLocationError, "Requested text from null source."); - assertThrow(0 <= start, SourceLocationError, "Invalid source location."); - assertThrow(start <= end, SourceLocationError, "Invalid source location."); - assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location."); - return source->source().substr(size_t(start), size_t(end - start)); - } + bool isValid() const { return sourceName || start != -1 || end != -1; } + + bool hasText() const { return sourceName && 0 <= start && start <= end; } /// @returns the smallest SourceLocation that contains both @param _a and @param _b. /// Assumes that @param _a and @param _b refer to the same source (exception: if the source of either one @@ -97,8 +88,8 @@ struct SourceLocation /// @param _b, then start resp. end of the result will be -1 as well). static SourceLocation smallestCovering(SourceLocation _a, SourceLocation const& _b) { - if (!_a.source) - _a.source = _b.source; + if (!_a.sourceName) + _a.sourceName = _b.sourceName; if (_a.start < 0) _a.start = _b.start; @@ -112,7 +103,7 @@ struct SourceLocation int start = -1; int end = -1; - std::shared_ptr source; + std::shared_ptr sourceName; }; SourceLocation const parseSourceLocation( @@ -127,8 +118,8 @@ inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _locat if (!_location.isValid()) return _out << "NO_LOCATION_SPECIFIED"; - if (_location.source) - _out << _location.source->name(); + if (_location.sourceName) + _out << *_location.sourceName; _out << "[" << _location.start << "," << _location.end << "]"; diff --git a/liblangutil/SourceReferenceExtractor.cpp b/liblangutil/SourceReferenceExtractor.cpp index 3eac873aa..717e590df 100644 --- a/liblangutil/SourceReferenceExtractor.cpp +++ b/liblangutil/SourceReferenceExtractor.cpp @@ -16,8 +16,9 @@ */ // SPDX-License-Identifier: GPL-3.0 #include -#include #include +#include +#include #include #include @@ -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(_exception); string const* message = boost::get_error_info(_exception); - SourceReference primary = extract(location, message ? *message : ""); + SourceReference primary = extract(_charStreamProvider, location, message ? *message : ""); std::vector secondary; auto secondaryLocation = boost::get_error_info(_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 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, diff --git a/liblangutil/SourceReferenceExtractor.h b/liblangutil/SourceReferenceExtractor.h index 7eb54845c..d26a941f5 100644 --- a/liblangutil/SourceReferenceExtractor.h +++ b/liblangutil/SourceReferenceExtractor.h @@ -28,6 +28,8 @@ namespace solidity::langutil { +class CharStreamProvider; + struct LineColumn { int line = {-1}; @@ -67,9 +69,9 @@ namespace SourceReferenceExtractor std::optional 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 = ""); } } diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index cc2afc24b..2a0799036 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -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)); } diff --git a/liblangutil/SourceReferenceFormatter.h b/liblangutil/SourceReferenceFormatter.h index dac76912d..630f00de5 100644 --- a/liblangutil/SourceReferenceFormatter.h +++ b/liblangutil/SourceReferenceFormatter.h @@ -23,6 +23,7 @@ #include #include +#include #include @@ -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; }; diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 97308f7e7..20c4f2c46 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -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; diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 04745344f..412ad1aa9 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -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; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index ea8662010..bae1b7d62 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -110,8 +110,8 @@ void ASTJsonConverter::setJsonNode( optional 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; } diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 7b673cca6..8b7f2751b 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -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); diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index 4f414cb99..8906fa97e 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -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) + "," diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 9aab3ff5d..af9335adf 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -101,7 +101,10 @@ pair 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(); diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index c7e25db29..c40424173 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -650,7 +650,7 @@ pair, vector> BMC::modelExpressions() if (uf->annotation().type->isValueType()) { expressionsToEvaluate.emplace_back(expr(*uf)); - expressionNames.push_back(uf->location().text()); + // TODO expressionNames.push_back(uf->location().text()); } return {expressionsToEvaluate, expressionNames}; diff --git a/libsolidity/formal/Predicate.cpp b/libsolidity/formal/Predicate.cpp index c2b8fd607..8e9aace61 100644 --- a/libsolidity/formal/Predicate.cpp +++ b/libsolidity/formal/Predicate.cpp @@ -200,8 +200,9 @@ string Predicate::formatSummaryCall(vector const& _args) co { solAssert(isSummary(), ""); - if (auto funCall = programFunctionCall()) - return funCall->location().text(); + //if (auto funCall = programFunctionCall()) +// return funCall->location().text(); + // TODO /// The signature of a function summary predicate is: summary(error, this, abiFunctions, cryptoFunctions, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars). /// Here we are interested in preInputVars to format the function call, diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 6f86c3cb5..45353720b 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -926,19 +926,6 @@ map CompilerStack::sourceIndices() const return indices; } -map> CompilerStack::indicesToCharStreams() const -{ - map> 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{}; - - 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 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{}) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 9459d7cfa..77b2fe4de 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -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 sourceIndices() const; - /// @returns the reverse mapping of source indices to their respective - /// CharStream instances. - std::map> 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 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 const& unhandledSMTLib2Queries() const { return m_unhandledSMTLib2Queries; } diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index a9c0cfd85..ab70d93b7 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -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(_exception)) message = ((_message.length() > 0) ? (_message + ":") : "") + *description; @@ -1017,6 +1022,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting Error const& err = dynamic_cast(*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); errors.append(formatErrorWithException( + stack, *error, err->type() == Error::Type::Warning, err->typeName(), diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 3896f34a8..852f056ac 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -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 const& _childNode): m_parser(_parser), m_location{_childNode->location()} {} @@ -63,7 +68,7 @@ public: template ASTPointer createNode(Args&& ... _args) { - solAssert(m_location.source, ""); + solAssert(m_location.sourceName, ""); if (m_location.end < 0) markEndPosition(); return make_shared(m_parser.nextID(), m_location, std::forward(_args)...); @@ -2084,7 +2089,7 @@ optional Parser::findLicenseString(std::vector> 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: \" to each source file. " @@ -2094,7 +2099,7 @@ optional Parser::findLicenseString(std::vector> 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." diff --git a/libyul/AsmJsonImporter.cpp b/libyul/AsmJsonImporter.cpp index 0aacbdf84..de4e06870 100644 --- a/libyul/AsmJsonImporter.cpp +++ b/libyul/AsmJsonImporter.cpp @@ -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; } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 5938c3af4..e8f5b3e4e 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -80,7 +80,7 @@ unique_ptr Parser::parse(std::shared_ptr const& _scanner, bool _ try { m_scanner = _scanner; - if (m_charStreamMap) + if (m_sourceNames) fetchSourceLocationFromComment(); auto block = make_unique(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(*sourceIndex)))) + else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(*sourceIndex)))) m_errorReporter.syntaxError(2674_error, commentLocation, "Invalid source mapping. Source index not defined via @use-src."); else { - shared_ptr charStream = m_charStreamMap->at(static_cast(*sourceIndex)); - solAssert(charStream, ""); - m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, charStream}); + shared_ptr sourceName = m_sourceNames->at(static_cast(*sourceIndex)); + solAssert(sourceName, ""); + m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, move(sourceName)}); } } } diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index fc0c9bb64..4b01ce697 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -72,11 +72,11 @@ public: explicit Parser( langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, - std::map> _charStreamMap + std::map> _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>> m_charStreamMap; + std::optional>> m_sourceNames; langutil::SourceLocation m_locationOverride; std::shared_ptr m_debugDataOverride; UseSourceLocationFrom m_useSourceLocationFrom = UseSourceLocationFrom::Scanner; diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 32318edb8..8a00608cf 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -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(CharStream(_source, _sourceName)); - m_parserResult = ObjectParser(m_errorReporter, languageToDialect(m_language, m_evmVersion)).parse(m_scanner, false); + m_charStream = make_unique(_source, _sourceName); + shared_ptr scanner = make_shared(*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 _deployName) const { auto [creationAssembly, deployedAssembly] = assembleEVMWithDeployed(_deployName); yulAssert(creationAssembly, ""); + yulAssert(m_charStream, ""); MachineAssemblyObject creationObject; creationObject.bytecode = make_shared(creationAssembly->assemble()); @@ -249,7 +253,7 @@ AssemblyStack::assembleWithDeployed(optional _deployName) const creationObject.sourceMappings = make_unique( evmasm::AssemblyItem::computeSourceMapping( creationAssembly->items(), - {{scanner().charStream() ? scanner().charStream()->name() : "", 0}} + {{m_charStream->name(), 0}} ) ); @@ -261,7 +265,7 @@ AssemblyStack::assembleWithDeployed(optional _deployName) const deployedObject.sourceMappings = make_unique( evmasm::AssemblyItem::computeSourceMapping( deployedAssembly->items(), - {{scanner().charStream() ? scanner().charStream()->name() : "", 0}} + {{m_charStream->name(), 0}} ) ); } diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index 925d0f87d..3fcd15998 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -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 m_scanner; + std::unique_ptr m_charStream; bool m_analysisSuccessful = false; std::shared_ptr m_parserResult; diff --git a/libyul/backends/wasm/EVMToEwasmTranslator.cpp b/libyul/backends/wasm/EVMToEwasmTranslator.cpp index 074174532..65687cf59 100644 --- a/libyul/backends/wasm/EVMToEwasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEwasmTranslator.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -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); } diff --git a/libyul/backends/wasm/EVMToEwasmTranslator.h b/libyul/backends/wasm/EVMToEwasmTranslator.h index 251e3352b..7f95f8d13 100644 --- a/libyul/backends/wasm/EVMToEwasmTranslator.h +++ b/libyul/backends/wasm/EVMToEwasmTranslator.h @@ -25,6 +25,10 @@ #include #include +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 m_polyfill; std::set m_polyfillFunctions; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index a553e0491..aeb40f099 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -561,7 +561,7 @@ bool CommandLineInterface::compile() m_compiler = make_unique(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()) { diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 5e260b14d..0c1e4dbad 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -57,11 +57,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) { "sub.asm", 1 } }; Assembly _assembly; - auto root_asm = make_shared("lorem ipsum", "root.asm"); + auto root_asm = make_shared("root.asm"); _assembly.setSourceLocation({1, 3, root_asm}); Assembly _subAsm; - auto sub_asm = make_shared("lorem ipsum", "sub.asm"); + auto sub_asm = make_shared("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("lorem ipsum", "root.asm"); + auto root_asm = make_shared("root.asm"); _assembly.setSourceLocation({1, 3, root_asm}); Assembly _subAsm; - auto sub_asm = make_shared("lorem ipsum", "sub.asm"); + auto sub_asm = make_shared("sub.asm"); _subAsm.setSourceLocation({6, 8, sub_asm}); _subAsm.appendImmutable("someImmutable"); _subAsm.appendImmutable("someOtherImmutable"); diff --git a/test/liblangutil/SourceLocation.cpp b/test/liblangutil/SourceLocation.cpp index ff1664dfe..c8457dd06 100644 --- a/test/liblangutil/SourceLocation.cpp +++ b/test/liblangutil/SourceLocation.cpp @@ -34,9 +34,9 @@ BOOST_AUTO_TEST_SUITE(SourceLocationTest) BOOST_AUTO_TEST_CASE(test_fail) { - auto const source = std::make_shared("lorem ipsum", "source"); - auto const sourceA = std::make_shared("lorem ipsum", "sourceA"); - auto const sourceB = std::make_shared("lorem ipsum", "sourceB"); + auto const source = std::make_shared("source"); + auto const sourceA = std::make_shared("sourceA"); + auto const sourceB = std::make_shared("sourceB"); BOOST_CHECK(SourceLocation{} == SourceLocation{}); BOOST_CHECK((SourceLocation{0, 3, sourceA} != SourceLocation{0, 3, sourceB})); diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index a571d282b..8579e9ea4 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -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; } diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp index 36172562d..bc1a5372d 100644 --- a/test/libsolidity/AnalysisFramework.cpp +++ b/test/libsolidity/AnalysisFramework.cpp @@ -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) diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index 75238c9cf..cfa25e813 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -109,7 +109,7 @@ void printAssemblyLocations(AssemblyItems const& _items) ", " << _loc.end << ", make_shared(\"" << - _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(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(sourceCode, "")); + shared_ptr sourceName = make_shared(); bool hasShifts = solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting(); auto codegenCharStream = make_shared("", "--CODEGEN--"); @@ -173,18 +174,18 @@ BOOST_AUTO_TEST_CASE(location_test) vector locations; if (solidity::test::CommonOptions::get().optimize) locations = - vector(31, SourceLocation{23, 103, sourceCode}) + - vector(1, SourceLocation{41, 100, sourceCode}) + - vector(1, SourceLocation{93, 95, sourceCode}) + - vector(15, SourceLocation{41, 100, sourceCode}); + vector(31, SourceLocation{23, 103, sourceName}) + + vector(1, SourceLocation{41, 100, sourceName}) + + vector(1, SourceLocation{93, 95, sourceName}) + + vector(15, SourceLocation{41, 100, sourceName}); else locations = - vector(hasShifts ? 31 : 32, SourceLocation{23, 103, sourceCode}) + - vector(24, SourceLocation{41, 100, sourceCode}) + - vector(1, SourceLocation{70, 79, sourceCode}) + - vector(1, SourceLocation{93, 95, sourceCode}) + - vector(2, SourceLocation{86, 95, sourceCode}) + - vector(2, SourceLocation{41, 100, sourceCode}); + vector(hasShifts ? 31 : 32, SourceLocation{23, 103, sourceName}) + + vector(24, SourceLocation{41, 100, sourceName}) + + vector(1, SourceLocation{70, 79, sourceName}) + + vector(1, SourceLocation{93, 95, sourceName}) + + vector(2, SourceLocation{86, 95, sourceName}) + + vector(2, SourceLocation{41, 100, sourceName}); checkAssemblyLocations(items, locations); } diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 36910647c..fd215cb94 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -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; } diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 32ed71e17..19b2da3b3 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -81,7 +81,7 @@ std::optional 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; diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index 6ec949c68..349baf481 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -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); diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 5443f7b39..48d87c6bb 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -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(loc.start), static_cast(loc.end - loc.start)); + auto asmStr = m_sourceCode.substr(static_cast(loc.start), static_cast(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?!"); diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index ed23bc609..bc0f6a7d8 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -17,6 +17,7 @@ // SPDX-License-Identifier: GPL-3.0 #include + #include #include #include @@ -119,11 +120,13 @@ void SyntaxTest::filterObtainedErrors() string sourceName; if (auto location = boost::get_error_info(*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(location->source->source().size()) - static_cast(m_sources.sources[sourceName].size()); + + int preambleSize = + static_cast(compiler().charStream(sourceName).size()) - + static_cast(m_sources.sources[sourceName].size()); solAssert(preambleSize >= 0, ""); // ignore the version & license pragma inserted by the testing tool when calculating locations. diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 35dd0de26..853b7dafc 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -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> yul::test::parse(string const& _source, bool _yul) { AssemblyStack stack( diff --git a/test/libyul/Common.h b/test/libyul/Common.h index 57f659400..f6c63feb9 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -44,8 +44,6 @@ struct Dialect; namespace solidity::yul::test { -void printErrors(langutil::ErrorList const& _errors); - std::pair, std::shared_ptr> parse(std::string const& _source, bool _yul = true); diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index eea7e0914..043eae331 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -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; } diff --git a/test/libyul/EwasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp index 3c5e6cacb..6051c2e20 100644 --- a/test/libyul/EwasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -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); -} diff --git a/test/libyul/EwasmTranslationTest.h b/test/libyul/EwasmTranslationTest.h index 5175430e3..eba82beee 100644 --- a/test/libyul/EwasmTranslationTest.h +++ b/test/libyul/EwasmTranslationTest.h @@ -20,16 +20,12 @@ #include -namespace solidity::langutil -{ -class Scanner; -class Error; -using ErrorList = std::vector>; -} +#include 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 m_object; + AssemblyStack m_stack; }; } diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index f4a1c296d..2c3560726 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -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); -} diff --git a/test/libyul/ObjectCompilerTest.h b/test/libyul/ObjectCompilerTest.h index e75f72fa9..c7880fe55 100644 --- a/test/libyul/ObjectCompilerTest.h +++ b/test/libyul/ObjectCompilerTest.h @@ -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; }; diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 676b6699c..553e84d4b 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -51,24 +51,19 @@ namespace solidity::yul::test namespace { -string_view constexpr g_strAlternateSourceText = "{}"; - shared_ptr parse(string const& _source, Dialect const& _dialect, ErrorReporter& errorReporter) { try { auto scanner = make_shared(CharStream(_source, "")); - map> indicesToCharStreams; - indicesToCharStreams[0] = scanner->charStream(); - indicesToCharStreams[1] = make_shared( - string(g_strAlternateSourceText.data(), g_strAlternateSourceText.size()), - "alternate.sol" - ); + map> indicesToSourceNames; + indicesToSourceNames[0] = make_shared("source0"); + indicesToSourceNames[1] = make_shared("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 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 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 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 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 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(result->statements.at(1))); auto const& switchStmt = get(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 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(result->statements.at(0))); BOOST_REQUIRE_EQUAL(get(result->statements.at(0)).statements.size(), 1); - CHECK_LOCATION(locationOf(get(result->statements.at(0)).statements.at(0)), sourceText, 123, 432); + CHECK_LOCATION(locationOf(get(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 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(result->statements.at(0))); VariableDeclaration const& varDecl = get(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 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(result->statements.at(0))); VariableDeclaration const& varDecl = get(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(*varDecl.value)); FunctionCall const& call = get(*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 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(result->statements.at(0))); Block const& innerBlock = get(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(result->statements.at(1))); ExpressionStatement const& sstoreStmt = get(innerBlock.statements.at(0)); BOOST_REQUIRE(holds_alternative(sstoreStmt.expression)); FunctionCall const& sstoreCall = get(sstoreStmt.expression); - CHECK_LOCATION(sstoreCall.debugData->location, g_strAlternateSourceText, 23, 45); + CHECK_LOCATION(sstoreCall.debugData->location, "source1", 23, 45); BOOST_REQUIRE(holds_alternative(result->statements.at(1))); ExpressionStatement mstoreStmt = get(result->statements.at(1)); BOOST_REQUIRE(holds_alternative(mstoreStmt.expression)); FunctionCall const& mstoreCall = get(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 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(result->statements.at(0))); VariableDeclaration const& varDecl = get(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(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(result->statements.at(0))); VariableDeclaration const& varDecl = get(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); } diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index f275e38a4..6f7da9f98 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -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); -} diff --git a/test/libyul/YulInterpreterTest.h b/test/libyul/YulInterpreterTest.h index 88e535fb0..fc362ecf6 100644 --- a/test/libyul/YulInterpreterTest.h +++ b/test/libyul/YulInterpreterTest.h @@ -20,13 +20,6 @@ #include -namespace solidity::langutil -{ -class Scanner; -class Error; -using ErrorList = std::vector>; -} - 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 m_ast; std::shared_ptr m_analysisInfo; }; diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 36d9cefc2..3454f09ac 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -28,6 +28,7 @@ #include #include +#include #include @@ -115,16 +116,10 @@ std::pair, std::shared_ptr> 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); -} diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index b4ba4ca7a..832b5dfb8 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -51,7 +51,6 @@ private: std::pair, std::shared_ptr> 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; diff --git a/test/tools/ossfuzz/SolidityEvmoneInterface.cpp b/test/tools/ossfuzz/SolidityEvmoneInterface.cpp index 954ae2bf0..4d536183c 100644 --- a/test/tools/ossfuzz/SolidityEvmoneInterface.cpp +++ b/test/tools/ossfuzz/SolidityEvmoneInterface.cpp @@ -41,13 +41,11 @@ optional 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 {}; diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index d405c2bc8..1fe4e6eaa 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -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"); } diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index 1d3ca3868..aaf7cc516 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -44,6 +44,8 @@ #include #include +#include +#include #include #include @@ -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 = make_shared(CharStream(_input, "")); - m_ast = yul::Parser(errorReporter, m_dialect).parse(scanner, false); + m_scanner = make_shared(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 m_scanner; shared_ptr m_ast; Dialect const& m_dialect{EVMDialect::strictAssemblyForEVMObjects(EVMVersion{})}; shared_ptr m_analysisInfo; diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index b5f8d60dd..7906be744 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -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> parse(string const& _source) { AssemblyStack stack( @@ -73,7 +67,7 @@ pair, shared_ptr> parse(string const& _source } else { - printErrors(stack.errors()); + SourceReferenceFormatter(cout, stack, true, false).printErrorInformation(stack.errors()); return {}; } } diff --git a/tools/solidityUpgrade/SourceTransform.h b/tools/solidityUpgrade/SourceTransform.h index 65226a442..04d128298 100644 --- a/tools/solidityUpgrade/SourceTransform.h +++ b/tools/solidityUpgrade/SourceTransform.h @@ -22,6 +22,9 @@ #include +#include +#include + #include #include @@ -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; diff --git a/tools/solidityUpgrade/SourceUpgrade.cpp b/tools/solidityUpgrade/SourceUpgrade.cpp index 540a042a7..6b9bcd1d0 100644 --- a/tools/solidityUpgrade/SourceUpgrade.cpp +++ b/tools/solidityUpgrade/SourceUpgrade.cpp @@ -347,14 +347,14 @@ bool SourceUpgrade::analyzeAndUpgrade(pair 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(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 diff --git a/tools/solidityUpgrade/SourceUpgrade.h b/tools/solidityUpgrade/SourceUpgrade.h index f70d24080..11e7e12a9 100644 --- a/tools/solidityUpgrade/SourceUpgrade.h +++ b/tools/solidityUpgrade/SourceUpgrade.h @@ -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); } diff --git a/tools/solidityUpgrade/Upgrade050.cpp b/tools/solidityUpgrade/Upgrade050.cpp index 9c0ecd656..c8b4de9e8 100644 --- a/tools/solidityUpgrade/Upgrade050.cpp +++ b/tools/solidityUpgrade/Upgrade050.cpp @@ -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") ); } diff --git a/tools/solidityUpgrade/Upgrade060.cpp b/tools/solidityUpgrade/Upgrade060.cpp index c614f89d0..52010db39 100644 --- a/tools/solidityUpgrade/Upgrade060.cpp +++ b/tools/solidityUpgrade/Upgrade060.cpp @@ -29,75 +29,6 @@ using namespace solidity; using namespace solidity::frontend; using namespace solidity::tools; -using Contracts = set; - -namespace -{ - -inline string appendOverride( - FunctionDefinition const& _function, - Contracts const& _expectedContracts -) -{ - auto location = _function.location(); - string upgradedCode; - string overrideExpression = SourceGeneration::functionOverride(_expectedContracts); - - if (SourceAnalysis::hasVirtualKeyword(location)) - upgradedCode = SourceTransform::insertAfterKeyword( - location, - "virtual", - overrideExpression - ); - else if (SourceAnalysis::hasMutabilityKeyword(location)) - upgradedCode = SourceTransform::insertAfterKeyword( - location, - stateMutabilityToString(_function.stateMutability()), - overrideExpression - ); - else if (SourceAnalysis::hasVisibilityKeyword(location)) - upgradedCode = SourceTransform::insertAfterKeyword( - location, - Declaration::visibilityToString(_function.visibility()), - overrideExpression - ); - else - upgradedCode = SourceTransform::insertAfterRightParenthesis( - location, - overrideExpression - ); - - return upgradedCode; -} - -inline string appendVirtual(FunctionDefinition const& _function) -{ - auto location = _function.location(); - string upgradedCode; - - if (SourceAnalysis::hasMutabilityKeyword(location)) - upgradedCode = SourceTransform::insertAfterKeyword( - location, - stateMutabilityToString(_function.stateMutability()), - "virtual" - ); - else if (SourceAnalysis::hasVisibilityKeyword(location)) - upgradedCode = SourceTransform::insertAfterKeyword( - location, - Declaration::visibilityToString(_function.visibility()), - "virtual" - ); - else - upgradedCode = SourceTransform::insertAfterRightParenthesis( - _function.location(), - "virtual" - ); - - return upgradedCode; -} - -} - void AbstractContract::endVisit(ContractDefinition const& _contract) { bool isFullyImplemented = _contract.annotation().unimplementedDeclarations->empty(); @@ -110,7 +41,7 @@ void AbstractContract::endVisit(ContractDefinition const& _contract) m_changes.emplace_back( UpgradeChange::Level::Safe, _contract.location(), - SourceTransform::insertBeforeKeyword(_contract.location(), "contract", "abstract") + SourceTransform{m_charStreamProvider}.insertBeforeKeyword(_contract.location(), "contract", "abstract") ); } @@ -159,6 +90,42 @@ void OverridingFunction::endVisit(ContractDefinition const& _contract) } } +string OverridingFunction::appendOverride( + FunctionDefinition const& _function, + Contracts const& _expectedContracts +) +{ + auto location = _function.location(); + string upgradedCode; + string overrideExpression = SourceGeneration::functionOverride(_expectedContracts); + + if (SourceAnalysis{m_charStreamProvider}.hasVirtualKeyword(location)) + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword( + location, + "virtual", + overrideExpression + ); + else if (SourceAnalysis{m_charStreamProvider}.hasMutabilityKeyword(location)) + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword( + location, + stateMutabilityToString(_function.stateMutability()), + overrideExpression + ); + else if (SourceAnalysis{m_charStreamProvider}.hasVisibilityKeyword(location)) + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword( + location, + Declaration::visibilityToString(_function.visibility()), + overrideExpression + ); + else + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis( + location, + overrideExpression + ); + + return upgradedCode; +} + void VirtualFunction::endVisit(ContractDefinition const& _contract) { auto const& inheritedFunctions = m_overrideChecker.inheritedFunctions(_contract); @@ -192,12 +159,39 @@ void VirtualFunction::endVisit(ContractDefinition const& _contract) ) { m_changes.emplace_back( - UpgradeChange::Level::Safe, - function->location(), - appendVirtual(*function) + UpgradeChange::Level::Safe, + function->location(), + appendVirtual(*function) ); } } } } } + +string VirtualFunction::appendVirtual(FunctionDefinition const& _function) const +{ + auto location = _function.location(); + string upgradedCode; + + if (SourceAnalysis{m_charStreamProvider}.hasMutabilityKeyword(location)) + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword( + location, + stateMutabilityToString(_function.stateMutability()), + "virtual" + ); + else if (SourceAnalysis{m_charStreamProvider}.hasVisibilityKeyword(location)) + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword( + location, + Declaration::visibilityToString(_function.visibility()), + "virtual" + ); + else + upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis( + _function.location(), + "virtual" + ); + + return upgradedCode; +} + diff --git a/tools/solidityUpgrade/Upgrade060.h b/tools/solidityUpgrade/Upgrade060.h index 9a8880b96..46b10a3a0 100644 --- a/tools/solidityUpgrade/Upgrade060.h +++ b/tools/solidityUpgrade/Upgrade060.h @@ -50,7 +50,14 @@ public: void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); } private: + using Contracts = std::set; + 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; }; } diff --git a/tools/solidityUpgrade/Upgrade070.cpp b/tools/solidityUpgrade/Upgrade070.cpp index 04b88f7ca..6a26b1400 100644 --- a/tools/solidityUpgrade/Upgrade070.cpp +++ b/tools/solidityUpgrade/Upgrade070.cpp @@ -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()) ); } diff --git a/tools/solidityUpgrade/UpgradeChange.cpp b/tools/solidityUpgrade/UpgradeChange.cpp index 51475ffd3..2976efe5d 100644 --- a/tools/solidityUpgrade/UpgradeChange.cpp +++ b/tools/solidityUpgrade/UpgradeChange.cpp @@ -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(m_location.start), - static_cast(m_location.end - m_location.start), m_patch + static_cast(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(log10(max(lineEnd.line, 1))) + 2; stringstream output; diff --git a/tools/solidityUpgrade/UpgradeChange.h b/tools/solidityUpgrade/UpgradeChange.h index 19f08c6a0..6cccc154b 100644 --- a/tools/solidityUpgrade/UpgradeChange.h +++ b/tools/solidityUpgrade/UpgradeChange.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -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; diff --git a/tools/solidityUpgrade/UpgradeSuite.h b/tools/solidityUpgrade/UpgradeSuite.h index 33aeb40eb..2bde6ec0e 100644 --- a/tools/solidityUpgrade/UpgradeSuite.h +++ b/tools/solidityUpgrade/UpgradeSuite.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -37,13 +38,17 @@ namespace solidity::tools class Upgrade { public: - Upgrade(std::vector& _changes): m_changes(_changes) {} + Upgrade( + langutil::CharStreamProvider const& _charStreamProvider, + std::vector& _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& m_changes; + langutil::CharStreamProvider const& m_charStreamProvider; }; /** @@ -53,8 +58,11 @@ protected: class AnalysisUpgrade: public Upgrade, public frontend::ASTConstVisitor { public: - AnalysisUpgrade(std::vector& _changes): - Upgrade(_changes), + AnalysisUpgrade( + langutil::CharStreamProvider const& _charStreamProvider, + std::vector& _changes + ): + Upgrade(_charStreamProvider, _changes), m_errorReporter(m_errors), m_overrideChecker(m_errorReporter) {} diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index ca15f3ccd..db7d79c31 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include @@ -389,7 +391,9 @@ vector ProgramFactory::build(Options const& _options) variant programOrErrors = Program::load(sourceCode); if (holds_alternative(programOrErrors)) { - cerr << get(programOrErrors) << endl; + SourceReferenceFormatter{cerr, SingletonCharStreamProvider(sourceCode), true, false} + .printErrorInformation(get(programOrErrors)); + cerr << endl; assertThrow(false, InvalidProgram, "Failed to load program " + path); } diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index e01581d6a..2635b27fa 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -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(get(ASTCopier{}(*program.m_ast)))), m_dialect{program.m_dialect}, diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index d0eb8e197..e42471d77 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -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 {