mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #586 from LefterisJP/natspec_contract_tags
Natspec title and author tag.
This commit is contained in:
commit
c7c189cac0
9
AST.h
9
AST.h
@ -156,13 +156,15 @@ class ContractDefinition: public Declaration
|
|||||||
public:
|
public:
|
||||||
ContractDefinition(Location const& _location,
|
ContractDefinition(Location const& _location,
|
||||||
ASTPointer<ASTString> const& _name,
|
ASTPointer<ASTString> const& _name,
|
||||||
|
ASTPointer<ASTString> const& _documentation,
|
||||||
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
|
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
|
||||||
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
||||||
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions):
|
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions):
|
||||||
Declaration(_location, _name),
|
Declaration(_location, _name),
|
||||||
m_definedStructs(_definedStructs),
|
m_definedStructs(_definedStructs),
|
||||||
m_stateVariables(_stateVariables),
|
m_stateVariables(_stateVariables),
|
||||||
m_definedFunctions(_definedFunctions)
|
m_definedFunctions(_definedFunctions),
|
||||||
|
m_documentation(_documentation)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
@ -172,6 +174,10 @@ public:
|
|||||||
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
|
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
|
||||||
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
|
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
|
||||||
|
|
||||||
|
/// @return A shared pointer of an ASTString.
|
||||||
|
/// Can contain a nullptr in which case indicates absence of documentation
|
||||||
|
ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
|
||||||
|
|
||||||
/// Returns the functions that make up the calling interface in the intended order.
|
/// Returns the functions that make up the calling interface in the intended order.
|
||||||
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
|
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
|
||||||
|
|
||||||
@ -179,6 +185,7 @@ private:
|
|||||||
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
|
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
|
||||||
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
|
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
|
||||||
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
|
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
|
||||||
|
ASTPointer<ASTString> m_documentation;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StructDefinition: public Declaration
|
class StructDefinition: public Declaration
|
||||||
|
@ -75,7 +75,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
|
|||||||
if (strPtr)
|
if (strPtr)
|
||||||
{
|
{
|
||||||
resetUser();
|
resetUser();
|
||||||
parseDocString(*strPtr);
|
parseDocString(*strPtr, CommentOwner::FUNCTION);
|
||||||
if (!m_notice.empty())
|
if (!m_notice.empty())
|
||||||
{// since @notice is the only user tag if missing function should not appear
|
{// since @notice is the only user tag if missing function should not appear
|
||||||
user["notice"] = Json::Value(m_notice);
|
user["notice"] = Json::Value(m_notice);
|
||||||
@ -95,6 +95,20 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
|
|||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
|
|
||||||
|
auto contractDoc = _contractDef.getDocumentation();
|
||||||
|
if (contractDoc)
|
||||||
|
{
|
||||||
|
m_contractAuthor.clear();
|
||||||
|
m_title.clear();
|
||||||
|
parseDocString(*contractDoc, CommentOwner::CONTRACT);
|
||||||
|
|
||||||
|
if (!m_contractAuthor.empty())
|
||||||
|
doc["author"] = m_contractAuthor;
|
||||||
|
|
||||||
|
if (!m_title.empty())
|
||||||
|
doc["title"] = m_title;
|
||||||
|
}
|
||||||
|
|
||||||
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
|
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
|
||||||
{
|
{
|
||||||
Json::Value method;
|
Json::Value method;
|
||||||
@ -102,16 +116,21 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
|
|||||||
if (strPtr)
|
if (strPtr)
|
||||||
{
|
{
|
||||||
resetDev();
|
resetDev();
|
||||||
parseDocString(*strPtr);
|
parseDocString(*strPtr, CommentOwner::FUNCTION);
|
||||||
|
|
||||||
if (!m_dev.empty())
|
if (!m_dev.empty())
|
||||||
method["details"] = Json::Value(m_dev);
|
method["details"] = Json::Value(m_dev);
|
||||||
|
|
||||||
|
if (!m_author.empty())
|
||||||
|
method["author"] = m_author;
|
||||||
|
|
||||||
Json::Value params(Json::objectValue);
|
Json::Value params(Json::objectValue);
|
||||||
for (auto const& pair: m_params)
|
for (auto const& pair: m_params)
|
||||||
params[pair.first] = pair.second;
|
params[pair.first] = pair.second;
|
||||||
|
|
||||||
if (!m_params.empty())
|
if (!m_params.empty())
|
||||||
method["params"] = params;
|
method["params"] = params;
|
||||||
|
|
||||||
if (!m_return.empty())
|
if (!m_return.empty())
|
||||||
method["return"] = m_return;
|
method["return"] = m_return;
|
||||||
|
|
||||||
@ -133,6 +152,7 @@ void InterfaceHandler::resetUser()
|
|||||||
void InterfaceHandler::resetDev()
|
void InterfaceHandler::resetDev()
|
||||||
{
|
{
|
||||||
m_dev.clear();
|
m_dev.clear();
|
||||||
|
m_author.clear();
|
||||||
m_return.clear();
|
m_return.clear();
|
||||||
m_params.clear();
|
m_params.clear();
|
||||||
}
|
}
|
||||||
@ -193,10 +213,12 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con
|
|||||||
|
|
||||||
std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos,
|
std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos,
|
||||||
std::string::const_iterator _end,
|
std::string::const_iterator _end,
|
||||||
std::string const& _tag)
|
std::string const& _tag,
|
||||||
|
CommentOwner _owner)
|
||||||
{
|
{
|
||||||
// LTODO: need to check for @(start of a tag) between here and the end of line
|
// LTODO: need to check for @(start of a tag) between here and the end of line
|
||||||
// for all cases
|
// for all cases. Also somehow automate list of acceptable tags for each
|
||||||
|
// language construct since current way does not scale well.
|
||||||
if (m_lastTag == DocTagType::NONE || _tag != "")
|
if (m_lastTag == DocTagType::NONE || _tag != "")
|
||||||
{
|
{
|
||||||
if (_tag == "dev")
|
if (_tag == "dev")
|
||||||
@ -205,37 +227,77 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite
|
|||||||
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
||||||
else if (_tag == "return")
|
else if (_tag == "return")
|
||||||
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
|
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
|
||||||
|
else if (_tag == "author")
|
||||||
|
{
|
||||||
|
if (_owner == CommentOwner::CONTRACT)
|
||||||
|
return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR);
|
||||||
|
else if (_owner == CommentOwner::FUNCTION)
|
||||||
|
return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR);
|
||||||
|
else
|
||||||
|
// LTODO: for now this else makes no sense but later comments will go to more language constructs
|
||||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts"));
|
||||||
|
}
|
||||||
|
else if (_tag == "title")
|
||||||
|
{
|
||||||
|
if (_owner == CommentOwner::CONTRACT)
|
||||||
|
return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE);
|
||||||
|
else
|
||||||
|
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts"));
|
||||||
|
}
|
||||||
else if (_tag == "param")
|
else if (_tag == "param")
|
||||||
return parseDocTagParam(_pos, _end);
|
return parseDocTagParam(_pos, _end);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered"));
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return appendDocTag(_pos, _end);
|
return appendDocTag(_pos, _end, _owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos,
|
std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos,
|
||||||
std::string::const_iterator _end)
|
std::string::const_iterator _end,
|
||||||
|
CommentOwner _owner)
|
||||||
{
|
{
|
||||||
switch (m_lastTag)
|
switch (m_lastTag)
|
||||||
{
|
{
|
||||||
case DocTagType::DEV:
|
case DocTagType::DEV:
|
||||||
m_dev += " ";
|
m_dev += " ";
|
||||||
return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
|
return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
|
||||||
case DocTagType::NOTICE:
|
case DocTagType::NOTICE:
|
||||||
m_notice += " ";
|
m_notice += " ";
|
||||||
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
||||||
case DocTagType::RETURN:
|
case DocTagType::RETURN:
|
||||||
m_return += " ";
|
m_return += " ";
|
||||||
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
|
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
|
||||||
case DocTagType::PARAM:
|
case DocTagType::AUTHOR:
|
||||||
return appendDocTagParam(_pos, _end);
|
if (_owner == CommentOwner::CONTRACT)
|
||||||
default:
|
{
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type"));
|
m_contractAuthor += " ";
|
||||||
break;
|
return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR);
|
||||||
|
}
|
||||||
|
else if (_owner == CommentOwner::FUNCTION)
|
||||||
|
{
|
||||||
|
m_author += " ";
|
||||||
|
return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment"));
|
||||||
|
case DocTagType::TITLE:
|
||||||
|
if (_owner == CommentOwner::CONTRACT)
|
||||||
|
{
|
||||||
|
m_title += " ";
|
||||||
|
return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment"));
|
||||||
|
case DocTagType::PARAM:
|
||||||
|
return appendDocTagParam(_pos, _end);
|
||||||
|
default:
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +309,7 @@ static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_i
|
|||||||
return (spacePos < nlPos) ? spacePos : nlPos;
|
return (spacePos < nlPos) ? spacePos : nlPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceHandler::parseDocString(std::string const& _string)
|
void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner)
|
||||||
{
|
{
|
||||||
auto currPos = _string.begin();
|
auto currPos = _string.begin();
|
||||||
auto end = _string.end();
|
auto end = _string.end();
|
||||||
@ -265,10 +327,10 @@ void InterfaceHandler::parseDocString(std::string const& _string)
|
|||||||
BOOST_THROW_EXCEPTION(DocstringParsingError() <<
|
BOOST_THROW_EXCEPTION(DocstringParsingError() <<
|
||||||
errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found"));
|
errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found"));
|
||||||
|
|
||||||
currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos));
|
currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner);
|
||||||
}
|
}
|
||||||
else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag
|
else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag
|
||||||
currPos = appendDocTag(currPos + 1, end);
|
currPos = appendDocTag(currPos + 1, end, _owner);
|
||||||
else if (currPos != end) // skip the line if a newline was found
|
else if (currPos != end) // skip the line if a newline was found
|
||||||
currPos = nlPos + 1;
|
currPos = nlPos + 1;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,15 @@ enum class DocTagType: uint8_t
|
|||||||
DEV,
|
DEV,
|
||||||
NOTICE,
|
NOTICE,
|
||||||
PARAM,
|
PARAM,
|
||||||
RETURN
|
RETURN,
|
||||||
|
AUTHOR,
|
||||||
|
TITLE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CommentOwner
|
||||||
|
{
|
||||||
|
CONTRACT,
|
||||||
|
FUNCTION
|
||||||
};
|
};
|
||||||
|
|
||||||
class InterfaceHandler
|
class InterfaceHandler
|
||||||
@ -89,12 +97,14 @@ private:
|
|||||||
std::string::const_iterator _end);
|
std::string::const_iterator _end);
|
||||||
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos,
|
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos,
|
||||||
std::string::const_iterator _end);
|
std::string::const_iterator _end);
|
||||||
void parseDocString(std::string const& _string);
|
void parseDocString(std::string const& _string, CommentOwner _owner);
|
||||||
std::string::const_iterator appendDocTag(std::string::const_iterator _pos,
|
std::string::const_iterator appendDocTag(std::string::const_iterator _pos,
|
||||||
std::string::const_iterator _end);
|
std::string::const_iterator _end,
|
||||||
|
CommentOwner _owner);
|
||||||
std::string::const_iterator parseDocTag(std::string::const_iterator _pos,
|
std::string::const_iterator parseDocTag(std::string::const_iterator _pos,
|
||||||
std::string::const_iterator _end,
|
std::string::const_iterator _end,
|
||||||
std::string const& _tag);
|
std::string const& _tag,
|
||||||
|
CommentOwner _owner);
|
||||||
|
|
||||||
Json::StyledWriter m_writer;
|
Json::StyledWriter m_writer;
|
||||||
|
|
||||||
@ -103,6 +113,9 @@ private:
|
|||||||
std::string m_notice;
|
std::string m_notice;
|
||||||
std::string m_dev;
|
std::string m_dev;
|
||||||
std::string m_return;
|
std::string m_return;
|
||||||
|
std::string m_contractAuthor;
|
||||||
|
std::string m_author;
|
||||||
|
std::string m_title;
|
||||||
std::vector<std::pair<std::string, std::string>> m_params;
|
std::vector<std::pair<std::string, std::string>> m_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,6 +112,9 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
|||||||
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
ASTPointer<ASTString> docstring;
|
||||||
|
if (m_scanner->getCurrentCommentLiteral() != "")
|
||||||
|
docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
|
||||||
expectToken(Token::CONTRACT);
|
expectToken(Token::CONTRACT);
|
||||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||||
expectToken(Token::LBRACE);
|
expectToken(Token::LBRACE);
|
||||||
@ -146,7 +149,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
|||||||
}
|
}
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RBRACE);
|
expectToken(Token::RBRACE);
|
||||||
return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
|
return nodeFactory.createNode<ContractDefinition>(name, docstring, structs, stateVariables, functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
|
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
|
||||||
|
Loading…
Reference in New Issue
Block a user