diff --git a/libsolutil/CMakeLists.txt b/libsolutil/CMakeLists.txt index 201429bb7..f97d61b67 100644 --- a/libsolutil/CMakeLists.txt +++ b/libsolutil/CMakeLists.txt @@ -13,8 +13,6 @@ set(sources ErrorCodes.h FixedHash.h FunctionSelector.h - IndentedWriter.cpp - IndentedWriter.h IpfsHash.cpp IpfsHash.h JSON.cpp diff --git a/libsolutil/IndentedWriter.cpp b/libsolutil/IndentedWriter.cpp deleted file mode 100644 index b2a3c06c9..000000000 --- a/libsolutil/IndentedWriter.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - 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 -/** - * @date 2017 - * Indented text writer. - */ - -#include -#include - -using namespace solidity::util; - -std::string IndentedWriter::format() const -{ - std::string result; - for (auto const& line: m_lines) - result += std::string(line.indentation * 4, ' ') + line.contents + "\n"; - return result; -} - -void IndentedWriter::newLine() -{ - if (!m_lines.back().contents.empty()) - m_lines.emplace_back(Line{std::string(), m_lines.back().indentation}); -} - -void IndentedWriter::indent() -{ - newLine(); - m_lines.back().indentation++; -} - -void IndentedWriter::unindent() -{ - newLine(); - assertThrow(m_lines.back().indentation > 0, IndentedWriterError, "Negative indentation."); - m_lines.back().indentation--; -} - -void IndentedWriter::add(std::string const& _str) -{ - m_lines.back().contents += _str; -} - -void IndentedWriter::addLine(std::string const& _line) -{ - newLine(); - add(_line); - newLine(); -} diff --git a/libsolutil/IndentedWriter.h b/libsolutil/IndentedWriter.h deleted file mode 100644 index 47e2817fa..000000000 --- a/libsolutil/IndentedWriter.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - 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 -/** - * @date 2017 - * Indented text writer. - */ - -#pragma once - -#include -#include - -#include - -namespace solidity::util -{ - -DEV_SIMPLE_EXCEPTION(IndentedWriterError); - -class IndentedWriter -{ -public: - // Returns the formatted output. - std::string format() const; - - // Go one indentation level in. - void indent(); - - // Go one indentation level out. - void unindent(); - - // Add text. - void add(std::string const& _str); - - // Add text with new line. - void addLine(std::string const& _line); - - // Add new line. - void newLine(); - -private: - struct Line - { - std::string contents; - unsigned indentation; - }; - - std::vector m_lines{{std::string(), 0}}; -}; - -} diff --git a/libsolutil/StringUtils.cpp b/libsolutil/StringUtils.cpp index 1dc86714d..f5d2bbfb3 100644 --- a/libsolutil/StringUtils.cpp +++ b/libsolutil/StringUtils.cpp @@ -23,6 +23,10 @@ */ #include + +#include + +#include #include #include @@ -190,3 +194,34 @@ std::string solidity::util::formatNumberReadable(bigint const& _value, bool _use return sign + str; } +std::string solidity::util::prefixLines( + std::string const& _input, + std::string const& _prefix, + bool _trimPrefix +) +{ + std::ostringstream output; + printPrefixed(output, _input, _prefix, _trimPrefix, false /* _ensureFinalNewline */); + return output.str(); +} + +void solidity::util::printPrefixed( + std::ostream& _output, + std::string const& _input, + std::string const& _prefix, + bool _trimPrefix, + bool _ensureFinalNewline +) +{ + std::istringstream input(_input); + std::string line; + while (std::getline(input, line)) + { + if (line.empty() && _trimPrefix) + _output << boost::trim_right_copy(_prefix); + else + _output << _prefix << line; + if (!input.eof() || _ensureFinalNewline) + _output << '\n'; + } +} diff --git a/libsolutil/StringUtils.h b/libsolutil/StringUtils.h index 0d5bc7839..77ffe6735 100644 --- a/libsolutil/StringUtils.h +++ b/libsolutil/StringUtils.h @@ -168,7 +168,7 @@ inline bool isDigit(char _c) return isdigit(_c, std::locale::classic()); } -// Checks if character is printable using classic "C" locale +/// Checks if character is printable using classic "C" locale /// @param _c character to be checked /// @return true if _c is a printable character, false otherwise. inline bool isPrint(char _c) @@ -176,4 +176,36 @@ inline bool isPrint(char _c) return isprint(_c, std::locale::classic()); } +/// Adds a prefix to every line in the input. +/// @see printPrefixed() +std::string prefixLines( + std::string const& _input, + std::string const& _prefix, + bool _trimPrefix = true +); + +/// Prints to a stream, adding a prefix to every line in the input. +/// Assumes \n as the line separator. +/// @param _trimPrefix If true, the function avoids introducing trailing whitespace on empty lines. +/// This is achieved by removing trailing spaces from the prefix on such lines. +/// Note that tabs and newlines are not removed, only spaces are. +/// @param _finalNewline If true, an extra \n will be printed at the end of @a _input if it does +/// not already end with one. +void printPrefixed( + std::ostream& _output, + std::string const& _input, + std::string const& _prefix, + bool _trimPrefix = true, + bool _ensureFinalNewline = true +); + +/// Adds a standard indent of 4 spaces to every line in the input. +/// Assumes \n as the line separator. +/// @param _indentEmptyLines If true, the indent will be applied to empty lines as well, resulting +/// such lines containing trailing whitespace. +inline std::string indent(std::string const& _input, bool _indentEmptyLines = false) +{ + return prefixLines(_input, " ", !_indentEmptyLines); +} + } diff --git a/libyul/Object.cpp b/libyul/Object.cpp index 83ee66a3b..0d3d66c8e 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -30,8 +30,6 @@ #include #include -#include -#include #include @@ -40,18 +38,6 @@ using namespace solidity::langutil; using namespace solidity::util; using namespace solidity::yul; -namespace -{ - -std::string indent(std::string const& _input) -{ - if (_input.empty()) - return _input; - return boost::replace_all_copy(" " + _input, "\n", "\n "); -} - -} - std::string Data::toString(Dialect const*, DebugInfoSelection const&, CharStreamProvider const*) const { return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f8242db7a..f32a14d91 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -33,7 +33,6 @@ set(libsolutil_sources libsolutil/CommonIO.cpp libsolutil/FixedHash.cpp libsolutil/FunctionSelector.cpp - libsolutil/IndentedWriter.cpp libsolutil/IpfsHash.cpp libsolutil/IterateReplacing.cpp libsolutil/JSON.cpp diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 79b597804..8e546017f 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -144,11 +145,8 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, else { if (outputSourceNames) - _stream << _linePrefix << "==== Source: " + name << " ====" << endl; - stringstream stream(source); - string line; - while (getline(stream, line)) - _stream << _linePrefix << line << endl; + printPrefixed(_stream, "==== Source: " + name + " ====", _linePrefix); + printPrefixed(_stream, source, _linePrefix); } } diff --git a/test/TestCase.cpp b/test/TestCase.cpp index 059d2ab70..51608bd4a 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -20,8 +20,8 @@ #include #include +#include -#include #include #include @@ -31,6 +31,7 @@ using namespace std; using namespace solidity; using namespace solidity::frontend; using namespace solidity::frontend::test; +using namespace solidity::util; void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const bool) { @@ -69,26 +70,14 @@ void TestCase::expect(string::iterator& _it, string::iterator _end, string::valu ++_it; } -void TestCase::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const -{ - stringstream output(_output); - string line; - while (getline(output, line)) - if (line.empty()) - // Avoid trailing spaces. - _stream << boost::trim_right_copy(_linePrefix) << endl; - else - _stream << _linePrefix << line << endl; -} - void TestCase::printSource(ostream& _stream, string const& _linePrefix, bool const) const { - printIndented(_stream, m_source, _linePrefix); + printPrefixed(_stream, m_source, _linePrefix); } void TestCase::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const { - printIndented(_stream, m_obtainedResult, _linePrefix); + printPrefixed(_stream, m_obtainedResult, _linePrefix); } TestCase::TestResult TestCase::checkResult(std::ostream& _stream, const std::string& _linePrefix, bool const _formatted) @@ -99,10 +88,10 @@ TestCase::TestResult TestCase::checkResult(std::ostream& _stream, const std::str util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) << _linePrefix << "Expected result:" << endl; // TODO could compute a simple diff with highlighted lines - printIndented(_stream, m_expectation, nextIndentLevel); + printPrefixed(_stream, m_expectation, nextIndentLevel); util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) << _linePrefix << "Obtained result:" << endl; - printIndented(_stream, m_obtainedResult, nextIndentLevel); + printPrefixed(_stream, m_obtainedResult, nextIndentLevel); return TestResult::Failure; } return TestResult::Success; diff --git a/test/TestCase.h b/test/TestCase.h index f631bea8d..301dbfb65 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -100,7 +100,6 @@ protected: ++_it; } - void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const; TestCase::TestResult checkResult(std::ostream& _stream, const std::string& _linePrefix, bool const _formatted); std::string m_source; diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index a318eacee..daf4a9ea4 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -270,12 +270,7 @@ bool ASTJSONTest::runTest( "Expected result" << (!_variant.name().empty() ? " (" + _variant.name() + "):" : ":") << std::endl; - { - std::istringstream stream(_variant.expectation); - std::string line; - while (getline(stream, line)) - _stream << nextIndentLevel << line << std::endl; - } + printPrefixed(_stream, _variant.expectation, nextIndentLevel); _stream << std::endl; AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << @@ -283,12 +278,7 @@ bool ASTJSONTest::runTest( "Obtained result" << (!_variant.name().empty() ? " (" + _variant.name() + "):" : ":") << std::endl; - { - std::istringstream stream(_variant.result); - std::string line; - while (getline(stream, line)) - _stream << nextIndentLevel << line << std::endl; - } + printPrefixed(_stream, _variant.result, nextIndentLevel); _stream << std::endl; return false; } @@ -301,11 +291,8 @@ void ASTJSONTest::printSource(std::ostream& _stream, std::string const& _linePre for (auto const& source: m_sources) { if (m_sources.size() > 1 || source.first != "a") - _stream << _linePrefix << sourceDelimiter << source.first << " ====" << std::endl << std::endl; - std::stringstream stream(source.second); - std::string line; - while (getline(stream, line)) - _stream << _linePrefix << line << std::endl; + printPrefixed(_stream, sourceDelimiter + source.first + " ====\n", _linePrefix); + printPrefixed(_stream, source.second, _linePrefix); _stream << std::endl; } } diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 5d8a69497..73aa780e4 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -158,11 +158,3 @@ TestCase::TestResult GasTest::run(std::ostream& _stream, std::string const& _lin return TestResult::Failure; } } - -void GasTest::printSource(std::ostream& _stream, std::string const& _linePrefix, bool) const -{ - std::string line; - std::istringstream input(m_source); - while (getline(input, line)) - _stream << _linePrefix << line << std::endl; -} diff --git a/test/libsolidity/GasTest.h b/test/libsolidity/GasTest.h index a04976cd5..1337ae3f6 100644 --- a/test/libsolidity/GasTest.h +++ b/test/libsolidity/GasTest.h @@ -41,7 +41,6 @@ public: TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; - void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool _formatted = false) const override; void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override; protected: diff --git a/test/libsolidity/NatspecJSONTest.cpp b/test/libsolidity/NatspecJSONTest.cpp index 434d5b392..53f0db86f 100644 --- a/test/libsolidity/NatspecJSONTest.cpp +++ b/test/libsolidity/NatspecJSONTest.cpp @@ -100,8 +100,9 @@ void NatspecJSONTest::printExpectedResult(ostream& _stream, string const& _lineP if (!m_expectedNatspecJSON.empty()) { _stream << _linePrefix << "----" << endl; - printIndented(_stream, formatNatspecExpectations(m_expectedNatspecJSON), _linePrefix); + printPrefixed(_stream, formatNatspecExpectations(m_expectedNatspecJSON), _linePrefix); } + } void NatspecJSONTest::printObtainedResult(ostream& _stream, string const& _linePrefix, bool _formatted) const @@ -114,7 +115,7 @@ void NatspecJSONTest::printObtainedResult(ostream& _stream, string const& _lineP _stream << _linePrefix << "----" << endl; // TODO: Diff both versions and highlight differences. // We should have a helper for doing that in newly defined test cases without much effort. - printIndented(_stream, formatNatspecExpectations(natspecJSON), _linePrefix); + printPrefixed(_stream, formatNatspecExpectations(natspecJSON), _linePrefix); } } diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index f59c61ad8..25113b689 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -647,11 +647,8 @@ void SemanticTest::printSource(std::ostream& _stream, std::string const& _linePr else { if (outputNames) - _stream << _linePrefix << "==== Source: " + name << " ====" << std::endl; - std::stringstream stream(source); - std::string line; - while (getline(stream, line)) - _stream << _linePrefix << line << std::endl; + printPrefixed(_stream, "==== Source: " + name + " ====", _linePrefix); + printPrefixed(_stream, source, _linePrefix); } } } diff --git a/test/libsolutil/IndentedWriter.cpp b/test/libsolutil/IndentedWriter.cpp deleted file mode 100644 index 94997c842..000000000 --- a/test/libsolutil/IndentedWriter.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - 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 -/** - * Unit tests for IndentedWriter. - */ - -#include - -#include - -#include - - -namespace solidity::util::test -{ - -BOOST_AUTO_TEST_SUITE(IndentedWriterTest) - -BOOST_AUTO_TEST_CASE(empty) -{ - IndentedWriter iw; - BOOST_CHECK_EQUAL(iw.format(), "\n"); -} - -BOOST_AUTO_TEST_CASE(new_lines) -{ - IndentedWriter iw; - iw.newLine(); - BOOST_CHECK_EQUAL(iw.format(), "\n"); -} - -BOOST_AUTO_TEST_CASE(text_without_newline) -{ - IndentedWriter iw; - iw.add("Hello World"); - BOOST_CHECK_EQUAL(iw.format(), "Hello World\n"); -} - -BOOST_AUTO_TEST_CASE(text_with_newline) -{ - IndentedWriter iw; - iw.addLine("Hello World"); - BOOST_CHECK_EQUAL(iw.format(), "Hello World\n\n"); -} - -BOOST_AUTO_TEST_CASE(indent) -{ - IndentedWriter iw; - iw.addLine("Hello"); - iw.indent(); - iw.addLine("World"); - iw.unindent(); - iw.addLine("and everyone else"); - BOOST_CHECK_EQUAL(iw.format(), "Hello\n World\nand everyone else\n\n"); -} - -BOOST_AUTO_TEST_SUITE_END() - -} diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index b50bcb38e..6d7297c2c 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -31,6 +31,7 @@ #include #include +#include #include @@ -86,7 +87,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line { util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) << _linePrefix << "Result after the optimiser:" << endl; - printIndented(_stream, printed, _linePrefix + " "); + printPrefixed(_stream, printed, _linePrefix + " "); return TestResult::FatalError; }