diff --git a/Changelog.md b/Changelog.md index 999520996..c4c5450eb 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Language Features: Compiler Features: * Code Generator: Use ``calldatacopy`` instead of ``codecopy`` to zero out memory past input. + * AST: Add a new node for doxygen-style, structured documentation that can be received by contract, function, event and modifier definitions. Bugfixes: diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index f9a8aab12..f98327405 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -428,6 +428,7 @@ Token Scanner::scanSlash() // doxygen style /// comment Token comment; m_skippedComments[NextNext].location.start = firstSlashPosition; + m_skippedComments[NextNext].location.source = m_source; comment = scanSingleLineDocComment(); m_skippedComments[NextNext].location.end = sourcePos(); m_skippedComments[NextNext].token = comment; @@ -454,6 +455,7 @@ Token Scanner::scanSlash() // we actually have a multiline documentation comment Token comment; m_skippedComments[NextNext].location.start = firstSlashPosition; + m_skippedComments[NextNext].location.source = m_source; comment = scanMultiLineDocComment(); m_skippedComments[NextNext].location.end = sourcePos(); m_skippedComments[NextNext].token = comment; diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index 1b3bd598b..cadd12fc3 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -73,7 +73,7 @@ bool DocStringAnalyser::visit(EventDefinition const& _event) void DocStringAnalyser::checkParameters( CallableDeclaration const& _callable, - DocumentedAnnotation& _annotation + StructurallyDocumentedAnnotation& _annotation ) { set validParams; @@ -95,8 +95,8 @@ void DocStringAnalyser::checkParameters( void DocStringAnalyser::handleConstructor( CallableDeclaration const& _callable, - Documented const& _node, - DocumentedAnnotation& _annotation + StructurallyDocumented const& _node, + StructurallyDocumentedAnnotation& _annotation ) { static set const validTags = set{"author", "dev", "notice", "param"}; @@ -106,8 +106,8 @@ void DocStringAnalyser::handleConstructor( void DocStringAnalyser::handleCallable( CallableDeclaration const& _callable, - Documented const& _node, - DocumentedAnnotation& _annotation + StructurallyDocumented const& _node, + StructurallyDocumentedAnnotation& _annotation ) { static set const validTags = set{"author", "dev", "notice", "return", "param"}; @@ -116,16 +116,16 @@ void DocStringAnalyser::handleCallable( } void DocStringAnalyser::parseDocStrings( - Documented const& _node, - DocumentedAnnotation& _annotation, + StructurallyDocumented const& _node, + StructurallyDocumentedAnnotation& _annotation, set const& _validTags, string const& _nodeName ) { DocStringParser parser; - if (_node.documentation() && !_node.documentation()->empty()) + if (_node.documentation() && !_node.documentation()->text()->empty()) { - if (!parser.parse(*_node.documentation(), m_errorReporter)) + if (!parser.parse(*_node.documentation()->text(), m_errorReporter)) m_errorOccured = true; _annotation.docTags = parser.tags(); } diff --git a/libsolidity/analysis/DocStringAnalyser.h b/libsolidity/analysis/DocStringAnalyser.h index 653413346..2b9e23195 100644 --- a/libsolidity/analysis/DocStringAnalyser.h +++ b/libsolidity/analysis/DocStringAnalyser.h @@ -51,24 +51,24 @@ private: void checkParameters( CallableDeclaration const& _callable, - DocumentedAnnotation& _annotation + StructurallyDocumentedAnnotation& _annotation ); void handleConstructor( CallableDeclaration const& _callable, - Documented const& _node, - DocumentedAnnotation& _annotation + StructurallyDocumented const& _node, + StructurallyDocumentedAnnotation& _annotation ); void handleCallable( CallableDeclaration const& _callable, - Documented const& _node, - DocumentedAnnotation& _annotation + StructurallyDocumented const& _node, + StructurallyDocumentedAnnotation& _annotation ); void parseDocStrings( - Documented const& _node, - DocumentedAnnotation& _annotation, + StructurallyDocumented const& _node, + StructurallyDocumentedAnnotation& _annotation, std::set const& _validTags, std::string const& _nodeName ); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index d5ef041f9..5a5e561c9 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -345,6 +345,30 @@ private: std::vector m_localVariables; }; +/** + * The doxygen-style, structured documentation class that represents an AST node. + */ +class StructuredDocumentation: public ASTNode +{ +public: + StructuredDocumentation( + int64_t _id, + SourceLocation const& _location, + ASTPointer const& _text + ): ASTNode(_id, _location), m_text(_text) + {} + + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + + /// @return A shared pointer of an ASTString. + /// Contains doxygen-style, structured documentation that is parsed later on. + ASTPointer const& text() const { return m_text; } + +private: + ASTPointer m_text; +}; + /** * Abstract class that is added to each AST node that can receive documentation. */ @@ -362,6 +386,24 @@ protected: ASTPointer m_documentation; }; +/** + * Abstract class that is added to each AST node that can receive a structured documentation. + */ +class StructurallyDocumented +{ +public: + virtual ~StructurallyDocumented() = default; + explicit StructurallyDocumented(ASTPointer const& _documentation): m_documentation(_documentation) {} + + /// @return A shared pointer of a FormalDocumentation. + /// Can contain a nullptr in which case indicates absence of documentation + ASTPointer const& documentation() const { return m_documentation; } + +protected: + ASTPointer m_documentation; +}; + + /** * Abstract class that is added to AST nodes that can be marked as not being fully implemented */ @@ -385,21 +427,21 @@ protected: * document order. It first visits all struct declarations, then all variable declarations and * finally all function declarations. */ -class ContractDefinition: public Declaration, public Documented +class ContractDefinition: public Declaration, public StructurallyDocumented { public: ContractDefinition( int64_t _id, SourceLocation const& _location, ASTPointer const& _name, - ASTPointer const& _documentation, + ASTPointer const& _documentation, std::vector> const& _baseContracts, std::vector> const& _subNodes, ContractKind _contractKind = ContractKind::Contract, bool _abstract = false ): Declaration(_id, _location, _name), - Documented(_documentation), + StructurallyDocumented(_documentation), m_baseContracts(_baseContracts), m_subNodes(_subNodes), m_contractKind(_contractKind), @@ -681,7 +723,7 @@ protected: std::vector> m_overrides; }; -class FunctionDefinition: public CallableDeclaration, public Documented, public ImplementationOptional +class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional { public: FunctionDefinition( @@ -693,14 +735,14 @@ public: Token _kind, bool _isVirtual, ASTPointer const& _overrides, - ASTPointer const& _documentation, + ASTPointer const& _documentation, ASTPointer const& _parameters, std::vector> const& _modifiers, ASTPointer const& _returnParameters, ASTPointer const& _body ): CallableDeclaration(_id, _location, _name, _visibility, _parameters, _isVirtual, _overrides, _returnParameters), - Documented(_documentation), + StructurallyDocumented(_documentation), ImplementationOptional(_body != nullptr), m_stateMutability(_stateMutability), m_kind(_kind), @@ -870,21 +912,21 @@ private: /** * Definition of a function modifier. */ -class ModifierDefinition: public CallableDeclaration, public Documented +class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented { public: ModifierDefinition( int64_t _id, SourceLocation const& _location, ASTPointer const& _name, - ASTPointer const& _documentation, + ASTPointer const& _documentation, ASTPointer const& _parameters, bool _isVirtual, ASTPointer const& _overrides, ASTPointer const& _body ): CallableDeclaration(_id, _location, _name, Visibility::Internal, _parameters, _isVirtual, _overrides), - Documented(_documentation), + StructurallyDocumented(_documentation), m_body(_body) { } @@ -935,19 +977,19 @@ private: /** * Definition of a (loggable) event. */ -class EventDefinition: public CallableDeclaration, public Documented +class EventDefinition: public CallableDeclaration, public StructurallyDocumented { public: EventDefinition( int64_t _id, SourceLocation const& _location, ASTPointer const& _name, - ASTPointer const& _documentation, + ASTPointer const& _documentation, ASTPointer const& _parameters, bool _anonymous = false ): CallableDeclaration(_id, _location, _name, Visibility::Default, _parameters), - Documented(_documentation), + StructurallyDocumented(_documentation), m_anonymous(_anonymous) { } diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index ae447f884..86636684c 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -56,9 +56,9 @@ struct DocTag std::string paramName; ///< Only used for @param, stores the parameter name. }; -struct DocumentedAnnotation +struct StructurallyDocumentedAnnotation { - virtual ~DocumentedAnnotation() = default; + virtual ~StructurallyDocumentedAnnotation() = default; /// Mapping docstring tag name -> content. std::multimap docTags; }; @@ -101,7 +101,7 @@ struct TypeDeclarationAnnotation: DeclarationAnnotation std::string canonicalName; }; -struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnotation +struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation { /// List of functions without a body. Can also contain functions from base classes. std::vector unimplementedFunctions; @@ -122,15 +122,15 @@ struct CallableDeclarationAnnotation: DeclarationAnnotation std::set baseFunctions; }; -struct FunctionDefinitionAnnotation: CallableDeclarationAnnotation, DocumentedAnnotation +struct FunctionDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation { }; -struct EventDefinitionAnnotation: CallableDeclarationAnnotation, DocumentedAnnotation +struct EventDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation { }; -struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, DocumentedAnnotation +struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation { }; @@ -142,7 +142,7 @@ struct VariableDeclarationAnnotation: DeclarationAnnotation std::set baseFunctions; }; -struct StatementAnnotation: ASTAnnotation, DocumentedAnnotation +struct StatementAnnotation: ASTAnnotation { }; diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index a455f30b2..38da35218 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -93,6 +93,7 @@ class PrimaryExpression; class Identifier; class ElementaryTypeNameExpression; class Literal; +class StructuredDocumentation; class VariableScope; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 71bb33f77..ed3c6fff9 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -268,7 +268,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node) { setJsonNode(_node, "ContractDefinition", { make_pair("name", _node.name()), - make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue), + make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("contractKind", contractKind(_node.contractKind())), make_pair("abstract", _node.abstract()), make_pair("fullyImplemented", _node.annotation().unimplementedFunctions.empty()), @@ -349,7 +349,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) { std::vector> attributes = { make_pair("name", _node.name()), - make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue), + make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("kind", TokenTraits::toString(_node.kind())), make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), make_pair("visibility", Declaration::visibilityToString(_node.visibility())), @@ -400,7 +400,7 @@ bool ASTJsonConverter::visit(ModifierDefinition const& _node) { std::vector> attributes = { make_pair("name", _node.name()), - make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue), + make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("parameters", toJson(_node.parameterList())), make_pair("virtual", _node.markedVirtual()), @@ -427,7 +427,7 @@ bool ASTJsonConverter::visit(EventDefinition const& _node) m_inEvent = true; setJsonNode(_node, "EventDefinition", { make_pair("name", _node.name()), - make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue), + make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("parameters", toJson(_node.parameterList())), make_pair("anonymous", _node.isAnonymous()) }); @@ -833,6 +833,17 @@ bool ASTJsonConverter::visit(Literal const& _node) return false; } +bool ASTJsonConverter::visit(StructuredDocumentation const& _node) +{ + Json::Value text{*_node.text()}; + std::vector> attributes = { + make_pair("text", text) + }; + setJsonNode(_node, "StructuredDocumentation", std::move(attributes)); + return false; +} + + void ASTJsonConverter::endVisit(EventDefinition const&) { diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 2fd57fb12..a1d3cd4ad 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -119,6 +119,7 @@ public: bool visit(Identifier const& _node) override; bool visit(ElementaryTypeNameExpression const& _node) override; bool visit(Literal const& _node) override; + bool visit(StructuredDocumentation const& _node) override; void endVisit(EventDefinition const&) override; diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index 6e8364454..8bdecdbb8 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -208,6 +208,8 @@ ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js return createElementaryTypeNameExpression(_json); if (nodeType == "Literal") return createLiteral(_json); + if (nodeType == "StructuredDocumentation") + return createDocumentation(_json); else astAssert(false, "Unknown type of ASTNode: " + nodeType); } @@ -283,7 +285,7 @@ ASTPointer ASTJsonImporter::createContractDefinition(Json::V return createASTNode( _node, make_shared(_node["name"].asString()), - nullOrASTString(_node, "documentation"), + _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), baseContracts, subNodes, contractKind(_node), @@ -397,7 +399,7 @@ ASTPointer ASTJsonImporter::createFunctionDefinition(Json::V kind, memberAsBool(_node, "virtual"), _node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")), - nullOrASTString(_node, "documentation"), + _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), createParameterList(member(_node, "parameters")), modifiers, createParameterList(member(_node, "returnParameters")), @@ -428,7 +430,7 @@ ASTPointer ASTJsonImporter::createModifierDefinition(Json::V return createASTNode( _node, memberAsASTString(_node, "name"), - nullOrASTString(_node,"documentation"), + _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), createParameterList(member(_node, "parameters")), memberAsBool(_node, "virtual"), _node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")), @@ -453,7 +455,7 @@ ASTPointer ASTJsonImporter::createEventDefinition(Json::Value c return createASTNode( _node, memberAsASTString(_node, "name"), - nullOrASTString(_node, "documentation"), + _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), createParameterList(member(_node, "parameters")), memberAsBool(_node, "anonymous") ); @@ -842,6 +844,18 @@ ASTPointer ASTJsonImporter::createLiteral(Json::Value const& _node) ); } +ASTPointer ASTJsonImporter::createDocumentation(Json::Value const& _node) +{ + static string const textString = "text"; + + astAssert(member(_node, textString).isString(), "'text' must be a string"); + + return createASTNode( + _node, + make_shared(_node[textString].asString()) + ); +} + // ===== helper functions ========== Json::Value ASTJsonImporter::member(Json::Value const& _node, string const& _name) diff --git a/libsolidity/ast/ASTJsonImporter.h b/libsolidity/ast/ASTJsonImporter.h index 8e05c60f3..ebcbd660c 100644 --- a/libsolidity/ast/ASTJsonImporter.h +++ b/libsolidity/ast/ASTJsonImporter.h @@ -119,6 +119,7 @@ private: ASTPointer createIdentifier(Json::Value const& _node); ASTPointer createElementaryTypeNameExpression(Json::Value const& _node); ASTPointer createLiteral(Json::Value const& _node); + ASTPointer createDocumentation(Json::Value const& _node); ///@} // =============== general helper functions =================== diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 0ffbbd31a..90dad003a 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -92,6 +92,7 @@ public: virtual bool visit(Identifier& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeNameExpression& _node) { return visitNode(_node); } virtual bool visit(Literal& _node) { return visitNode(_node); } + virtual bool visit(StructuredDocumentation& _node) { return visitNode(_node); } virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); } virtual void endVisit(PragmaDirective& _node) { endVisitNode(_node); } @@ -143,6 +144,7 @@ public: virtual void endVisit(Identifier& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeNameExpression& _node) { endVisitNode(_node); } virtual void endVisit(Literal& _node) { endVisitNode(_node); } + virtual void endVisit(StructuredDocumentation& _node) { endVisitNode(_node); } protected: /// Generic function called by default for each node, to be overridden by derived classes @@ -207,6 +209,7 @@ public: virtual bool visit(Identifier const& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeNameExpression const& _node) { return visitNode(_node); } virtual bool visit(Literal const& _node) { return visitNode(_node); } + virtual bool visit(StructuredDocumentation const& _node) { return visitNode(_node); } virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); } virtual void endVisit(PragmaDirective const& _node) { endVisitNode(_node); } @@ -258,6 +261,7 @@ public: virtual void endVisit(Identifier const& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeNameExpression const& _node) { endVisitNode(_node); } virtual void endVisit(Literal const& _node) { endVisitNode(_node); } + virtual void endVisit(StructuredDocumentation const& _node) { endVisitNode(_node); } protected: /// Generic function called by default for each node, to be overridden by derived classes diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index 4ca48e514..bc0123d51 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -67,10 +67,24 @@ void ImportDirective::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void StructuredDocumentation::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void StructuredDocumentation::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + void ContractDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) { + if (m_documentation) + m_documentation->accept(_visitor); listAccept(m_baseContracts, _visitor); listAccept(m_subNodes, _visitor); } @@ -81,6 +95,8 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) { + if (m_documentation) + m_documentation->accept(_visitor); listAccept(m_baseContracts, _visitor); listAccept(m_subNodes, _visitor); } @@ -203,6 +219,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) { + if (m_documentation) + m_documentation->accept(_visitor); if (m_overrides) m_overrides->accept(_visitor); m_parameters->accept(_visitor); @@ -219,6 +237,8 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) { + if (m_documentation) + m_documentation->accept(_visitor); if (m_overrides) m_overrides->accept(_visitor); m_parameters->accept(_visitor); @@ -263,6 +283,8 @@ void ModifierDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) { + if (m_documentation) + m_documentation->accept(_visitor); m_parameters->accept(_visitor); if (m_overrides) m_overrides->accept(_visitor); @@ -275,6 +297,8 @@ void ModifierDefinition::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) { + if (m_documentation) + m_documentation->accept(_visitor); m_parameters->accept(_visitor); if (m_overrides) m_overrides->accept(_visitor); @@ -308,14 +332,22 @@ void ModifierInvocation::accept(ASTConstVisitor& _visitor) const void EventDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) + { + if (m_documentation) + m_documentation->accept(_visitor); m_parameters->accept(_visitor); + } _visitor.endVisit(*this); } void EventDefinition::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) + { + if (m_documentation) + m_documentation->accept(_visitor); m_parameters->accept(_visitor); + } _visitor.endVisit(*this); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index f23ae8a19..dbeb63033 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3323,13 +3323,13 @@ Type const* FunctionType::selfType() const return m_parameterTypes.at(0); } -ASTPointer FunctionType::documentation() const +ASTPointer FunctionType::documentation() const { - auto function = dynamic_cast(m_declaration); + auto function = dynamic_cast(m_declaration); if (function) return function->documentation(); - return ASTPointer(); + return ASTPointer(); } bool FunctionType::padArguments() const diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 7ad662dbb..669250970 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1208,9 +1208,9 @@ public: /// Currently, this will only return true for internal functions like keccak and ecrecover. bool isPure() const; bool isPayable() const { return m_stateMutability == StateMutability::Payable; } - /// @return A shared pointer of an ASTString. - /// Can contain a nullptr in which case indicates absence of documentation - ASTPointer documentation() const; + /// @return A shared pointer of StructuredDocumentation. + /// Can contain a nullptr in which case indicates absence of documentation. + ASTPointer documentation() const; /// true iff arguments are to be padded to multiples of 32 bytes for external calls /// The only functions that do not pad are hash functions, the low-level call functions diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 6de3a3e5b..2b0e9131f 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -135,6 +135,19 @@ void Parser::parsePragmaVersion(SourceLocation const& _location, vector c ); } +ASTPointer Parser::parseStructuredDocumentation() +{ + if (m_scanner->currentCommentLiteral() != "") + { + ASTNodeFactory nodeFactory{*this}; + nodeFactory.setLocation(m_scanner->currentCommentLocation()); + return nodeFactory.createNode( + make_shared(m_scanner->currentCommentLiteral()) + ); + } + return nullptr; +} + ASTPointer Parser::parsePragmaDirective() { RecursionGuard recursionGuard(*this); @@ -276,14 +289,13 @@ ASTPointer Parser::parseContractDefinition() RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); ASTPointer name = nullptr; - ASTPointer docString; + ASTPointer documentation; vector> baseContracts; vector> subNodes; std::pair contractKind{}; try { - if (m_scanner->currentCommentLiteral() != "") - docString = make_shared(m_scanner->currentCommentLiteral()); + documentation = parseStructuredDocumentation(); contractKind = parseContractKind(); name = expectIdentifierToken(); if (m_scanner->currentToken() == Token::Is) @@ -350,7 +362,7 @@ ASTPointer Parser::parseContractDefinition() expectToken(Token::RBrace); return nodeFactory.createNode( name, - docString, + documentation, baseContracts, subNodes, contractKind.first, @@ -538,9 +550,7 @@ ASTPointer Parser::parseFunctionDefinition() { RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); - ASTPointer docstring; - if (m_scanner->currentCommentLiteral() != "") - docstring = make_shared(m_scanner->currentCommentLiteral()); + ASTPointer documentation = parseStructuredDocumentation(); Token kind = m_scanner->currentToken(); ASTPointer name; @@ -598,7 +608,7 @@ ASTPointer Parser::parseFunctionDefinition() kind, header.isVirtual, header.overrides, - docstring, + documentation, header.parameters, header.modifiers, header.returnParameters, @@ -792,9 +802,7 @@ ASTPointer Parser::parseModifierDefinition() m_insideModifier = true; ASTNodeFactory nodeFactory(*this); - ASTPointer docstring; - if (m_scanner->currentCommentLiteral() != "") - docstring = make_shared(m_scanner->currentCommentLiteral()); + ASTPointer documentation = parseStructuredDocumentation(); expectToken(Token::Modifier); ASTPointer name(expectIdentifierToken()); @@ -835,16 +843,14 @@ ASTPointer Parser::parseModifierDefinition() ASTPointer block = parseBlock(); nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, docstring, parameters, isVirtual, overrides, block); + return nodeFactory.createNode(name, documentation, parameters, isVirtual, overrides, block); } ASTPointer Parser::parseEventDefinition() { RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); - ASTPointer docstring; - if (m_scanner->currentCommentLiteral() != "") - docstring = make_shared(m_scanner->currentCommentLiteral()); + ASTPointer documentation = parseStructuredDocumentation(); expectToken(Token::Event); ASTPointer name(expectIdentifierToken()); @@ -861,7 +867,7 @@ ASTPointer Parser::parseEventDefinition() } nodeFactory.markEndPosition(); expectToken(Token::Semicolon); - return nodeFactory.createNode(name, docstring, parameters, anonymous); + return nodeFactory.createNode(name, documentation, parameters, anonymous); } ASTPointer Parser::parseUsingDirective() @@ -1355,7 +1361,7 @@ ASTPointer Parser::parseEmitStatement(ASTPointer const if (m_scanner->currentToken() != Token::Period) break; m_scanner->next(); - }; + } auto eventName = expressionFromIndexAccessStructure(iap); expectToken(Token::LParen); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index e6d244fdc..25bb2b93f 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -80,6 +80,7 @@ private: ///@{ ///@name Parsing functions for the AST nodes void parsePragmaVersion(langutil::SourceLocation const& _location, std::vector const& _tokens, std::vector const& _literals); + ASTPointer parseStructuredDocumentation(); ASTPointer parsePragmaDirective(); ASTPointer parseImportDirective(); /// @returns an std::pair, where diff --git a/test/libsolidity/ASTJSON/documentation.json b/test/libsolidity/ASTJSON/documentation.json index 8c700498c..8671978b0 100644 --- a/test/libsolidity/ASTJSON/documentation.json +++ b/test/libsolidity/ASTJSON/documentation.json @@ -4,10 +4,10 @@ { "C": [ - 1 + 2 ] }, - "id": 2, + "id": 3, "nodeType": "SourceUnit", "nodes": [ @@ -16,17 +16,23 @@ "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "documentation": "This contract is empty", + "documentation": + { + "id": 1, + "nodeType": "StructuredDocumentation", + "src": "0:27:1", + "text": "This contract is empty" + }, "fullyImplemented": true, - "id": 1, + "id": 2, "linearizedBaseContracts": [ - 1 + 2 ], "name": "C", "nodeType": "ContractDefinition", "nodes": [], - "scope": 2, + "scope": 3, "src": "28:13:1" } ], @@ -38,10 +44,10 @@ { "C": [ - 3 + 5 ] }, - "id": 4, + "id": 6, "nodeType": "SourceUnit", "nodes": [ @@ -50,17 +56,23 @@ "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "documentation": "This contract is empty\nand has a line-breaking comment.", + "documentation": + { + "id": 4, + "nodeType": "StructuredDocumentation", + "src": "0:61:2", + "text": "This contract is empty\nand has a line-breaking comment." + }, "fullyImplemented": true, - "id": 3, + "id": 5, "linearizedBaseContracts": [ - 3 + 5 ], "name": "C", "nodeType": "ContractDefinition", "nodes": [], - "scope": 4, + "scope": 6, "src": "62:13:2" } ], @@ -72,10 +84,10 @@ { "C": [ - 15 + 20 ] }, - "id": 16, + "id": 21, "nodeType": "SourceUnit", "nodes": [ @@ -86,10 +98,10 @@ "contractKind": "contract", "documentation": null, "fullyImplemented": true, - "id": 15, + "id": 20, "linearizedBaseContracts": [ - 15 + 20 ], "name": "C", "nodeType": "ContractDefinition", @@ -97,13 +109,19 @@ [ { "anonymous": false, - "documentation": "Some comment on Evt.", - "id": 6, + "documentation": + { + "id": 7, + "nodeType": "StructuredDocumentation", + "src": "15:26:3", + "text": "Some comment on Evt." + }, + "id": 9, "name": "Evt", "nodeType": "EventDefinition", "parameters": { - "id": 5, + "id": 8, "nodeType": "ParameterList", "parameters": [], "src": "51:2:3" @@ -113,26 +131,32 @@ { "body": { - "id": 9, + "id": 13, "nodeType": "Block", "src": "99:6:3", "statements": [ { - "id": 8, + "id": 12, "nodeType": "PlaceholderStatement", "src": "101:1:3" } ] }, - "documentation": "Some comment on mod.", - "id": 10, + "documentation": + { + "id": 10, + "nodeType": "StructuredDocumentation", + "src": "57:26:3", + "text": "Some comment on mod." + }, + "id": 14, "name": "mod", "nodeType": "ModifierDefinition", "overrides": null, "parameters": { - "id": 7, + "id": 11, "nodeType": "ParameterList", "parameters": [], "src": "96:2:3" @@ -144,14 +168,20 @@ { "body": { - "id": 13, + "id": 18, "nodeType": "Block", "src": "155:2:3", "statements": [] }, - "documentation": "Some comment on fn.", + "documentation": + { + "id": 15, + "nodeType": "StructuredDocumentation", + "src": "108:25:3", + "text": "Some comment on fn." + }, "functionSelector": "a4a2c40b", - "id": 14, + "id": 19, "implemented": true, "kind": "function", "modifiers": [], @@ -160,26 +190,26 @@ "overrides": null, "parameters": { - "id": 11, + "id": 16, "nodeType": "ParameterList", "parameters": [], "src": "145:2:3" }, "returnParameters": { - "id": 12, + "id": 17, "nodeType": "ParameterList", "parameters": [], "src": "155:0:3" }, - "scope": 15, + "scope": 20, "src": "134:23:3", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "scope": 16, + "scope": 21, "src": "0:159:3" } ], diff --git a/test/libsolidity/ASTJSON/documentation_legacy.json b/test/libsolidity/ASTJSON/documentation_legacy.json index cd8012d9c..90866e7fb 100644 --- a/test/libsolidity/ASTJSON/documentation_legacy.json +++ b/test/libsolidity/ASTJSON/documentation_legacy.json @@ -6,7 +6,7 @@ { "C": [ - 15 + 20 ] } }, @@ -29,10 +29,10 @@ "fullyImplemented": true, "linearizedBaseContracts": [ - 15 + 20 ], "name": "C", - "scope": 16 + "scope": 21 }, "children": [ @@ -40,11 +40,19 @@ "attributes": { "anonymous": false, - "documentation": "Some comment on Evt.", "name": "Evt" }, "children": [ + { + "attributes": + { + "text": "Some comment on Evt." + }, + "id": 7, + "name": "StructuredDocumentation", + "src": "15:26:3" + }, { "attributes": { @@ -54,19 +62,18 @@ ] }, "children": [], - "id": 5, + "id": 8, "name": "ParameterList", "src": "51:2:3" } ], - "id": 6, + "id": 9, "name": "EventDefinition", "src": "42:12:3" }, { "attributes": { - "documentation": "Some comment on mod.", "name": "mod", "overrides": null, "virtual": false, @@ -77,55 +84,12 @@ { "attributes": { - "parameters": - [ - null - ] + "text": "Some comment on mod." }, - "children": [], - "id": 7, - "name": "ParameterList", - "src": "96:2:3" + "id": 10, + "name": "StructuredDocumentation", + "src": "57:26:3" }, - { - "children": - [ - { - "id": 8, - "name": "PlaceholderStatement", - "src": "101:1:3" - } - ], - "id": 9, - "name": "Block", - "src": "99:6:3" - } - ], - "id": 10, - "name": "ModifierDefinition", - "src": "84:21:3" - }, - { - "attributes": - { - "documentation": "Some comment on fn.", - "functionSelector": "a4a2c40b", - "implemented": true, - "isConstructor": false, - "kind": "function", - "modifiers": - [ - null - ], - "name": "fn", - "overrides": null, - "scope": 15, - "stateMutability": "nonpayable", - "virtual": false, - "visibility": "public" - }, - "children": - [ { "attributes": { @@ -137,6 +101,66 @@ "children": [], "id": 11, "name": "ParameterList", + "src": "96:2:3" + }, + { + "children": + [ + { + "id": 12, + "name": "PlaceholderStatement", + "src": "101:1:3" + } + ], + "id": 13, + "name": "Block", + "src": "99:6:3" + } + ], + "id": 14, + "name": "ModifierDefinition", + "src": "84:21:3" + }, + { + "attributes": + { + "functionSelector": "a4a2c40b", + "implemented": true, + "isConstructor": false, + "kind": "function", + "modifiers": + [ + null + ], + "name": "fn", + "overrides": null, + "scope": 20, + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + "children": + [ + { + "attributes": + { + "text": "Some comment on fn." + }, + "id": 15, + "name": "StructuredDocumentation", + "src": "108:25:3" + }, + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 16, + "name": "ParameterList", "src": "145:2:3" }, { @@ -148,7 +172,7 @@ ] }, "children": [], - "id": 12, + "id": 17, "name": "ParameterList", "src": "155:0:3" }, @@ -161,22 +185,22 @@ ] }, "children": [], - "id": 13, + "id": 18, "name": "Block", "src": "155:2:3" } ], - "id": 14, + "id": 19, "name": "FunctionDefinition", "src": "134:23:3" } ], - "id": 15, + "id": 20, "name": "ContractDefinition", "src": "0:159:3" } ], - "id": 16, + "id": 21, "name": "SourceUnit", "src": "0:160:3" } diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 3087b4b0f..3f70f9160 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -98,7 +98,7 @@ void checkFunctionNatspec( std::string const& _expectedDoc ) { - auto doc = _function->documentation(); + auto doc = _function->documentation()->text(); BOOST_CHECK_MESSAGE(doc != nullptr, "Function does not have Natspec Doc as expected"); BOOST_CHECK_EQUAL(*doc, _expectedDoc); }