From 5738e865d5375751332d8f884f2b00b006d76945 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 30 Nov 2016 15:04:07 +0100 Subject: Accept any kind of whitespace after natspec tags --- libsolidity/parsing/DocStringParser.cpp | 60 +++++++++++++++++++++++++------- test/libsolidity/SolidityNatspecJSON.cpp | 23 ++++++++++++ 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index bbee35f5..4c59c47c 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -16,16 +16,39 @@ static inline string::const_iterator skipLineOrEOS( return (_nlPos == _end) ? _end : ++_nlPos; } -static inline string::const_iterator firstSpaceOrNl( +static inline string::const_iterator firstSpaceOrTab( string::const_iterator _pos, string::const_iterator _end ) { auto spacePos = find(_pos, _end, ' '); - auto nlPos = find(_pos, _end, '\n'); - return (spacePos < nlPos) ? spacePos : nlPos; + auto tabPos = find(_pos, _end, '\t'); + return (spacePos < tabPos) ? spacePos : tabPos; } +static inline string::const_iterator firstWsOrNl( + string::const_iterator _pos, + string::const_iterator _end +) +{ + auto wsPos = firstSpaceOrTab(_pos, _end); + auto nlPos = find(wsPos, _end, '\n'); + return (wsPos < nlPos) ? wsPos : nlPos; +} + + +static inline string::const_iterator skipWhitespace( + string::const_iterator _pos, + string::const_iterator _end +) +{ + auto currPos = _pos; + while ((*currPos == ' ' || *currPos == '\t') && currPos != _end) + currPos += 1; + return currPos; +} + + bool DocStringParser::parse(string const& _docString, ErrorList& _errors) { m_errors = &_errors; @@ -43,7 +66,7 @@ bool DocStringParser::parse(string const& _docString, ErrorList& _errors) if (tagPos != end && tagPos < nlPos) { // we found a tag - auto tagNameEndPos = firstSpaceOrNl(tagPos, end); + auto tagNameEndPos = firstWsOrNl(tagPos, end); if (tagNameEndPos == end) { appendError("End of tag " + string(tagPos, tagNameEndPos) + "not found"); @@ -75,7 +98,7 @@ DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, boo { solAssert(!!m_lastTag, ""); auto nlPos = find(_pos, _end, '\n'); - if (_appending && _pos < _end && *_pos != ' ') + if (_appending && _pos < _end && *_pos != ' ' && *_pos != '\t') m_lastTag->content += " "; copy(_pos, nlPos, back_inserter(m_lastTag->content)); return skipLineOrEOS(nlPos, _end); @@ -83,19 +106,30 @@ DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, boo DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) { - // find param name - auto currPos = find(_pos, _end, ' '); - if (currPos == _end) + // find param name start + auto nameStartPos = skipWhitespace(_pos, _end); + if (nameStartPos == _end) + { + appendError("No param name given" + string(nameStartPos, _end)); + return _end; + } + auto nameEndPos = firstSpaceOrTab(nameStartPos, _end); + if (nameEndPos == _end) { - appendError("End of param name not found" + string(_pos, _end)); + appendError("End of param name not found" + string(nameStartPos, _end)); return _end; } + auto paramName = string(nameStartPos, nameEndPos); - auto paramName = string(_pos, currPos); + auto descStartPos = skipWhitespace(nameEndPos, _end); + if (descStartPos == _end) + { + appendError("No description given for param" + paramName); + return _end; + } - currPos += 1; - auto nlPos = find(currPos, _end, '\n'); - auto paramDesc = string(currPos, nlPos); + auto nlPos = find(descStartPos, _end, '\n'); + auto paramDesc = string(descStartPos, nlPos); newTag("param"); m_lastTag->paramName = paramName; m_lastTag->content = paramDesc; diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index e32264c4..c59b30c3 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -251,6 +251,29 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params) checkNatspec(sourceCode, natspec, false); } +BOOST_AUTO_TEST_CASE(dev_multiple_params_mixed_whitespace) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter\n" + " /// @param second Documentation for the second parameter\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul(uint256,uint256)\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " }\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) { char const* sourceCode = R"( -- cgit From 9ca0fde853735d183c3db5c77c83de7c70c4ec98 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 1 Dec 2016 10:14:19 +0100 Subject: Fix and better output for tests --- libsolidity/parsing/DocStringParser.cpp | 6 ++++++ test/libsolidity/SolidityNatspecJSON.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index 4c59c47c..5d9a75ef 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -99,7 +99,13 @@ DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, boo solAssert(!!m_lastTag, ""); auto nlPos = find(_pos, _end, '\n'); if (_appending && _pos < _end && *_pos != ' ' && *_pos != '\t') + { m_lastTag->content += " "; + } + else if (!_appending) + { + _pos = skipWhitespace(_pos, _end); + } copy(_pos, nlPos, back_inserter(m_lastTag->content)); return skipLineOrEOS(nlPos, _end); } diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index c59b30c3..0657c321 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -56,7 +56,7 @@ public: m_reader.parse(_expectedDocumentationString, expectedDocumentation); BOOST_CHECK_MESSAGE( expectedDocumentation == generatedDocumentation, - "Expected " << expectedDocumentation.toStyledString() << + "Expected:\n" << expectedDocumentation.toStyledString() << "\n but got:\n" << generatedDocumentation.toStyledString() ); } -- cgit From cc7834f2a96e305bba3c7470271560dbf99d17f9 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 27 Jan 2017 00:00:05 +0100 Subject: Doc tags followed by newline are now parsed properly --- libsolidity/parsing/DocStringParser.cpp | 2 +- test/libsolidity/SolidityNatspecJSON.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index 5d9a75ef..481a3349 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -31,8 +31,8 @@ static inline string::const_iterator firstWsOrNl( string::const_iterator _end ) { + auto nlPos = find(_pos, _end, '\n'); auto wsPos = firstSpaceOrTab(_pos, _end); - auto nlPos = find(wsPos, _end, '\n'); return (wsPos < nlPos) ? wsPos : nlPos; } diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 0657c321..42b989dd 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(dev_desc_after_nl) char const* natspec = "{" "\"methods\":{" " \"mul(uint256,uint256)\":{ \n" - " \"details\": \" Multiplies a number by 7 and adds second parameter\",\n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" " \"second\": \"Documentation for the second parameter\"\n" @@ -402,7 +402,7 @@ BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" " \"second\": \"Documentation for the second parameter\"\n" " },\n" - " \"return\": \" The result of the multiplication\"\n" + " \"return\": \"The result of the multiplication\"\n" " }\n" "}}"; -- cgit From 98b51b378e42ba67d727c0d2245314cdaab2fd53 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 27 Jan 2017 00:09:00 +0100 Subject: More verbose function naming --- libsolidity/parsing/DocStringParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index 481a3349..c2af82de 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -26,7 +26,7 @@ static inline string::const_iterator firstSpaceOrTab( return (spacePos < tabPos) ? spacePos : tabPos; } -static inline string::const_iterator firstWsOrNl( +static inline string::const_iterator firstWhitespaceOrNewline( string::const_iterator _pos, string::const_iterator _end ) @@ -66,7 +66,7 @@ bool DocStringParser::parse(string const& _docString, ErrorList& _errors) if (tagPos != end && tagPos < nlPos) { // we found a tag - auto tagNameEndPos = firstWsOrNl(tagPos, end); + auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end); if (tagNameEndPos == end) { appendError("End of tag " + string(tagPos, tagNameEndPos) + "not found"); -- cgit From 0e021e76a58d0ae7a7fe1647f079e7e5087b4641 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 27 Jan 2017 11:19:48 +0100 Subject: Minor changes. --- libsolidity/parsing/DocStringParser.cpp | 36 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index c2af82de..8e912126 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -1,14 +1,19 @@ #include -#include #include +#include +#include + using namespace std; using namespace dev; using namespace dev::solidity; -static inline string::const_iterator skipLineOrEOS( +namespace +{ + +string::const_iterator skipLineOrEOS( string::const_iterator _nlPos, string::const_iterator _end ) @@ -16,38 +21,35 @@ static inline string::const_iterator skipLineOrEOS( return (_nlPos == _end) ? _end : ++_nlPos; } -static inline string::const_iterator firstSpaceOrTab( +string::const_iterator firstSpaceOrTab( string::const_iterator _pos, string::const_iterator _end ) { - auto spacePos = find(_pos, _end, ' '); - auto tabPos = find(_pos, _end, '\t'); - return (spacePos < tabPos) ? spacePos : tabPos; + return boost::range::find_first_of(make_pair(_pos, _end), " \t"); } -static inline string::const_iterator firstWhitespaceOrNewline( +string::const_iterator firstWhitespaceOrNewline( string::const_iterator _pos, string::const_iterator _end ) { - auto nlPos = find(_pos, _end, '\n'); - auto wsPos = firstSpaceOrTab(_pos, _end); - return (wsPos < nlPos) ? wsPos : nlPos; + return boost::range::find_first_of(make_pair(_pos, _end), " \t\n"); } -static inline string::const_iterator skipWhitespace( +string::const_iterator skipWhitespace( string::const_iterator _pos, string::const_iterator _end ) { auto currPos = _pos; - while ((*currPos == ' ' || *currPos == '\t') && currPos != _end) + while (currPos != _end && (*currPos == ' ' || *currPos == '\t')) currPos += 1; return currPos; } +} bool DocStringParser::parse(string const& _docString, ErrorList& _errors) { @@ -99,13 +101,9 @@ DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, boo solAssert(!!m_lastTag, ""); auto nlPos = find(_pos, _end, '\n'); if (_appending && _pos < _end && *_pos != ' ' && *_pos != '\t') - { m_lastTag->content += " "; - } else if (!_appending) - { _pos = skipWhitespace(_pos, _end); - } copy(_pos, nlPos, back_inserter(m_lastTag->content)); return skipLineOrEOS(nlPos, _end); } @@ -116,13 +114,13 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) auto nameStartPos = skipWhitespace(_pos, _end); if (nameStartPos == _end) { - appendError("No param name given" + string(nameStartPos, _end)); + appendError("No param name given"); return _end; } auto nameEndPos = firstSpaceOrTab(nameStartPos, _end); if (nameEndPos == _end) { - appendError("End of param name not found" + string(nameStartPos, _end)); + appendError("End of param name not found: " + string(nameStartPos, _end)); return _end; } auto paramName = string(nameStartPos, nameEndPos); @@ -130,7 +128,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) auto descStartPos = skipWhitespace(nameEndPos, _end); if (descStartPos == _end) { - appendError("No description given for param" + paramName); + appendError("No description given for param " + paramName); return _end; } -- cgit From f01c8c07e5647e02a45ad0802578153c7273668a Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 27 Jan 2017 12:13:14 +0100 Subject: Tests for natspect parsing failure cases --- test/libsolidity/SolidityNatspecJSON.cpp | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 42b989dd..ac55382b 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -635,6 +635,48 @@ BOOST_AUTO_TEST_CASE(dev_documenting_nonexistent_param) expectNatspecError(sourceCode); } +BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname) +{ + char const* sourceCode = R"( + contract test { + /// @dev Multiplies a number by 7 and adds second parameter + /// @param a Documentation for the first parameter + /// @param + function mul(uint a, uint second) returns(uint d) { return a * 7 + second; } + } + )"; + + expectNatspecError(sourceCode); +} + +BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname_end) +{ + char const* sourceCode = R"( + contract test { + /// @dev Multiplies a number by 7 and adds second parameter + /// @param a Documentation for the first parameter + /// @param se + function mul(uint a, uint second) returns(uint d) { return a * 7 + second; } + } + )"; + + expectNatspecError(sourceCode); +} + +BOOST_AUTO_TEST_CASE(dev_documenting_no_param_description) +{ + char const* sourceCode = R"( + contract test { + /// @dev Multiplies a number by 7 and adds second parameter + /// @param a Documentation for the first parameter + /// @param second + function mul(uint a, uint second) returns(uint d) { return a * 7 + second; } + } + )"; + + expectNatspecError(sourceCode); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit From c08f659634b5808a1283861939053df2584cab7d Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 27 Jan 2017 14:09:19 +0100 Subject: Changelog entry. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 7dd607d8..4edf76f0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Features: Bugfixes: * Code generator: Allow recursive structs. * Type checker: Allow multiple events of the same name (but with different arities or argument types) + * Natspec parser: Fix error with ``@param`` parsing and whitespace. ### 0.4.8 (2017-01-13) -- cgit