Fixes source extraction from docs.

This commit is contained in:
Erik Kundt 2019-10-23 22:13:17 +02:00
parent abf1aa74cf
commit ec53899a10
6 changed files with 251 additions and 242 deletions

View File

@ -292,27 +292,27 @@ Consider you have the following pre-0.5.0 contract already deployed:
:: ::
// This will not compile with the current version of the compiler // This will not compile with the current version of the compiler
pragma solidity ^0.4.25; pragma solidity ^0.4.25;
contract OldContract { contract OldContract {
function someOldFunction(uint8 a) { function someOldFunction(uint8 a) {
//... //...
} }
function anotherOldFunction() constant returns (bool) { function anotherOldFunction() constant returns (bool) {
//... //...
} }
// ... // ...
} }
This will no longer compile with Solidity v0.5.0. However, you can define a compatible interface for it: This will no longer compile with Solidity v0.5.0. However, you can define a compatible interface for it:
:: ::
pragma solidity >=0.5.0 <0.7.0; pragma solidity >=0.5.0 <0.7.0;
interface OldContract { interface OldContract {
function someOldFunction(uint8 a) external; function someOldFunction(uint8 a) external;
function anotherOldFunction() external returns (bool); function anotherOldFunction() external returns (bool);
} }
Note that we did not declare ``anotherOldFunction`` to be ``view``, despite it being declared ``constant`` in the original Note that we did not declare ``anotherOldFunction`` to be ``view``, despite it being declared ``constant`` in the original
contract. This is due to the fact that starting with Solidity v0.5.0 ``staticcall`` is used to call ``view`` functions. contract. This is due to the fact that starting with Solidity v0.5.0 ``staticcall`` is used to call ``view`` functions.
@ -325,19 +325,19 @@ Given the interface defined above, you can now easily use the already deployed p
:: ::
pragma solidity >=0.5.0 <0.7.0; pragma solidity >=0.5.0 <0.7.0;
interface OldContract { interface OldContract {
function someOldFunction(uint8 a) external; function someOldFunction(uint8 a) external;
function anotherOldFunction() external returns (bool); function anotherOldFunction() external returns (bool);
} }
contract NewContract { contract NewContract {
function doSomething(OldContract a) public returns (bool) { function doSomething(OldContract a) public returns (bool) {
a.someOldFunction(0x42); a.someOldFunction(0x42);
return a.anotherOldFunction(); return a.anotherOldFunction();
} }
} }
Similarly, pre-0.5.0 libraries can be used by defining the functions of the library without implementation and Similarly, pre-0.5.0 libraries can be used by defining the functions of the library without implementation and
supplying the address of the pre-0.5.0 library during linking (see :ref:`commandline-compiler` for how to use the supplying the address of the pre-0.5.0 library during linking (see :ref:`commandline-compiler` for how to use the
@ -345,17 +345,17 @@ commandline compiler for linking):
:: ::
pragma solidity >=0.5.0 <0.7.0; pragma solidity >=0.5.0 <0.7.0;
library OldLibrary { library OldLibrary {
function someFunction(uint8 a) public returns(bool); function someFunction(uint8 a) public returns(bool);
} }
contract NewContract { contract NewContract {
function f(uint8 a) public returns (bool) { function f(uint8 a) public returns (bool) {
return OldLibrary.someFunction(a); return OldLibrary.someFunction(a);
} }
} }
Example Example
@ -368,144 +368,144 @@ Old version:
:: ::
// This will not compile // This will not compile
pragma solidity ^0.4.25; pragma solidity ^0.4.25;
contract OtherContract { contract OtherContract {
uint x; uint x;
function f(uint y) external { function f(uint y) external {
x = y; x = y;
} }
function() payable external {} function() payable external {}
} }
contract Old { contract Old {
OtherContract other; OtherContract other;
uint myNumber; uint myNumber;
// Function mutability not provided, not an error. // Function mutability not provided, not an error.
function someInteger() internal returns (uint) { return 2; } function someInteger() internal returns (uint) { return 2; }
// Function visibility not provided, not an error. // Function visibility not provided, not an error.
// Function mutability not provided, not an error. // Function mutability not provided, not an error.
function f(uint x) returns (bytes) { function f(uint x) returns (bytes) {
// Var is fine in this version. // Var is fine in this version.
var z = someInteger(); var z = someInteger();
x += z; x += z;
// Throw is fine in this version. // Throw is fine in this version.
if (x > 100) if (x > 100)
throw; throw;
bytes b = new bytes(x); bytes b = new bytes(x);
y = -3 >> 1; y = -3 >> 1;
// y == -1 (wrong, should be -2) // y == -1 (wrong, should be -2)
do { do {
x += 1; x += 1;
if (x > 10) continue; if (x > 10) continue;
// 'Continue' causes an infinite loop. // 'Continue' causes an infinite loop.
} while (x < 11); } while (x < 11);
// Call returns only a Bool. // Call returns only a Bool.
bool success = address(other).call("f"); bool success = address(other).call("f");
if (!success) if (!success)
revert(); revert();
else { else {
// Local variables could be declared after their use. // Local variables could be declared after their use.
int y; int y;
} }
return b; return b;
} }
// No need for an explicit data location for 'arr' // No need for an explicit data location for 'arr'
function g(uint[] arr, bytes8 x, OtherContract otherContract) public { function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
otherContract.transfer(1 ether); otherContract.transfer(1 ether);
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes), // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
// the first 4 bytes of x will be lost. This might lead to // the first 4 bytes of x will be lost. This might lead to
// unexpected behavior since bytesX are right padded. // unexpected behavior since bytesX are right padded.
uint32 y = uint32(x); uint32 y = uint32(x);
myNumber += y + msg.value; myNumber += y + msg.value;
} }
} }
New version: New version:
:: ::
pragma solidity >=0.5.0 <0.7.0; pragma solidity >=0.5.0 <0.7.0;
contract OtherContract { contract OtherContract {
uint x; uint x;
function f(uint y) external { function f(uint y) external {
x = y; x = y;
} }
function() payable external {} function() payable external {}
} }
contract New { contract New {
OtherContract other; OtherContract other;
uint myNumber; uint myNumber;
// Function mutability must be specified. // Function mutability must be specified.
function someInteger() internal pure returns (uint) { return 2; } function someInteger() internal pure returns (uint) { return 2; }
// Function visibility must be specified. // Function visibility must be specified.
// Function mutability must be specified. // Function mutability must be specified.
function f(uint x) public returns (bytes memory) { function f(uint x) public returns (bytes memory) {
// The type must now be explicitly given. // The type must now be explicitly given.
uint z = someInteger(); uint z = someInteger();
x += z; x += z;
// Throw is now disallowed. // Throw is now disallowed.
require(x > 100); require(x > 100);
int y = -3 >> 1; int y = -3 >> 1;
// y == -2 (correct) require(y == -2);
do { do {
x += 1; x += 1;
if (x > 10) continue; if (x > 10) continue;
// 'Continue' jumps to the condition below. // 'Continue' jumps to the condition below.
} while (x < 11); } while (x < 11);
// Call returns (bool, bytes). // Call returns (bool, bytes).
// Data location must be specified. // Data location must be specified.
(bool success, bytes memory data) = address(other).call("f"); (bool success, bytes memory data) = address(other).call("f");
if (!success) if (!success)
revert(); revert();
return data; return data;
} }
using address_make_payable for address; using address_make_payable for address;
// Data location for 'arr' must be specified // Data location for 'arr' must be specified
function g(uint[] memory arr, bytes8 x, OtherContract otherContract, address unknownContract) public payable { function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
// 'otherContract.transfer' is not provided. // 'otherContract.transfer' is not provided.
// Since the code of 'OtherContract' is known and has the fallback // Since the code of 'OtherContract' is known and has the fallback
// function, address(otherContract) has type 'address payable'. // function, address(otherContract) has type 'address payable'.
address(otherContract).transfer(1 ether); address(otherContract).transfer(1 ether);
// 'unknownContract.transfer' is not provided. // 'unknownContract.transfer' is not provided.
// 'address(unknownContract).transfer' is not provided // 'address(unknownContract).transfer' is not provided
// since 'address(unknownContract)' is not 'address payable'. // since 'address(unknownContract)' is not 'address payable'.
// If the function takes an 'address' which you want to send // If the function takes an 'address' which you want to send
// funds to, you can convert it to 'address payable' via 'uint160'. // funds to, you can convert it to 'address payable' via 'uint160'.
// Note: This is not recommended and the explicit type // Note: This is not recommended and the explicit type
// 'address payable' should be used whenever possible. // 'address payable' should be used whenever possible.
// To increase clarity, we suggest the use of a library for // To increase clarity, we suggest the use of a library for
// the conversion (provided after the contract in this example). // the conversion (provided after the contract in this example).
address payable addr = unknownContract.make_payable(); address payable addr = unknownContract.make_payable();
require(addr.send(1 ether)); require(addr.send(1 ether));
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes), // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
// the conversion is not allowed. // the conversion is not allowed.
// We need to convert to a common size first: // We need to convert to a common size first:
bytes4 x4 = bytes4(x); // Padding happens on the right bytes4 x4 = bytes4(x); // Padding happens on the right
uint32 y = uint32(x4); // Conversion is consistent uint32 y = uint32(x4); // Conversion is consistent
// 'msg.value' cannot be used in a 'non-payable' function. // 'msg.value' cannot be used in a 'non-payable' function.
// We need to make the function payable // We need to make the function payable
myNumber += y + msg.value; myNumber += y + msg.value;
} }
} }
// We can define a library for explicitly converting ``address`` // We can define a library for explicitly converting ``address``
// to ``address payable`` as a workaround. // to ``address payable`` as a workaround.
library address_make_payable { library address_make_payable {
function make_payable(address x) internal pure returns (address payable) { function make_payable(address x) internal pure returns (address payable) {
return address(uint160(x)); return address(uint160(x));
} }
} }

View File

@ -150,24 +150,24 @@ to write a function, for example:
:: ::
pragma solidity >=0.4.0 <0.7.0; pragma solidity >=0.4.0 <0.7.0;
contract arrayExample { contract arrayExample {
// public state variable // public state variable
uint[] public myArray; uint[] public myArray;
// Getter function generated by the compiler // Getter function generated by the compiler
/* /*
function myArray(uint i) returns (uint) { function myArray(uint i) public view returns (uint) {
return myArray[i]; return myArray[i];
}
*/
// function that returns entire array
function getArray() public view returns (uint[] memory) {
return myArray;
}
} }
*/
// function that returns entire array
function getArray() returns (uint[] memory) {
return myArray;
}
}
Now you can use ``getArray()`` to retrieve the entire array, instead of Now you can use ``getArray()`` to retrieve the entire array, instead of
``myArray(i)``, which returns a single element per call. ``myArray(i)``, which returns a single element per call.

View File

@ -37,7 +37,7 @@ breaking changes. These releases always have versions of the form
The version pragma is used as follows:: The version pragma is used as follows::
pragma solidity ^0.5.2; pragma solidity ^0.5.2;
A source file with the line above does not compile with a compiler earlier than version 0.5.2, A source file with the line above does not compile with a compiler earlier than version 0.5.2,
and it also does not work on a compiler starting from version 0.6.0 (this and it also does not work on a compiler starting from version 0.6.0 (this

View File

@ -49,22 +49,22 @@ The following example shows a contract and a function using all available tags.
.. code:: solidity .. code:: solidity
pragma solidity ^0.5.6; pragma solidity ^0.5.6;
/// @title A simulator for trees /// @title A simulator for trees
/// @author Larry A. Gardner /// @author Larry A. Gardner
/// @notice You can use this contract for only the most basic simulation /// @notice You can use this contract for only the most basic simulation
/// @dev All function calls are currently implemented without side effects /// @dev All function calls are currently implemented without side effects
contract Tree { contract Tree {
/// @author Mary A. Botanist /// @author Mary A. Botanist
/// @notice Calculate tree age in years, rounded up, for live trees /// @notice Calculate tree age in years, rounded up, for live trees
/// @dev The Alexandr N. Tetearing algorithm could increase precision /// @dev The Alexandr N. Tetearing algorithm could increase precision
/// @param rings The number of rings from dendrochronological sample /// @param rings The number of rings from dendrochronological sample
/// @return age in years, rounded up for partial years /// @return age in years, rounded up for partial years
function age(uint256 rings) external pure returns (uint256) { function age(uint256 rings) external pure returns (uint256) {
return rings + 1; return rings + 1;
} }
} }
.. _header-tags: .. _header-tags:

View File

@ -499,26 +499,26 @@ not mean loss of proving power.
:: ::
pragma solidity >=0.5.0; pragma solidity >=0.5.0;
pragma experimental SMTChecker; pragma experimental SMTChecker;
contract Recover contract Recover
{ {
function f( function f(
bytes32 hash, bytes32 hash,
uint8 _v1, uint8 _v2, uint8 _v1, uint8 _v2,
bytes32 _r1, bytes32 _r2, bytes32 _r1, bytes32 _r2,
bytes32 _s1, bytes32 _s2 bytes32 _s1, bytes32 _s2
) public pure returns (address) { ) public pure returns (address) {
address a1 = ecrecover(hash, _v1, _r1, _s1); address a1 = ecrecover(hash, _v1, _r1, _s1);
require(_v1 == _v2); require(_v1 == _v2);
require(_r1 == _r2); require(_r1 == _r2);
require(_s1 == _s2); require(_s1 == _s2);
address a2 = ecrecover(hash, _v2, _r2, _s2); address a2 = ecrecover(hash, _v2, _r2, _s2);
assert(a1 == a2); assert(a1 == a2);
return a1; return a1;
} }
} }
In the example above, the SMTChecker is not expressive enough to actually In the example above, the SMTChecker is not expressive enough to actually
compute ``ecrecover``, but by modelling the function calls as uninterpreted compute ``ecrecover``, but by modelling the function calls as uninterpreted
@ -552,34 +552,34 @@ types.
:: ::
pragma solidity >=0.5.0; pragma solidity >=0.5.0;
pragma experimental SMTChecker; pragma experimental SMTChecker;
// This will not compile // This will report a warning
contract Aliasing contract Aliasing
{ {
uint[] array; uint[] array;
function f( function f(
uint[] memory a, uint[] memory a,
uint[] memory b, uint[] memory b,
uint[][] memory c, uint[][] memory c,
uint[] storage d uint[] storage d
) internal view { ) internal view {
require(array[0] == 42); require(array[0] == 42);
require(a[0] == 2); require(a[0] == 2);
require(c[0][0] == 2); require(c[0][0] == 2);
require(d[0] == 2); require(d[0] == 2);
b[0] = 1; b[0] = 1;
// Erasing knowledge about memory references should not // Erasing knowledge about memory references should not
// erase knowledge about state variables. // erase knowledge about state variables.
assert(array[0] == 42); assert(array[0] == 42);
// Fails because `a == b` is possible. // Fails because `a == b` is possible.
assert(a[0] == 2); assert(a[0] == 2);
// Fails because `c[i] == b` is possible. // Fails because `c[i] == b` is possible.
assert(c[0][0] == 2); assert(c[0][0] == 2);
assert(d[0] == 2); assert(d[0] == 2);
assert(b[0] == 1); assert(b[0] == 1);
} }
} }
After the assignment to ``b[0]``, we need to clear knowledge about ``a`` since After the assignment to ``b[0]``, we need to clear knowledge about ``a`` since
it has the same type (``uint[]``) and data location (memory). We also need to it has the same type (``uint[]``) and data location (memory). We also need to

View File

@ -39,6 +39,7 @@ def extract_test_cases(path):
# and abort a line not indented properly. # and abort a line not indented properly.
def extract_docs_cases(path): def extract_docs_cases(path):
inside = False inside = False
extractedLines = []
tests = [] tests = []
# Collect all snippets of indented blocks # Collect all snippets of indented blocks
@ -46,15 +47,23 @@ def extract_docs_cases(path):
if l != '': if l != '':
if not inside and l.startswith(' '): if not inside and l.startswith(' '):
# start new test # start new test
tests += [''] extractedLines += ['']
inside = l.startswith(' ') inside = l.startswith(' ')
if inside: if inside:
tests[-1] += l + '\n' extractedLines[-1] += l + '\n'
# Filter all tests that do not contain Solidity
return [ codeStart = "(pragma solidity|contract.*{|library.*{|interface.*{)"
test for test in tests
if re.search(r'^ [ ]*(pragma solidity|contract |library |interface )', test, re.MULTILINE) # Filter all tests that do not contain Solidity or are intended incorrectly.
] for lines in extractedLines:
if re.search(r'^\s{0,3}' + codeStart, lines, re.MULTILINE):
print("Intendation error in " + path + ":")
print(lines)
exit(1)
if re.search(r'^\s{4}' + codeStart, lines, re.MULTILINE):
tests.append(lines)
return tests
def write_cases(f, tests): def write_cases(f, tests):
cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower() cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()