diff --git a/liblangutil/SourceReferenceFormatterHuman.cpp b/liblangutil/SourceReferenceFormatterHuman.cpp index cbf24cf35..b8fdba163 100644 --- a/liblangutil/SourceReferenceFormatterHuman.cpp +++ b/liblangutil/SourceReferenceFormatterHuman.cpp @@ -23,6 +23,7 @@ #include #include #include +#include using namespace std; using namespace solidity; @@ -30,6 +31,20 @@ using namespace solidity::langutil; using namespace solidity::util; using namespace solidity::util::formatting; +namespace +{ + +std::string replaceNonTabs(std::string_view _utf8Input, char _filler) +{ + std::string output; + for (char const c: _utf8Input) + if ((c & 0xc0) != 0x80) + output.push_back(c == '\t' ? '\t' : _filler); + return output; +} + +} + AnsiColorized SourceReferenceFormatterHuman::normalColored() const { return AnsiColorized(m_stream, m_colored, {WHITE}); @@ -85,6 +100,8 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _ frameColored() << "-->"; m_stream << ' ' << _ref.sourceName << ':' << line << ':' << (_ref.position.column + 1) << ":\n"; + string_view text = _ref.text; + if (!_ref.multiline) { int const locationLength = _ref.endColumn - _ref.startColumn; @@ -96,21 +113,15 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _ // line 2: frameColored() << line << " |"; - m_stream << ' ' << _ref.text.substr(0, _ref.startColumn); - highlightColored() << _ref.text.substr(_ref.startColumn, locationLength); - m_stream << _ref.text.substr(_ref.endColumn) << '\n'; + m_stream << ' ' << text.substr(0, _ref.startColumn); + highlightColored() << text.substr(_ref.startColumn, locationLength); + m_stream << text.substr(_ref.endColumn) << '\n'; // line 3: m_stream << leftpad << ' '; frameColored() << '|'; - m_stream << ' '; - - for_each( - _ref.text.cbegin(), - _ref.text.cbegin() + numCodepoints(_ref.text.substr(0, _ref.startColumn)), - [this](char ch) { m_stream << (ch == '\t' ? '\t' : ' '); } - ); - diagColored() << string(numCodepoints(_ref.text.substr(_ref.startColumn, locationLength)), '^'); + m_stream << ' ' << replaceNonTabs(text.substr(0, _ref.startColumn), ' '); + diagColored() << replaceNonTabs(text.substr(_ref.startColumn, locationLength), '^'); m_stream << '\n'; } else @@ -122,13 +133,13 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _ // line 2: frameColored() << line << " |"; - m_stream << ' ' << _ref.text.substr(0, _ref.startColumn); - highlightColored() << _ref.text.substr(_ref.startColumn) << '\n'; + m_stream << ' ' << text.substr(0, _ref.startColumn); + highlightColored() << text.substr(_ref.startColumn) << '\n'; // line 3: m_stream << leftpad << ' '; frameColored() << '|'; - m_stream << ' ' << string(_ref.startColumn, ' '); + m_stream << ' ' << replaceNonTabs(text.substr(0, _ref.startColumn), ' '); diagColored() << "^ (Relevant source part starts here and spans across multiple lines)."; m_stream << '\n'; } diff --git a/libsolutil/UTF8.cpp b/libsolutil/UTF8.cpp index 82c87bb44..a7d55af6c 100644 --- a/libsolutil/UTF8.cpp +++ b/libsolutil/UTF8.cpp @@ -138,13 +138,4 @@ bool validateUTF8(std::string const& _input, size_t& _invalidPosition) return validateUTF8(reinterpret_cast(_input.c_str()), _input.length(), _invalidPosition); } -size_t numCodepoints(std::string const& _utf8EncodedInput) -{ - size_t codepoint = 0; - for (char c: _utf8EncodedInput) - codepoint += (c & 0xc0) != 0x80; - - return codepoint; -} - } diff --git a/libsolutil/UTF8.h b/libsolutil/UTF8.h index fb5ee376c..cd84c3982 100644 --- a/libsolutil/UTF8.h +++ b/libsolutil/UTF8.h @@ -38,6 +38,4 @@ inline bool validateUTF8(std::string const& _input) return validateUTF8(_input, invalidPos); } -size_t numCodepoints(std::string const& _utf8EncodedInput); - } diff --git a/test/cmdlineTests/message_format_utf16/err b/test/cmdlineTests/message_format_utf16/err deleted file mode 100644 index abe92d2e5..000000000 --- a/test/cmdlineTests/message_format_utf16/err +++ /dev/null @@ -1,11 +0,0 @@ -Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. ---> message_format_utf16/input.sol - -Warning: Source file does not specify required compiler version! ---> message_format_utf16/input.sol - -Warning: Statement has no effect. - --> message_format_utf16/input.sol:2:58: - | -2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; } - | ^^^^^^^^^^^^ diff --git a/test/cmdlineTests/message_format_utf16/input.sol b/test/cmdlineTests/message_format_utf16/input.sol deleted file mode 100644 index 2c1f9007a..000000000 --- a/test/cmdlineTests/message_format_utf16/input.sol +++ /dev/null @@ -1,3 +0,0 @@ -contract Foo { -/* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; } -} diff --git a/test/cmdlineTests/message_format_utf8/err b/test/cmdlineTests/message_format_utf8/err new file mode 100644 index 000000000..fcd1717b8 --- /dev/null +++ b/test/cmdlineTests/message_format_utf8/err @@ -0,0 +1,35 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> message_format_utf8/input.sol + +Warning: Source file does not specify required compiler version! +--> message_format_utf8/input.sol + +Warning: Statement has no effect. + --> message_format_utf8/input.sol:2:58: + | +2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; } + | ^^^^^^^^^^^^ + +Warning: Statement has no effect. + --> message_format_utf8/input.sol:6:25: + | +6 | "S = π × r²"; + | ^^^^^^^^^^^^ + +Warning: Statement has no effect. + --> message_format_utf8/input.sol:7:39: + | +7 | /* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ "∑ 1/n! ≈ 2.7"; // tabs in-between + | ^^^^^^^^^^^^^^ + +Warning: Statement has no effect. + --> message_format_utf8/input.sol:8:30: + | +8 | /* Ŀŏŗėɯ ïƥŝʉɱ */ "μὴ χεῖρον βέλτιστον"; // tabs in-between and inside + | ^^^ ^^^^^^ ^^^^^^^^^^ + +Warning: Function state mutability can be restricted to pure + --> message_format_utf8/input.sol:12:2: + | +12 | function selector() public returns(uint) { // starts with tab + | ^ (Relevant source part starts here and spans across multiple lines). diff --git a/test/cmdlineTests/message_format_utf8/input.sol b/test/cmdlineTests/message_format_utf8/input.sol new file mode 100644 index 000000000..51585efde --- /dev/null +++ b/test/cmdlineTests/message_format_utf8/input.sol @@ -0,0 +1,15 @@ +contract Foo { +/* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; } + + function f() public pure { + + "S = π × r²"; +/* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ "∑ 1/n! ≈ 2.7"; // tabs in-between +/* Ŀŏŗėɯ ïƥŝʉɱ */ "μὴ χεῖρον βέλτιστον"; // tabs in-between and inside + + } + + function selector() public returns(uint) { // starts with tab + return 0; + } +}