Adds NatSpec to AST for struct definitions.

This commit is contained in:
Marko Veniger 2023-04-18 13:10:21 +02:00
parent f0c0df2d8c
commit 07def48f45
11 changed files with 288 additions and 6 deletions

View File

@ -7,6 +7,7 @@ Compiler Features:
* Assembler: Use ``push0`` for placing ``0`` in the stack for EVM versions starting from "Shanghai". This decreases the deployment costs. * Assembler: Use ``push0`` for placing ``0`` in the stack for EVM versions starting from "Shanghai". This decreases the deployment costs.
* EVM: Support for the EVM Version "Shanghai". * EVM: Support for the EVM Version "Shanghai".
* NatSpec: Add support for NatSpec documentation in ``enum`` definitions. * NatSpec: Add support for NatSpec documentation in ``enum`` definitions.
* NatSpec: Add support for NatSpec documentation in ``struct`` definitions.
* Optimizer: Re-implement simplified version of UnusedAssignEliminator and UnusedStoreEliminator. It can correctly remove some unused assignments in deeply nested loops that were ignored by the old version. * Optimizer: Re-implement simplified version of UnusedAssignEliminator and UnusedStoreEliminator. It can correctly remove some unused assignments in deeply nested loops that were ignored by the old version.
* SMTChecker: Properties that are proved safe are now reported explicitly at the end of the analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties. * SMTChecker: Properties that are proved safe are now reported explicitly at the end of the analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties.
* SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option ``--model-checker-show-unsupported`` and the JSON option ``settings.modelChecker.showUnsupported`` can be enabled to show the full list. * SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option ``--model-checker-show-unsupported`` and the JSON option ``settings.modelChecker.showUnsupported`` can be enabled to show the full list.

View File

@ -709,7 +709,7 @@ private:
bool m_global = false; bool m_global = false;
}; };
class StructDefinition: public Declaration, public ScopeOpener class StructDefinition: public Declaration, public StructurallyDocumented, public ScopeOpener
{ {
public: public:
StructDefinition( StructDefinition(
@ -717,9 +717,13 @@ public:
SourceLocation const& _location, SourceLocation const& _location,
ASTPointer<ASTString> const& _name, ASTPointer<ASTString> const& _name,
SourceLocation _nameLocation, SourceLocation _nameLocation,
std::vector<ASTPointer<VariableDeclaration>> _members std::vector<ASTPointer<VariableDeclaration>> _members,
ASTPointer<StructuredDocumentation> _documentation
): ):
Declaration(_id, _location, _name, std::move(_nameLocation)), m_members(std::move(_members)) {} Declaration(_id, _location, _name, std::move(_nameLocation)),
StructurallyDocumented(std::move(_documentation)),
m_members(std::move(_members))
{}
void accept(ASTVisitor& _visitor) override; void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override; void accept(ASTConstVisitor& _visitor) const override;

View File

@ -367,6 +367,7 @@ bool ASTJsonExporter::visit(StructDefinition const& _node)
std::vector<pair<string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
make_pair("name", _node.name()), make_pair("name", _node.name()),
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
make_pair("members", toJson(_node.members())), make_pair("members", toJson(_node.members())),
make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))

View File

@ -449,7 +449,8 @@ ASTPointer<ASTNode> ASTJsonImporter::createStructDefinition(Json::Value const& _
_node, _node,
memberAsASTString(_node, "name"), memberAsASTString(_node, "name"),
createNameSourceLocation(_node), createNameSourceLocation(_node),
members members,
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation"))
); );
} }

View File

@ -682,6 +682,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
{ {
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation();
expectToken(Token::Struct); expectToken(Token::Struct);
auto [name, nameLocation] = expectIdentifierWithLocation(); auto [name, nameLocation] = expectIdentifierWithLocation();
vector<ASTPointer<VariableDeclaration>> members; vector<ASTPointer<VariableDeclaration>> members;
@ -693,7 +694,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RBrace); expectToken(Token::RBrace);
return nodeFactory.createNode<StructDefinition>(std::move(name), std::move(nameLocation), std::move(members)); return nodeFactory.createNode<StructDefinition>(std::move(name), std::move(nameLocation), std::move(members), std::move(documentation));
} }
ASTPointer<EnumValue> Parser::parseEnumValue() ASTPointer<EnumValue> Parser::parseEnumValue()

View File

@ -0,0 +1,126 @@
{
"absolutePath": "a",
"exportedSymbols":
{
"Example":
[
8
]
},
"id": 9,
"nodeType": "SourceUnit",
"nodes":
[
{
"canonicalName": "Example",
"documentation":
{
"id": 1,
"nodeType": "StructuredDocumentation",
"src": "0:112:1",
"text": "@title example of title\n @author example of author\n @notice example of notice\n @dev example of dev"
},
"id": 8,
"members":
[
{
"constant": false,
"id": 3,
"mutability": "mutable",
"name": "text",
"nameLocation": "140:4:1",
"nodeType": "VariableDeclaration",
"scope": 8,
"src": "133:11:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_string_storage_ptr",
"typeString": "string"
},
"typeName":
{
"id": 2,
"name": "string",
"nodeType": "ElementaryTypeName",
"src": "133:6:1",
"typeDescriptions":
{
"typeIdentifier": "t_string_storage_ptr",
"typeString": "string"
}
},
"visibility": "internal"
},
{
"constant": false,
"id": 5,
"mutability": "mutable",
"name": "valid",
"nameLocation": "155:5:1",
"nodeType": "VariableDeclaration",
"scope": 8,
"src": "150:10:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_bool",
"typeString": "bool"
},
"typeName":
{
"id": 4,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "150:4:1",
"typeDescriptions":
{
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"visibility": "internal"
},
{
"constant": false,
"id": 7,
"mutability": "mutable",
"name": "value",
"nameLocation": "174:5:1",
"nodeType": "VariableDeclaration",
"scope": 8,
"src": "166:13:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 6,
"name": "uint256",
"nodeType": "ElementaryTypeName",
"src": "166:7:1",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"name": "Example",
"nameLocation": "119:7:1",
"nodeType": "StructDefinition",
"scope": 9,
"src": "112:70:1",
"visibility": "public"
}
],
"src": "112:71:1"
}

View File

@ -0,0 +1,11 @@
/// @title example of title
/// @author example of author
/// @notice example of notice
/// @dev example of dev
struct Example {
string text;
bool valid;
uint256 value;
}
// ----

View File

@ -0,0 +1,90 @@
{
"absolutePath": "a",
"id": 9,
"nodeType": "SourceUnit",
"nodes":
[
{
"documentation":
{
"id": 1,
"nodeType": "StructuredDocumentation",
"src": "0:112:1",
"text": "@title example of title\n @author example of author\n @notice example of notice\n @dev example of dev"
},
"id": 8,
"members":
[
{
"constant": false,
"id": 3,
"mutability": "mutable",
"name": "text",
"nameLocation": "140:4:1",
"nodeType": "VariableDeclaration",
"src": "133:11:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {},
"typeName":
{
"id": 2,
"name": "string",
"nodeType": "ElementaryTypeName",
"src": "133:6:1",
"typeDescriptions": {}
},
"visibility": "internal"
},
{
"constant": false,
"id": 5,
"mutability": "mutable",
"name": "valid",
"nameLocation": "155:5:1",
"nodeType": "VariableDeclaration",
"src": "150:10:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {},
"typeName":
{
"id": 4,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "150:4:1",
"typeDescriptions": {}
},
"visibility": "internal"
},
{
"constant": false,
"id": 7,
"mutability": "mutable",
"name": "value",
"nameLocation": "174:5:1",
"nodeType": "VariableDeclaration",
"src": "166:13:1",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {},
"typeName":
{
"id": 6,
"name": "uint256",
"nodeType": "ElementaryTypeName",
"src": "166:7:1",
"typeDescriptions": {}
},
"visibility": "internal"
}
],
"name": "Example",
"nameLocation": "119:7:1",
"nodeType": "StructDefinition",
"src": "112:70:1",
"visibility": "public"
}
],
"src": "112:71:1"
}

View File

@ -1076,6 +1076,41 @@ BOOST_AUTO_TEST_CASE(dev_author_at_function)
expectNatspecError(sourceCode); expectNatspecError(sourceCode);
} }
BOOST_AUTO_TEST_CASE(struct_no_docs)
{
char const* sourceCode = R"(
contract C {
/// @title example of title
/// @author example of author
/// @notice example of notice
/// @dev example of dev
struct Example {
string text;
bool valid;
uint256 value;
}
}
)";
char const* devDoc = R"ABCDEF(
{
"kind": "dev",
"methods": {},
"version": 1
})ABCDEF";
checkNatspec(sourceCode, "C", devDoc, false);
char const* userDoc = R"ABCDEF(
{
"kind": "user",
"methods": {},
"version": 1
})ABCDEF";
checkNatspec(sourceCode, "C", userDoc, true);
}
BOOST_AUTO_TEST_CASE(enum_no_docs) BOOST_AUTO_TEST_CASE(enum_no_docs)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

View File

@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
BOOST_CHECK_EQUAL(c.type()->identifier(), "t_type$_t_contract$_MyContract$$$_$2_$"); BOOST_CHECK_EQUAL(c.type()->identifier(), "t_type$_t_contract$_MyContract$$$_$2_$");
BOOST_CHECK_EQUAL(ContractType(c, true).identifier(), "t_super$_MyContract$$$_$2"); BOOST_CHECK_EQUAL(ContractType(c, true).identifier(), "t_super$_MyContract$$$_$2");
StructDefinition s(++id, {}, make_shared<string>("Struct"), {}, {}); StructDefinition s(++id, {}, make_shared<string>("Struct"), {}, {}, {});
s.annotation().recursive = false; s.annotation().recursive = false;
BOOST_CHECK_EQUAL(s.type()->identifier(), "t_type$_t_struct$_Struct_$3_storage_ptr_$"); BOOST_CHECK_EQUAL(s.type()->identifier(), "t_type$_t_struct$_Struct_$3_storage_ptr_$");

View File

@ -0,0 +1,12 @@
contract C {
/// @title example of title
/// @author example of author
/// @notice example of notice
/// @dev example of dev
struct Example {
string text;
bool valid;
uint256 value;
}
}
// ----