diff --git a/Changelog.md b/Changelog.md index 536837c71..1ae3b7c6f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Language Features: Compiler Features: * AST: Export NatSpec comments above each statement as their documentation. * Inline Assembly: Do not warn anymore about variables or functions being shadowed by EVM opcodes. + * NatSpec: Provide source locations for parsing errors. * Optimizer: Simple inlining when jumping to small blocks that jump again after a few side-effect free opcodes. diff --git a/liblangutil/ErrorReporter.cpp b/liblangutil/ErrorReporter.cpp index 820e60da8..5703d33b8 100644 --- a/liblangutil/ErrorReporter.cpp +++ b/liblangutil/ErrorReporter.cpp @@ -234,16 +234,6 @@ void ErrorReporter::fatalTypeError(ErrorId _error, SourceLocation const& _locati ); } -void ErrorReporter::docstringParsingError(ErrorId _error, string const& _description) -{ - error( - _error, - Error::Type::DocstringParsingError, - SourceLocation(), - _description - ); -} - void ErrorReporter::docstringParsingError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( diff --git a/liblangutil/ErrorReporter.h b/liblangutil/ErrorReporter.h index e533d7f6c..7cdce0caa 100644 --- a/liblangutil/ErrorReporter.h +++ b/liblangutil/ErrorReporter.h @@ -112,7 +112,6 @@ public: void fatalTypeError(ErrorId _error, SourceLocation const& _location, std::string const& _description); void fatalTypeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondLocation, std::string const& _description); - void docstringParsingError(ErrorId _error, std::string const& _description); void docstringParsingError(ErrorId _error, SourceLocation const& _location, std::string const& _description); ErrorList const& errors() const; diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index 9de1d8979..e8346f2fe 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -25,7 +25,6 @@ #include #include -#include #include using namespace std; diff --git a/libsolidity/analysis/DocStringTagParser.cpp b/libsolidity/analysis/DocStringTagParser.cpp index 02c22e9b8..99197c083 100644 --- a/libsolidity/analysis/DocStringTagParser.cpp +++ b/libsolidity/analysis/DocStringTagParser.cpp @@ -147,12 +147,10 @@ void DocStringTagParser::parseDocStrings( string const& _nodeName ) { - DocStringParser parser; - if (_node.documentation() && !_node.documentation()->text()->empty()) - { - parser.parse(*_node.documentation()->text(), m_errorReporter); - _annotation.docTags = parser.tags(); - } + if (!_node.documentation()) + return; + + _annotation.docTags = DocStringParser{*_node.documentation(), m_errorReporter}.parse(); size_t returnTagsVisited = 0; for (auto const& docTag: _annotation.docTags) diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index 314f04201..73da98b71 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -18,6 +18,8 @@ #include +#include + #include #include #include @@ -78,25 +80,26 @@ string::const_iterator skipWhitespace( } -void DocStringParser::parse(string const& _docString, ErrorReporter& _errorReporter) +multimap DocStringParser::parse() { - m_errorReporter = &_errorReporter; m_lastTag = nullptr; + m_docTags = {}; - auto currPos = _docString.begin(); - auto end = _docString.end(); + solAssert(m_node.text(), ""); + iter currPos = m_node.text()->begin(); + iter end = m_node.text()->end(); while (currPos != end) { - auto tagPos = find(currPos, end, '@'); - auto nlPos = find(currPos, end, '\n'); + iter tagPos = find(currPos, end, '@'); + iter nlPos = find(currPos, end, '\n'); if (tagPos != end && tagPos < nlPos) { // we found a tag - auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end); - auto tagName = string(tagPos + 1, tagNameEndPos); - auto tagDataPos = (tagNameEndPos != end) ? tagNameEndPos + 1 : tagNameEndPos; + iter tagNameEndPos = firstWhitespaceOrNewline(tagPos, end); + string tagName{tagPos + 1, tagNameEndPos}; + iter tagDataPos = (tagNameEndPos != end) ? tagNameEndPos + 1 : tagNameEndPos; currPos = parseDocTag(tagDataPos, end, tagName); } else if (!!m_lastTag) // continuation of the previous tag @@ -104,7 +107,7 @@ void DocStringParser::parse(string const& _docString, ErrorReporter& _errorRepor else if (currPos != end) { // if it begins without a tag then consider it as @notice - if (currPos == _docString.begin()) + if (currPos == m_node.text()->begin()) { currPos = parseDocTag(currPos, end, "notice"); continue; @@ -115,6 +118,7 @@ void DocStringParser::parse(string const& _docString, ErrorReporter& _errorRepor currPos = nlPos + 1; } } + return move(m_docTags); } DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, bool _appending) @@ -135,7 +139,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) auto nameStartPos = skipWhitespace(_pos, _end); if (nameStartPos == _end) { - m_errorReporter->docstringParsingError(3335_error, "No param name given"); + m_errorReporter.docstringParsingError(3335_error, m_node.location(), "No param name given"); return _end; } auto nameEndPos = firstNonIdentifier(nameStartPos, _end); @@ -146,7 +150,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) if (descStartPos == nlPos) { - m_errorReporter->docstringParsingError(9942_error, "No description given for param " + paramName); + m_errorReporter.docstringParsingError(9942_error, m_node.location(), "No description given for param " + paramName); return _end; } diff --git a/libsolidity/parsing/DocStringParser.h b/libsolidity/parsing/DocStringParser.h index 4b6d6b512..981ff12a4 100644 --- a/libsolidity/parsing/DocStringParser.h +++ b/libsolidity/parsing/DocStringParser.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include namespace solidity::langutil @@ -34,13 +35,17 @@ class ErrorReporter; namespace solidity::frontend { +class StructurallyDocumented; + class DocStringParser { public: - /// Parse the given @a _docString and stores the parsed components internally. - void parse(std::string const& _docString, langutil::ErrorReporter& _errorReporter); - - std::multimap const& tags() const { return m_docTags; } + /// @param _documentedNode the node whose documentation is parsed. + DocStringParser(StructuredDocumentation const& _documentedNode, langutil::ErrorReporter& _errorReporter): + m_node(_documentedNode), + m_errorReporter(_errorReporter) + {} + std::multimap parse(); private: using iter = std::string::const_iterator; @@ -58,10 +63,11 @@ private: /// Creates and inserts a new tag and adjusts m_lastTag. void newTag(std::string const& _tagName); + StructuredDocumentation const& m_node; + langutil::ErrorReporter& m_errorReporter; /// Mapping tag name -> content. std::multimap m_docTags; DocTag* m_lastTag = nullptr; - langutil::ErrorReporter* m_errorReporter = nullptr; }; } diff --git a/test/libsolidity/syntaxTests/natspec/docstring_empty_description.sol b/test/libsolidity/syntaxTests/natspec/docstring_empty_description.sol index 8a0b9bb38..e77e42c42 100644 --- a/test/libsolidity/syntaxTests/natspec/docstring_empty_description.sol +++ b/test/libsolidity/syntaxTests/natspec/docstring_empty_description.sol @@ -3,4 +3,4 @@ contract C { function vote(uint id) public {} } // ---- -// DocstringParsingError 9942: No description given for param id +// DocstringParsingError 9942: (17-30): No description given for param id diff --git a/test/libsolidity/syntaxTests/natspec/docstring_empty_tag.sol b/test/libsolidity/syntaxTests/natspec/docstring_empty_tag.sol index 5ab6b8260..56c3d59aa 100644 --- a/test/libsolidity/syntaxTests/natspec/docstring_empty_tag.sol +++ b/test/libsolidity/syntaxTests/natspec/docstring_empty_tag.sol @@ -3,4 +3,4 @@ abstract contract C { function vote(uint id) public {} } // ---- -// DocstringParsingError 3335: No param name given +// DocstringParsingError 3335: (26-36): No param name given