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:
|
||||
ContractDefinition(Location const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
ASTPointer<ASTString> const& _documentation,
|
||||
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
|
||||
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
||||
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions):
|
||||
Declaration(_location, _name),
|
||||
m_definedStructs(_definedStructs),
|
||||
m_stateVariables(_stateVariables),
|
||||
m_definedFunctions(_definedFunctions)
|
||||
m_definedFunctions(_definedFunctions),
|
||||
m_documentation(_documentation)
|
||||
{}
|
||||
|
||||
virtual void accept(ASTVisitor& _visitor) override;
|
||||
@ -172,6 +174,10 @@ public:
|
||||
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
|
||||
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.
|
||||
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
|
||||
|
||||
@ -179,6 +185,7 @@ private:
|
||||
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
|
||||
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
|
||||
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
|
||||
ASTPointer<ASTString> m_documentation;
|
||||
};
|
||||
|
||||
class StructDefinition: public Declaration
|
||||
|
@ -75,7 +75,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
|
||||
if (strPtr)
|
||||
{
|
||||
resetUser();
|
||||
parseDocString(*strPtr);
|
||||
parseDocString(*strPtr, CommentOwner::FUNCTION);
|
||||
if (!m_notice.empty())
|
||||
{// since @notice is the only user tag if missing function should not appear
|
||||
user["notice"] = Json::Value(m_notice);
|
||||
@ -95,6 +95,20 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
|
||||
Json::Value doc;
|
||||
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())
|
||||
{
|
||||
Json::Value method;
|
||||
@ -102,16 +116,21 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
|
||||
if (strPtr)
|
||||
{
|
||||
resetDev();
|
||||
parseDocString(*strPtr);
|
||||
parseDocString(*strPtr, CommentOwner::FUNCTION);
|
||||
|
||||
if (!m_dev.empty())
|
||||
method["details"] = Json::Value(m_dev);
|
||||
|
||||
if (!m_author.empty())
|
||||
method["author"] = m_author;
|
||||
|
||||
Json::Value params(Json::objectValue);
|
||||
for (auto const& pair: m_params)
|
||||
params[pair.first] = pair.second;
|
||||
|
||||
if (!m_params.empty())
|
||||
method["params"] = params;
|
||||
|
||||
if (!m_return.empty())
|
||||
method["return"] = m_return;
|
||||
|
||||
@ -133,6 +152,7 @@ void InterfaceHandler::resetUser()
|
||||
void InterfaceHandler::resetDev()
|
||||
{
|
||||
m_dev.clear();
|
||||
m_author.clear();
|
||||
m_return.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 _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
|
||||
// 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 (_tag == "dev")
|
||||
@ -205,37 +227,77 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite
|
||||
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
||||
else if (_tag == "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")
|
||||
return parseDocTagParam(_pos, _end);
|
||||
else
|
||||
{
|
||||
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered"));
|
||||
}
|
||||
}
|
||||
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 _end)
|
||||
std::string::const_iterator _end,
|
||||
CommentOwner _owner)
|
||||
{
|
||||
switch (m_lastTag)
|
||||
{
|
||||
case DocTagType::DEV:
|
||||
m_dev += " ";
|
||||
return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
|
||||
case DocTagType::NOTICE:
|
||||
m_notice += " ";
|
||||
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
||||
case DocTagType::RETURN:
|
||||
m_return += " ";
|
||||
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
|
||||
case DocTagType::PARAM:
|
||||
return appendDocTagParam(_pos, _end);
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type"));
|
||||
break;
|
||||
case DocTagType::DEV:
|
||||
m_dev += " ";
|
||||
return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
|
||||
case DocTagType::NOTICE:
|
||||
m_notice += " ";
|
||||
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
|
||||
case DocTagType::RETURN:
|
||||
m_return += " ";
|
||||
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
|
||||
case DocTagType::AUTHOR:
|
||||
if (_owner == CommentOwner::CONTRACT)
|
||||
{
|
||||
m_contractAuthor += " ";
|
||||
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;
|
||||
}
|
||||
|
||||
void InterfaceHandler::parseDocString(std::string const& _string)
|
||||
void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner)
|
||||
{
|
||||
auto currPos = _string.begin();
|
||||
auto end = _string.end();
|
||||
@ -265,10 +327,10 @@ void InterfaceHandler::parseDocString(std::string const& _string)
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() <<
|
||||
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
|
||||
currPos = appendDocTag(currPos + 1, end);
|
||||
currPos = appendDocTag(currPos + 1, end, _owner);
|
||||
else if (currPos != end) // skip the line if a newline was found
|
||||
currPos = nlPos + 1;
|
||||
}
|
||||
|
@ -45,7 +45,15 @@ enum class DocTagType: uint8_t
|
||||
DEV,
|
||||
NOTICE,
|
||||
PARAM,
|
||||
RETURN
|
||||
RETURN,
|
||||
AUTHOR,
|
||||
TITLE
|
||||
};
|
||||
|
||||
enum class CommentOwner
|
||||
{
|
||||
CONTRACT,
|
||||
FUNCTION
|
||||
};
|
||||
|
||||
class InterfaceHandler
|
||||
@ -89,12 +97,14 @@ private:
|
||||
std::string::const_iterator _end);
|
||||
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos,
|
||||
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 _end);
|
||||
std::string::const_iterator _end,
|
||||
CommentOwner _owner);
|
||||
std::string::const_iterator parseDocTag(std::string::const_iterator _pos,
|
||||
std::string::const_iterator _end,
|
||||
std::string const& _tag);
|
||||
std::string const& _tag,
|
||||
CommentOwner _owner);
|
||||
|
||||
Json::StyledWriter m_writer;
|
||||
|
||||
@ -103,6 +113,9 @@ private:
|
||||
std::string m_notice;
|
||||
std::string m_dev;
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -112,6 +112,9 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
{
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
ASTPointer<ASTString> docstring;
|
||||
if (m_scanner->getCurrentCommentLiteral() != "")
|
||||
docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
|
||||
expectToken(Token::CONTRACT);
|
||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||
expectToken(Token::LBRACE);
|
||||
@ -146,7 +149,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
}
|
||||
nodeFactory.markEndPosition();
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user