Skip to content

Commit

Permalink
Adds structured docs for variable declarations.
Browse files Browse the repository at this point in the history
- adds natspec generation for state variables.
- exports structured docs for state variables to JSON.
  • Loading branch information
erak authored and aarlt committed May 19, 2020
1 parent 3e8b9bd commit 7d37ed4
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 5 deletions.
17 changes: 17 additions & 0 deletions libsolidity/analysis/DocStringAnalyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ bool DocStringAnalyser::visit(FunctionDefinition const& _function)
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)
{
handleCallable(_modifier, _modifier, _modifier.annotation());
Expand Down Expand Up @@ -117,6 +124,16 @@ void DocStringAnalyser::handleCallable(
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(
StructurallyDocumented const& _node,
StructurallyDocumentedAnnotation& _annotation,
Expand Down
7 changes: 7 additions & 0 deletions libsolidity/analysis/DocStringAnalyser.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class DocStringAnalyser: private ASTConstVisitor
private:
bool visit(ContractDefinition const& _contract) override;
bool visit(FunctionDefinition const& _function) override;
bool visit(VariableDeclaration const& _variable) override;
bool visit(ModifierDefinition const& _modifier) override;
bool visit(EventDefinition const& _event) override;

Expand All @@ -67,6 +68,12 @@ class DocStringAnalyser: private ASTConstVisitor
StructurallyDocumentedAnnotation& _annotation
);

void handleDeclaration(
Declaration const& _declaration,
StructurallyDocumented const& _node,
StructurallyDocumentedAnnotation& _annotation
);

void parseDocStrings(
StructurallyDocumented const& _node,
StructurallyDocumentedAnnotation& _annotation,
Expand Down
8 changes: 5 additions & 3 deletions libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen
* Declaration of a variable. This can be used in various places, e.g. in function parameter
* lists, struct definitions and even function bodies.
*/
class VariableDeclaration: public Declaration
class VariableDeclaration: public Declaration, public StructurallyDocumented
{
public:
enum Location { Unspecified, Storage, Memory, CallData };
Expand All @@ -882,15 +882,17 @@ class VariableDeclaration: public Declaration
ASTPointer<ASTString> const& _name,
ASTPointer<Expression> _value,
Visibility _visibility,
ASTPointer<StructuredDocumentation> const& _documentation,
bool _isStateVar = false,
bool _isIndexed = false,
Mutability _mutability = Mutability::Mutable,
ASTPointer<OverrideSpecifier> _overrides = nullptr,
Location _referenceLocation = Location::Unspecified
):
Declaration(_id, _location, _name, _visibility),
m_typeName(std::move(_type)),
m_value(std::move(_value)),
StructurallyDocumented(_documentation),
m_typeName(_type),
m_value(_value),
m_isStateVariable(_isStateVar),
m_isIndexed(_isIndexed),
m_mutability(_mutability),
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/ast/ASTAnnotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, Structurally
{
};

struct VariableDeclarationAnnotation: DeclarationAnnotation
struct VariableDeclarationAnnotation: DeclarationAnnotation, StructurallyDocumentedAnnotation
{
/// Type of variable (type of identifier referencing this variable).
TypePointer type = nullptr;
Expand Down
3 changes: 3 additions & 0 deletions libsolidity/ast/ASTJsonConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,10 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node)
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
};
if (_node.isStateVariable() && _node.isPublic())
{
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
attributes.emplace_back("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue);
}
if (m_inEvent)
attributes.emplace_back("indexed", _node.isIndexed());
if (!_node.annotation().baseFunctions.empty())
Expand Down
1 change: 1 addition & 0 deletions libsolidity/ast/ASTJsonImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json:
make_shared<ASTString>(member(_node, "name").asString()),
nullOrCast<Expression>(member(_node, "value")),
visibility(_node),
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
memberAsBool(_node, "stateVariable"),
_node.isMember("indexed") ? memberAsBool(_node, "indexed") : false,
mutability,
Expand Down
26 changes: 26 additions & 0 deletions libsolidity/interface/Natspec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)

for (auto const& it: _contractDef.interfaceFunctions())
if (it.second->hasDeclaration())
{
if (auto const* f = dynamic_cast<FunctionDefinition const*>(&it.second->declaration()))
{
string value = extractDoc(f->annotation().docTags, "notice");
Expand All @@ -63,6 +64,18 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
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;

return doc;
Expand Down Expand Up @@ -108,6 +121,19 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
if (!method.empty())
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;
Expand Down
8 changes: 7 additions & 1 deletion libsolidity/parsing/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
ASTNodeFactory nodeFactory = _lookAheadArrayType ?
ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this);
ASTPointer<TypeName> type;
ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation();
if (_lookAheadArrayType)
type = _lookAheadArrayType;
else
Expand All @@ -695,6 +696,9 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
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)
fatalParserError(
2915_error,
Expand Down Expand Up @@ -809,6 +813,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
identifier,
value,
visibility,
documentation,
_options.isStateVariable,
isIndexed,
mutability,
Expand Down Expand Up @@ -1574,7 +1579,8 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme
ASTPointer<TypeName>(),
name,
ASTPointer<Expression>(),
Visibility::Default
Visibility::Default,
nullptr
);
}
variables.push_back(var);
Expand Down
39 changes: 39 additions & 0 deletions test/libsolidity/SolidityNatspecJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,45 @@ BOOST_AUTO_TEST_CASE(dev_and_user_no_doc)
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)
{
char const* sourceCode = R"(
Expand Down
Original file line number Diff line number Diff line change
@@ -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 changes: 13 additions & 0 deletions test/libsolidity/syntaxTests/natspec/docstring_variable.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}
// ----

0 comments on commit 7d37ed4

Please sign in to comment.