Skip to content

Commit 354f9d1

Browse files
committed
Fix: Allow multiple @return tags on public state variables
1 parent aae9d34 commit 354f9d1

File tree

4 files changed

+97
-27
lines changed

4 files changed

+97
-27
lines changed

Changelog.md

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

libsolidity/analysis/DocStringTagParser.cpp

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ bool DocStringTagParser::parseDocStrings(SourceUnit const& _sourceUnit)
4949

5050
bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceUnit)
5151
{
52-
auto errorWatcher = m_errorReporter.errorWatcher();
52+
ErrorReporter::ErrorWatcher errorWatcher = m_errorReporter.errorWatcher();
5353

5454
SimpleASTVisitor visitReturns(
5555
[](ASTNode const&) { return true; },
@@ -65,39 +65,41 @@ bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceU
6565
if (tagName == "return")
6666
{
6767
returnTagsVisited++;
68+
vector<string> returnParameterNames;
69+
6870
if (auto const* varDecl = dynamic_cast<VariableDeclaration const*>(&_node))
6971
{
70-
solAssert(varDecl->isPublic(), "@return is only allowed on public state-variables.");
71-
if (returnTagsVisited > 1)
72-
m_errorReporter.docstringParsingError(
73-
5256_error,
74-
documentationNode.documentation()->location(),
75-
"Documentation tag \"@" + tagName + "\" is only allowed once on state-variables."
76-
);
72+
if (!varDecl->isPublic())
73+
continue;
74+
75+
// FunctionType() requires the DeclarationTypeChecker to have run.
76+
returnParameterNames = FunctionType(*varDecl).returnParameterNames();
7777
}
7878
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_node))
79+
returnParameterNames = FunctionType(*function).returnParameterNames();
80+
else
81+
continue;
82+
83+
string content = tagValue.content;
84+
string firstWord = content.substr(0, content.find_first_of(" \t"));
85+
86+
if (returnTagsVisited > returnParameterNames.size())
87+
m_errorReporter.docstringParsingError(
88+
2604_error,
89+
documentationNode.documentation()->location(),
90+
"Documentation tag \"@" + tagName + " " + content + "\"" +
91+
" exceeds the number of return parameters."
92+
);
93+
else
7994
{
80-
string content = tagValue.content;
81-
string firstWord = content.substr(0, content.find_first_of(" \t"));
82-
83-
if (returnTagsVisited > function->returnParameters().size())
95+
string const& parameter = returnParameterNames.at(returnTagsVisited - 1);
96+
if (!parameter.empty() && parameter != firstWord)
8497
m_errorReporter.docstringParsingError(
85-
2604_error,
98+
5856_error,
8699
documentationNode.documentation()->location(),
87-
"Documentation tag \"@" + tagName + " " + tagValue.content + "\"" +
88-
" exceeds the number of return parameters."
100+
"Documentation tag \"@" + tagName + " " + content + "\"" +
101+
" does not contain the name of its return parameter."
89102
);
90-
else
91-
{
92-
auto parameter = function->returnParameters().at(returnTagsVisited - 1);
93-
if (!parameter->name().empty() && parameter->name() != firstWord)
94-
m_errorReporter.docstringParsingError(
95-
5856_error,
96-
documentationNode.documentation()->location(),
97-
"Documentation tag \"@" + tagName + " " + tagValue.content + "\"" +
98-
" does not contain the name of its return parameter."
99-
);
100-
}
101103
}
102104
}
103105
}

test/libsolidity/SolidityNatspecJSON.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,73 @@ BOOST_AUTO_TEST_CASE(public_state_variable)
328328
checkNatspec(sourceCode, "test", userDoc, true);
329329
}
330330

331+
BOOST_AUTO_TEST_CASE(public_state_variable_struct)
332+
{
333+
char const* sourceCode = R"(
334+
contract Bank {
335+
struct Coin {
336+
string observeGraphicURL;
337+
string reverseGraphicURL;
338+
}
339+
340+
/// @notice Get the n-th coin I own
341+
/// @return observeGraphicURL Front pic
342+
/// @return reverseGraphicURL Back pic
343+
Coin[] public coinStack;
344+
}
345+
)";
346+
347+
char const* devDoc = R"R(
348+
{
349+
"methods" : {},
350+
"stateVariables" :
351+
{
352+
"coinStack" :
353+
{
354+
"returns" :
355+
{
356+
"observeGraphicURL" : "Front pic",
357+
"reverseGraphicURL" : "Back pic"
358+
}
359+
}
360+
}
361+
}
362+
)R";
363+
checkNatspec(sourceCode, "Bank", devDoc, false);
364+
365+
char const* userDoc = R"R(
366+
{
367+
"methods" :
368+
{
369+
"coinStack(uint256)" :
370+
{
371+
"notice": "Get the n-th coin I own"
372+
}
373+
}
374+
}
375+
)R";
376+
checkNatspec(sourceCode, "Bank", userDoc, true);
377+
}
378+
379+
BOOST_AUTO_TEST_CASE(public_state_variable_struct_repeated)
380+
{
381+
char const* sourceCode = R"(
382+
contract Bank {
383+
struct Coin {
384+
string obverseGraphicURL;
385+
string reverseGraphicURL;
386+
}
387+
388+
/// @notice Get the n-th coin I own
389+
/// @return obverseGraphicURL Front pic
390+
/// @return obverseGraphicURL Front pic
391+
Coin[] public coinStack;
392+
}
393+
)";
394+
395+
expectNatspecError(sourceCode);
396+
}
397+
331398
BOOST_AUTO_TEST_CASE(private_state_variable)
332399
{
333400
char const* sourceCode = R"(

test/libsolidity/syntaxTests/natspec/docstring_state_variable_too_many_return_tags.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ contract test {
66
uint public state;
77
}
88
// ----
9-
// DocstringParsingError 5256: (18-137): Documentation tag "@return" is only allowed once on state-variables.
9+
// DocstringParsingError 2604: (18-137): Documentation tag "@return returns something" exceeds the number of return parameters.

0 commit comments

Comments
 (0)