mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Adds structured docs for variable declarations.
- adds natspec generation for state variables. - exports structured docs for state variables to JSON.
This commit is contained in:
parent
3e8b9bdb1c
commit
7d37ed4531
@ -57,6 +57,13 @@ bool DocStringAnalyser::visit(FunctionDefinition const& _function)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DocStringAnalyser::visit(VariableDeclaration const& _variable)
|
||||||
|
{
|
||||||
|
if (_variable.isStateVariable() && _variable.isPartOfExternalInterface())
|
||||||
|
handleDeclaration(_variable, _variable, _variable.annotation());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DocStringAnalyser::visit(ModifierDefinition const& _modifier)
|
bool DocStringAnalyser::visit(ModifierDefinition const& _modifier)
|
||||||
{
|
{
|
||||||
handleCallable(_modifier, _modifier, _modifier.annotation());
|
handleCallable(_modifier, _modifier, _modifier.annotation());
|
||||||
@ -117,6 +124,16 @@ void DocStringAnalyser::handleCallable(
|
|||||||
checkParameters(_callable, _node, _annotation);
|
checkParameters(_callable, _node, _annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocStringAnalyser::handleDeclaration(
|
||||||
|
Declaration const&,
|
||||||
|
StructurallyDocumented const& _node,
|
||||||
|
StructurallyDocumentedAnnotation& _annotation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param"};
|
||||||
|
parseDocStrings(_node, _annotation, validTags, "state variables");
|
||||||
|
}
|
||||||
|
|
||||||
void DocStringAnalyser::parseDocStrings(
|
void DocStringAnalyser::parseDocStrings(
|
||||||
StructurallyDocumented const& _node,
|
StructurallyDocumented const& _node,
|
||||||
StructurallyDocumentedAnnotation& _annotation,
|
StructurallyDocumentedAnnotation& _annotation,
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool visit(ContractDefinition const& _contract) override;
|
bool visit(ContractDefinition const& _contract) override;
|
||||||
bool visit(FunctionDefinition const& _function) override;
|
bool visit(FunctionDefinition const& _function) override;
|
||||||
|
bool visit(VariableDeclaration const& _variable) override;
|
||||||
bool visit(ModifierDefinition const& _modifier) override;
|
bool visit(ModifierDefinition const& _modifier) override;
|
||||||
bool visit(EventDefinition const& _event) override;
|
bool visit(EventDefinition const& _event) override;
|
||||||
|
|
||||||
@ -67,6 +68,12 @@ private:
|
|||||||
StructurallyDocumentedAnnotation& _annotation
|
StructurallyDocumentedAnnotation& _annotation
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void handleDeclaration(
|
||||||
|
Declaration const& _declaration,
|
||||||
|
StructurallyDocumented const& _node,
|
||||||
|
StructurallyDocumentedAnnotation& _annotation
|
||||||
|
);
|
||||||
|
|
||||||
void parseDocStrings(
|
void parseDocStrings(
|
||||||
StructurallyDocumented const& _node,
|
StructurallyDocumented const& _node,
|
||||||
StructurallyDocumentedAnnotation& _annotation,
|
StructurallyDocumentedAnnotation& _annotation,
|
||||||
|
@ -859,7 +859,7 @@ private:
|
|||||||
* Declaration of a variable. This can be used in various places, e.g. in function parameter
|
* Declaration of a variable. This can be used in various places, e.g. in function parameter
|
||||||
* lists, struct definitions and even function bodies.
|
* lists, struct definitions and even function bodies.
|
||||||
*/
|
*/
|
||||||
class VariableDeclaration: public Declaration
|
class VariableDeclaration: public Declaration, public StructurallyDocumented
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Location { Unspecified, Storage, Memory, CallData };
|
enum Location { Unspecified, Storage, Memory, CallData };
|
||||||
@ -882,6 +882,7 @@ public:
|
|||||||
ASTPointer<ASTString> const& _name,
|
ASTPointer<ASTString> const& _name,
|
||||||
ASTPointer<Expression> _value,
|
ASTPointer<Expression> _value,
|
||||||
Visibility _visibility,
|
Visibility _visibility,
|
||||||
|
ASTPointer<StructuredDocumentation> const& _documentation,
|
||||||
bool _isStateVar = false,
|
bool _isStateVar = false,
|
||||||
bool _isIndexed = false,
|
bool _isIndexed = false,
|
||||||
Mutability _mutability = Mutability::Mutable,
|
Mutability _mutability = Mutability::Mutable,
|
||||||
@ -889,8 +890,9 @@ public:
|
|||||||
Location _referenceLocation = Location::Unspecified
|
Location _referenceLocation = Location::Unspecified
|
||||||
):
|
):
|
||||||
Declaration(_id, _location, _name, _visibility),
|
Declaration(_id, _location, _name, _visibility),
|
||||||
m_typeName(std::move(_type)),
|
StructurallyDocumented(_documentation),
|
||||||
m_value(std::move(_value)),
|
m_typeName(_type),
|
||||||
|
m_value(_value),
|
||||||
m_isStateVariable(_isStateVar),
|
m_isStateVariable(_isStateVar),
|
||||||
m_isIndexed(_isIndexed),
|
m_isIndexed(_isIndexed),
|
||||||
m_mutability(_mutability),
|
m_mutability(_mutability),
|
||||||
|
@ -171,7 +171,7 @@ struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, Structurally
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VariableDeclarationAnnotation: DeclarationAnnotation
|
struct VariableDeclarationAnnotation: DeclarationAnnotation, StructurallyDocumentedAnnotation
|
||||||
{
|
{
|
||||||
/// Type of variable (type of identifier referencing this variable).
|
/// Type of variable (type of identifier referencing this variable).
|
||||||
TypePointer type = nullptr;
|
TypePointer type = nullptr;
|
||||||
|
@ -390,7 +390,10 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node)
|
|||||||
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
||||||
};
|
};
|
||||||
if (_node.isStateVariable() && _node.isPublic())
|
if (_node.isStateVariable() && _node.isPublic())
|
||||||
|
{
|
||||||
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
|
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
|
||||||
|
attributes.emplace_back("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue);
|
||||||
|
}
|
||||||
if (m_inEvent)
|
if (m_inEvent)
|
||||||
attributes.emplace_back("indexed", _node.isIndexed());
|
attributes.emplace_back("indexed", _node.isIndexed());
|
||||||
if (!_node.annotation().baseFunctions.empty())
|
if (!_node.annotation().baseFunctions.empty())
|
||||||
|
@ -441,6 +441,7 @@ ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json:
|
|||||||
make_shared<ASTString>(member(_node, "name").asString()),
|
make_shared<ASTString>(member(_node, "name").asString()),
|
||||||
nullOrCast<Expression>(member(_node, "value")),
|
nullOrCast<Expression>(member(_node, "value")),
|
||||||
visibility(_node),
|
visibility(_node),
|
||||||
|
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
|
||||||
memberAsBool(_node, "stateVariable"),
|
memberAsBool(_node, "stateVariable"),
|
||||||
_node.isMember("indexed") ? memberAsBool(_node, "indexed") : false,
|
_node.isMember("indexed") ? memberAsBool(_node, "indexed") : false,
|
||||||
mutability,
|
mutability,
|
||||||
|
@ -52,6 +52,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
|||||||
|
|
||||||
for (auto const& it: _contractDef.interfaceFunctions())
|
for (auto const& it: _contractDef.interfaceFunctions())
|
||||||
if (it.second->hasDeclaration())
|
if (it.second->hasDeclaration())
|
||||||
|
{
|
||||||
if (auto const* f = dynamic_cast<FunctionDefinition const*>(&it.second->declaration()))
|
if (auto const* f = dynamic_cast<FunctionDefinition const*>(&it.second->declaration()))
|
||||||
{
|
{
|
||||||
string value = extractDoc(f->annotation().docTags, "notice");
|
string value = extractDoc(f->annotation().docTags, "notice");
|
||||||
@ -63,6 +64,18 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
|||||||
methods[it.second->externalSignature()] = user;
|
methods[it.second->externalSignature()] = user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (auto var = dynamic_cast<VariableDeclaration const*>(&it.second->declaration()))
|
||||||
|
{
|
||||||
|
string value = extractDoc(var->annotation().docTags, "notice");
|
||||||
|
if (!value.empty())
|
||||||
|
{
|
||||||
|
Json::Value user;
|
||||||
|
// since @notice is the only user tag if missing function should not appear
|
||||||
|
user["notice"] = Json::Value(value);
|
||||||
|
methods[it.second->externalSignature()] = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
doc["methods"] = methods;
|
doc["methods"] = methods;
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
@ -108,6 +121,19 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
|
|||||||
if (!method.empty())
|
if (!method.empty())
|
||||||
methods[it.second->externalSignature()] = method;
|
methods[it.second->externalSignature()] = method;
|
||||||
}
|
}
|
||||||
|
if (auto var = dynamic_cast<VariableDeclaration const*>(&it.second->declaration()))
|
||||||
|
{
|
||||||
|
Json::Value method(devDocumentation(var->annotation().docTags));
|
||||||
|
if (!method.empty())
|
||||||
|
{
|
||||||
|
// Json::Value jsonReturn = extractReturnParameterDocs(var->annotation().docTags, *var);
|
||||||
|
|
||||||
|
// if (!jsonReturn.empty())
|
||||||
|
// method["returns"] = jsonReturn;
|
||||||
|
|
||||||
|
methods[it.second->externalSignature()] = method;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doc["methods"] = methods;
|
doc["methods"] = methods;
|
||||||
|
@ -686,6 +686,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
|||||||
ASTNodeFactory nodeFactory = _lookAheadArrayType ?
|
ASTNodeFactory nodeFactory = _lookAheadArrayType ?
|
||||||
ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this);
|
ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this);
|
||||||
ASTPointer<TypeName> type;
|
ASTPointer<TypeName> type;
|
||||||
|
ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation();
|
||||||
if (_lookAheadArrayType)
|
if (_lookAheadArrayType)
|
||||||
type = _lookAheadArrayType;
|
type = _lookAheadArrayType;
|
||||||
else
|
else
|
||||||
@ -695,6 +696,9 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
|||||||
nodeFactory.setEndPositionFromNode(type);
|
nodeFactory.setEndPositionFromNode(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (!_options.isStateVariable && documentation != nullptr)
|
||||||
|
// fatalParserError("Only state variables can retrieve a docstring.");
|
||||||
|
|
||||||
if (dynamic_cast<FunctionTypeName*>(type.get()) && _options.isStateVariable && m_scanner->currentToken() == Token::LBrace)
|
if (dynamic_cast<FunctionTypeName*>(type.get()) && _options.isStateVariable && m_scanner->currentToken() == Token::LBrace)
|
||||||
fatalParserError(
|
fatalParserError(
|
||||||
2915_error,
|
2915_error,
|
||||||
@ -809,6 +813,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
|||||||
identifier,
|
identifier,
|
||||||
value,
|
value,
|
||||||
visibility,
|
visibility,
|
||||||
|
documentation,
|
||||||
_options.isStateVariable,
|
_options.isStateVariable,
|
||||||
isIndexed,
|
isIndexed,
|
||||||
mutability,
|
mutability,
|
||||||
@ -1574,7 +1579,8 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme
|
|||||||
ASTPointer<TypeName>(),
|
ASTPointer<TypeName>(),
|
||||||
name,
|
name,
|
||||||
ASTPointer<Expression>(),
|
ASTPointer<Expression>(),
|
||||||
Visibility::Default
|
Visibility::Default,
|
||||||
|
nullptr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
variables.push_back(var);
|
variables.push_back(var);
|
||||||
|
@ -204,6 +204,45 @@ BOOST_AUTO_TEST_CASE(dev_and_user_no_doc)
|
|||||||
checkNatspec(sourceCode, "test", userNatspec, true);
|
checkNatspec(sourceCode, "test", userNatspec, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(dev_state_variable)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract test {
|
||||||
|
/// @dev Public accessor for the internal state
|
||||||
|
/// @notice Keeps track of the internal state
|
||||||
|
uint public state;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const* natspec = "{"
|
||||||
|
"\"methods\":{"
|
||||||
|
" \"state()\":{ \n"
|
||||||
|
" \"details\": \"Public accessor for the internal state\",\n"
|
||||||
|
" }\n"
|
||||||
|
"}}";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "test", natspec, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_state_variable)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract test {
|
||||||
|
/// @notice Keeps track of the internal state
|
||||||
|
uint public state;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const* natspec = "{"
|
||||||
|
"\"methods\":{"
|
||||||
|
" \"state()\":{ \n"
|
||||||
|
" \"notice\": \"Keeps track of the internal state\",n"
|
||||||
|
" }\n"
|
||||||
|
"}}";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "test", natspec, true);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
|
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
/// @title example of title
|
||||||
|
/// @author example of author
|
||||||
|
/// @notice example of notice
|
||||||
|
/// @dev example of dev
|
||||||
|
/// @param example of param
|
||||||
|
/// @return example of return
|
||||||
|
uint public state;
|
||||||
|
}
|
13
test/libsolidity/syntaxTests/natspec/docstring_variable.sol
Normal file
13
test/libsolidity/syntaxTests/natspec/docstring_variable.sol
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure returns (uint) {
|
||||||
|
/// @title example of title
|
||||||
|
/// @author example of author
|
||||||
|
/// @notice example of notice
|
||||||
|
/// @dev example of dev
|
||||||
|
/// @param example of param
|
||||||
|
/// @return example of return
|
||||||
|
uint state = 42;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
Loading…
Reference in New Issue
Block a user