Fix: Allow multiple @return tags on public state variables

This commit is contained in:
Mathias Baumann 2021-05-26 17:37:49 +02:00
parent aae9d347aa
commit 354f9d1015
4 changed files with 97 additions and 27 deletions

View File

@ -20,6 +20,7 @@ Bugfixes:
* Code Generator: Fix internal error when super would have to skip an unimplemented function in the virtual resolution order. * Code Generator: Fix internal error when super would have to skip an unimplemented function in the virtual resolution order.
* Control Flow Graph: Take internal calls to functions that always revert into account for reporting unused or unassigned variables. * Control Flow Graph: Take internal calls to functions that always revert into account for reporting unused or unassigned variables.
* Control Flow Graph: Assume unimplemented modifiers use a placeholder. * Control Flow Graph: Assume unimplemented modifiers use a placeholder.
* Natspec: Allow multiple ``@return`` tags on public state variable documentation.
* SMTChecker: Fix internal error on struct constructor with fixed bytes member initialized with string literal. * SMTChecker: Fix internal error on struct constructor with fixed bytes member initialized with string literal.
* SMTChecker: Fix internal error on external calls from the constructor. * SMTChecker: Fix internal error on external calls from the constructor.
* SMTChecker: Fix internal error on conversion from ``bytes`` to ``fixed bytes``. * SMTChecker: Fix internal error on conversion from ``bytes`` to ``fixed bytes``.

View File

@ -49,7 +49,7 @@ bool DocStringTagParser::parseDocStrings(SourceUnit const& _sourceUnit)
bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceUnit) bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceUnit)
{ {
auto errorWatcher = m_errorReporter.errorWatcher(); ErrorReporter::ErrorWatcher errorWatcher = m_errorReporter.errorWatcher();
SimpleASTVisitor visitReturns( SimpleASTVisitor visitReturns(
[](ASTNode const&) { return true; }, [](ASTNode const&) { return true; },
@ -65,39 +65,41 @@ bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceU
if (tagName == "return") if (tagName == "return")
{ {
returnTagsVisited++; returnTagsVisited++;
vector<string> returnParameterNames;
if (auto const* varDecl = dynamic_cast<VariableDeclaration const*>(&_node)) if (auto const* varDecl = dynamic_cast<VariableDeclaration const*>(&_node))
{ {
solAssert(varDecl->isPublic(), "@return is only allowed on public state-variables."); if (!varDecl->isPublic())
if (returnTagsVisited > 1) continue;
m_errorReporter.docstringParsingError(
5256_error, // FunctionType() requires the DeclarationTypeChecker to have run.
documentationNode.documentation()->location(), returnParameterNames = FunctionType(*varDecl).returnParameterNames();
"Documentation tag \"@" + tagName + "\" is only allowed once on state-variables."
);
} }
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_node)) else if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_node))
{ returnParameterNames = FunctionType(*function).returnParameterNames();
string content = tagValue.content; else
string firstWord = content.substr(0, content.find_first_of(" \t")); continue;
if (returnTagsVisited > function->returnParameters().size()) string content = tagValue.content;
string firstWord = content.substr(0, content.find_first_of(" \t"));
if (returnTagsVisited > returnParameterNames.size())
m_errorReporter.docstringParsingError(
2604_error,
documentationNode.documentation()->location(),
"Documentation tag \"@" + tagName + " " + content + "\"" +
" exceeds the number of return parameters."
);
else
{
string const& parameter = returnParameterNames.at(returnTagsVisited - 1);
if (!parameter.empty() && parameter != firstWord)
m_errorReporter.docstringParsingError( m_errorReporter.docstringParsingError(
2604_error, 5856_error,
documentationNode.documentation()->location(), documentationNode.documentation()->location(),
"Documentation tag \"@" + tagName + " " + tagValue.content + "\"" + "Documentation tag \"@" + tagName + " " + content + "\"" +
" exceeds the number of return parameters." " does not contain the name of its return parameter."
); );
else
{
auto parameter = function->returnParameters().at(returnTagsVisited - 1);
if (!parameter->name().empty() && parameter->name() != firstWord)
m_errorReporter.docstringParsingError(
5856_error,
documentationNode.documentation()->location(),
"Documentation tag \"@" + tagName + " " + tagValue.content + "\"" +
" does not contain the name of its return parameter."
);
}
} }
} }
} }

View File

@ -328,6 +328,73 @@ BOOST_AUTO_TEST_CASE(public_state_variable)
checkNatspec(sourceCode, "test", userDoc, true); checkNatspec(sourceCode, "test", userDoc, true);
} }
BOOST_AUTO_TEST_CASE(public_state_variable_struct)
{
char const* sourceCode = R"(
contract Bank {
struct Coin {
string observeGraphicURL;
string reverseGraphicURL;
}
/// @notice Get the n-th coin I own
/// @return observeGraphicURL Front pic
/// @return reverseGraphicURL Back pic
Coin[] public coinStack;
}
)";
char const* devDoc = R"R(
{
"methods" : {},
"stateVariables" :
{
"coinStack" :
{
"returns" :
{
"observeGraphicURL" : "Front pic",
"reverseGraphicURL" : "Back pic"
}
}
}
}
)R";
checkNatspec(sourceCode, "Bank", devDoc, false);
char const* userDoc = R"R(
{
"methods" :
{
"coinStack(uint256)" :
{
"notice": "Get the n-th coin I own"
}
}
}
)R";
checkNatspec(sourceCode, "Bank", userDoc, true);
}
BOOST_AUTO_TEST_CASE(public_state_variable_struct_repeated)
{
char const* sourceCode = R"(
contract Bank {
struct Coin {
string obverseGraphicURL;
string reverseGraphicURL;
}
/// @notice Get the n-th coin I own
/// @return obverseGraphicURL Front pic
/// @return obverseGraphicURL Front pic
Coin[] public coinStack;
}
)";
expectNatspecError(sourceCode);
}
BOOST_AUTO_TEST_CASE(private_state_variable) BOOST_AUTO_TEST_CASE(private_state_variable)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

View File

@ -6,4 +6,4 @@ contract test {
uint public state; uint public state;
} }
// ---- // ----
// DocstringParsingError 5256: (18-137): Documentation tag "@return" is only allowed once on state-variables. // DocstringParsingError 2604: (18-137): Documentation tag "@return returns something" exceeds the number of return parameters.