mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
NatSpec: Implement `@inheritdoc`
This commit is contained in:
committed by
Mathias Baumann
parent
6a1b1283fd
commit
ba0a4de50d
@@ -77,7 +77,7 @@ public:
|
||||
BOOST_REQUIRE(Error::containsErrorOfType(m_compilerStack.errors(), Error::Type::DocstringParsingError));
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
CompilerStack m_compilerStack;
|
||||
};
|
||||
|
||||
@@ -1277,13 +1277,7 @@ BOOST_AUTO_TEST_CASE(dev_default_inherit_variable)
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"x()":
|
||||
{
|
||||
"details": "test"
|
||||
}
|
||||
}
|
||||
"methods": { "x()": { "details": "test" } }
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec1 = R"ABCDEF({
|
||||
@@ -1318,13 +1312,80 @@ BOOST_AUTO_TEST_CASE(user_default_inherit_variable)
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"x()":
|
||||
{
|
||||
"notice": "Hello world"
|
||||
"methods": { "x()": { "notice": "Hello world" } }
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "C", natspec, true);
|
||||
checkNatspec(sourceCode, "D", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_explicit_inherit_variable)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
contract B {
|
||||
function x() virtual external returns (uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
/// @notice Hello world
|
||||
/// @dev test
|
||||
function x() virtual external returns (uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract D is C, B {
|
||||
/// @inheritdoc C
|
||||
uint public override(C, B) x;
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods": { "x()": { "details": "test" } }
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec1 = R"ABCDEF({
|
||||
"methods" : {},
|
||||
"stateVariables" :
|
||||
{
|
||||
"x" :
|
||||
{
|
||||
"details" : "test"
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "C", natspec, false);
|
||||
checkNatspec(sourceCode, "D", natspec1, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_explicit_inherit_variable)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
contract B {
|
||||
function x() virtual external returns (uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
/// @notice Hello world
|
||||
/// @dev test
|
||||
function x() virtual external returns (uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract D is C, B {
|
||||
/// @inheritdoc C
|
||||
uint public override(C, B) x;
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods": { "x()": { "notice": "Hello world" } }
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "C", natspec, true);
|
||||
@@ -1423,6 +1484,411 @@ BOOST_AUTO_TEST_CASE(user_default_inherit)
|
||||
checkNatspec(sourceCode, "Token", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_explicit_inherit)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 {
|
||||
function transfer(address to, uint amount) virtual external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC21, ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||
checkNatspec(sourceCode, "Token", natspec, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_explicit_inherit)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 {
|
||||
function transfer(address to, uint amount) virtual external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC21, ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||
checkNatspec(sourceCode, "Token", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_explicit_inherit2)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 is ERC20 {
|
||||
function transfer(address to, uint amount) virtual override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
function transfer(address to, uint amount) override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||
checkNatspec(sourceCode, "ERC21", natspec, false);
|
||||
checkNatspec(sourceCode, "Token", natspec, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_explicit_inherit2)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 is ERC20 {
|
||||
function transfer(address to, uint amount) virtual override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
function transfer(address to, uint amount) override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||
checkNatspec(sourceCode, "ERC21", natspec, true);
|
||||
checkNatspec(sourceCode, "Token", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_explicit_inherit_partial2)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 is ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
/// @dev override dev comment
|
||||
/// @notice override notice
|
||||
function transfer(address to, uint amount) virtual override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC21 {
|
||||
function transfer(address to, uint amount) override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "override dev comment",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||
checkNatspec(sourceCode, "Token", natspec2, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_explicit_inherit_partial2)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 is ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
/// @dev override dev comment
|
||||
/// @notice override notice
|
||||
function transfer(address to, uint amount) virtual override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC21 {
|
||||
function transfer(address to, uint amount) override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "override notice"
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||
checkNatspec(sourceCode, "Token", natspec2, true);
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE(dev_explicit_inherit_partial)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 {
|
||||
function transfer(address to, uint amount) virtual external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC21, ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
/// @dev override dev comment
|
||||
/// @notice override notice
|
||||
function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "override dev comment",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||
checkNatspec(sourceCode, "Token", natspec2, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_explicit_inherit_partial)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract ERC21 {
|
||||
function transfer(address to, uint amount) virtual external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is ERC21, ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
/// @dev override dev comment
|
||||
/// @notice override notice
|
||||
function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "override notice"
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||
checkNatspec(sourceCode, "Token", natspec2, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_inherit_parameter_mismatch)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
@@ -1517,6 +1983,80 @@ BOOST_AUTO_TEST_CASE(user_inherit_parameter_mismatch)
|
||||
checkNatspec(sourceCode, "Token", natspec2, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_explicit_inehrit_complex)
|
||||
{
|
||||
char const *sourceCode1 = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
interface ERC21 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer2
|
||||
/// @dev test2
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
)";
|
||||
|
||||
char const *sourceCode2 = R"(
|
||||
import "Interfaces.sol" as myInterfaces;
|
||||
|
||||
contract Token is myInterfaces.ERC20, myInterfaces.ERC21 {
|
||||
/// @inheritdoc myInterfaces.ERC20
|
||||
function transfer(address too, uint amount)
|
||||
override(myInterfaces.ERC20, myInterfaces.ERC21) external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
m_compilerStack.reset();
|
||||
m_compilerStack.setSources({
|
||||
{"Interfaces.sol", "pragma solidity >=0.0;\n" + std::string(sourceCode1)},
|
||||
{"Testfile.sol", "pragma solidity >=0.0;\n" + std::string(sourceCode2)}
|
||||
});
|
||||
|
||||
m_compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
|
||||
|
||||
Json::Value generatedDocumentation = m_compilerStack.natspecDev("Token");
|
||||
Json::Value expectedDocumentation;
|
||||
util::jsonParseStrict(natspec, expectedDocumentation);
|
||||
|
||||
expectedDocumentation["version"] = Json::Value(Natspec::c_natspecVersion);
|
||||
expectedDocumentation["kind"] = Json::Value("dev");
|
||||
|
||||
BOOST_CHECK_MESSAGE(
|
||||
expectedDocumentation == generatedDocumentation,
|
||||
"Expected:\n" << expectedDocumentation.toStyledString() <<
|
||||
"\n but got:\n" << generatedDocumentation.toStyledString()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
/// @inheritdoc X
|
||||
function f() internal {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DocstringParsingError 9397: (17-34): Documentation tag @inheritdoc references inexistent contract "X".
|
||||
@@ -0,0 +1,10 @@
|
||||
contract D {
|
||||
}
|
||||
|
||||
contract C is D {
|
||||
/// @inheritdoc D
|
||||
function f() internal {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DocstringParsingError 4682: (38-55): Documentation tag @inheritdoc references contract "D", but the contract does not contain a function that is overridden by this function.
|
||||
@@ -0,0 +1,11 @@
|
||||
contract D {
|
||||
struct S { uint a; }
|
||||
}
|
||||
|
||||
contract C is D {
|
||||
/// @inheritdoc D.S
|
||||
function f() internal {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DocstringParsingError 1430: (63-82): Documentation tag @inheritdoc reference "D.S" is not a contract.
|
||||
@@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
struct S { uint a; }
|
||||
/// @inheritdoc S
|
||||
function f() internal {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DocstringParsingError 1430: (42-59): Documentation tag @inheritdoc reference "S" is not a contract.
|
||||
@@ -0,0 +1,17 @@
|
||||
contract ERC20 {
|
||||
/// @notice This event is emitted when a transfer occurs.
|
||||
/// @param from The source account.
|
||||
/// @param to The destination account.
|
||||
/// @param amount The amount.
|
||||
/// @dev A test case!
|
||||
event Transfer(address indexed from, address indexed to, uint amount);
|
||||
}
|
||||
|
||||
contract A is ERC20 {
|
||||
/// @inheritdoc ERC20
|
||||
event Transfer();
|
||||
}
|
||||
|
||||
|
||||
// ----
|
||||
// DocstringParsingError 6546: (305-326): Documentation tag @inheritdoc not valid for events.
|
||||
Reference in New Issue
Block a user