Browse Source

Changes in InterfaceHandler to deal with multiline natspec

- Also now Solidity scanner considers Carriage Return as whitespace
- Tests for Natspec generation with the new multiline comments
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
30beaca359
  1. 46
      libsolidity/InterfaceHandler.cpp
  2. 3
      libsolidity/InterfaceHandler.h
  3. 2
      libsolidity/Scanner.cpp
  4. 29
      test/solidityNatspecJSON.cpp

46
libsolidity/InterfaceHandler.cpp

@ -166,9 +166,12 @@ static inline std::string::const_iterator skipLineOrEOS(std::string::const_itera
std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos,
std::string::const_iterator _end, std::string::const_iterator _end,
std::string& _tagString, std::string& _tagString,
DocTagType _tagType) DocTagType _tagType,
bool _appending)
{ {
auto nlPos = std::find(_pos, _end, '\n'); auto nlPos = std::find(_pos, _end, '\n');
if (_appending && *_pos != ' ')
_tagString += " ";
std::copy(_pos, nlPos, back_inserter(_tagString)); std::copy(_pos, nlPos, back_inserter(_tagString));
m_lastTag = _tagType; m_lastTag = _tagType;
return skipLineOrEOS(nlPos, _end); return skipLineOrEOS(nlPos, _end);
@ -201,7 +204,8 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con
solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter"); solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter");
auto pair = m_params.back(); auto pair = m_params.back();
pair.second += " "; if (*_pos != ' ')
pair.second += " ";
auto nlPos = std::find(_pos, _end, '\n'); auto nlPos = std::find(_pos, _end, '\n');
std::copy(_pos, nlPos, back_inserter(pair.second)); std::copy(_pos, nlPos, back_inserter(pair.second));
@ -221,17 +225,17 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite
if (m_lastTag == DocTagType::NONE || _tag != "") if (m_lastTag == DocTagType::NONE || _tag != "")
{ {
if (_tag == "dev") if (_tag == "dev")
return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV); return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV, false);
else if (_tag == "notice") else if (_tag == "notice")
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE); return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE, false);
else if (_tag == "return") else if (_tag == "return")
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN); return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN, false);
else if (_tag == "author") else if (_tag == "author")
{ {
if (_owner == CommentOwner::CONTRACT) if (_owner == CommentOwner::CONTRACT)
return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR); return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR, false);
else if (_owner == CommentOwner::FUNCTION) else if (_owner == CommentOwner::FUNCTION)
return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR); return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR, false);
else else
// LTODO: for now this else makes no sense but later comments will go to more language constructs // LTODO: for now this else makes no sense but later comments will go to more language constructs
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts")); BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts"));
@ -239,7 +243,7 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite
else if (_tag == "title") else if (_tag == "title")
{ {
if (_owner == CommentOwner::CONTRACT) if (_owner == CommentOwner::CONTRACT)
return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE); return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE, false);
else else
// LTODO: Unknown tag, throw some form of warning and not just an exception // LTODO: Unknown tag, throw some form of warning and not just an exception
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts")); BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts"));
@ -261,34 +265,22 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it
switch (m_lastTag) switch (m_lastTag)
{ {
case DocTagType::DEV: case DocTagType::DEV:
m_dev += " "; return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV, true);
return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
case DocTagType::NOTICE: case DocTagType::NOTICE:
m_notice += " "; return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE, true);
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
case DocTagType::RETURN: case DocTagType::RETURN:
m_return += " "; return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN, true);
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
case DocTagType::AUTHOR: case DocTagType::AUTHOR:
if (_owner == CommentOwner::CONTRACT) if (_owner == CommentOwner::CONTRACT)
{ return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR, true);
m_contractAuthor += " ";
return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR);
}
else if (_owner == CommentOwner::FUNCTION) else if (_owner == CommentOwner::FUNCTION)
{ return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR, true);
m_author += " ";
return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR);
}
else else
// LTODO: Unknown tag, throw some form of warning and not just an exception // LTODO: Unknown tag, throw some form of warning and not just an exception
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment")); BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment"));
case DocTagType::TITLE: case DocTagType::TITLE:
if (_owner == CommentOwner::CONTRACT) if (_owner == CommentOwner::CONTRACT)
{ return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE, true);
m_title += " ";
return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE);
}
else else
// LTODO: Unknown tag, throw some form of warning and not just an exception // LTODO: Unknown tag, throw some form of warning and not just an exception
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment")); BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment"));
@ -329,7 +321,7 @@ void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _
currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner); currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner);
} }
else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag
currPos = appendDocTag(currPos + 1, end, _owner); currPos = appendDocTag(currPos, end, _owner);
else if (currPos != end) // skip the line if a newline was found else if (currPos != end) // skip the line if a newline was found
currPos = nlPos + 1; currPos = nlPos + 1;
} }

3
libsolidity/InterfaceHandler.h

@ -92,7 +92,8 @@ private:
std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos,
std::string::const_iterator _end, std::string::const_iterator _end,
std::string& _tagString, std::string& _tagString,
DocTagType _tagType); DocTagType _tagType,
bool _appending);
std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end); std::string::const_iterator _end);
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos,

2
libsolidity/Scanner.cpp

@ -80,7 +80,7 @@ bool isLineTerminator(char c)
} }
bool isWhiteSpace(char c) bool isWhiteSpace(char c)
{ {
return c == ' ' || c == '\n' || c == '\t'; return c == ' ' || c == '\n' || c == '\t' || c == '\r';
} }
bool isIdentifierStart(char c) bool isIdentifierStart(char c)
{ {

29
test/solidityNatspecJSON.cpp

@ -394,6 +394,35 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return)
checkNatspec(sourceCode, natspec, false); checkNatspec(sourceCode, natspec, false);
} }
BOOST_AUTO_TEST_CASE(dev_multiline_comment)
{
char const* sourceCode = "contract test {\n"
" /**\n"
" * @dev Multiplies a number by 7 and adds second parameter\n"
" * @param a Documentation for the first parameter starts here.\n"
" * Since it's a really complicated parameter we need 2 lines\n"
" * @param second Documentation for the second parameter\n"
" * @return The result of the multiplication\n"
" * and cookies with nutella\n"
" */"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \n"
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
" \"params\": {\n"
" \"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 and cookies with nutella\"\n"
" }\n"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_contract_no_doc) BOOST_AUTO_TEST_CASE(dev_contract_no_doc)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"

Loading…
Cancel
Save