mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fixes source extraction from docs.
This commit is contained in:
parent
abf1aa74cf
commit
ec53899a10
@ -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
|
||||
pragma solidity ^0.4.25;
|
||||
contract OldContract {
|
||||
function someOldFunction(uint8 a) {
|
||||
//...
|
||||
}
|
||||
function anotherOldFunction() constant returns (bool) {
|
||||
//...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
// This will not compile with the current version of the compiler
|
||||
pragma solidity ^0.4.25;
|
||||
contract OldContract {
|
||||
function someOldFunction(uint8 a) {
|
||||
//...
|
||||
}
|
||||
function anotherOldFunction() constant returns (bool) {
|
||||
//...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
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;
|
||||
interface OldContract {
|
||||
function someOldFunction(uint8 a) external;
|
||||
function anotherOldFunction() external returns (bool);
|
||||
}
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
interface OldContract {
|
||||
function someOldFunction(uint8 a) external;
|
||||
function anotherOldFunction() external returns (bool);
|
||||
}
|
||||
|
||||
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.
|
||||
@ -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 {
|
||||
function someOldFunction(uint8 a) external;
|
||||
function anotherOldFunction() external returns (bool);
|
||||
}
|
||||
interface OldContract {
|
||||
function someOldFunction(uint8 a) external;
|
||||
function anotherOldFunction() external returns (bool);
|
||||
}
|
||||
|
||||
contract NewContract {
|
||||
function doSomething(OldContract a) public returns (bool) {
|
||||
a.someOldFunction(0x42);
|
||||
return a.anotherOldFunction();
|
||||
}
|
||||
}
|
||||
contract NewContract {
|
||||
function doSomething(OldContract a) public returns (bool) {
|
||||
a.someOldFunction(0x42);
|
||||
return a.anotherOldFunction();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -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 {
|
||||
function someFunction(uint8 a) public returns(bool);
|
||||
}
|
||||
library OldLibrary {
|
||||
function someFunction(uint8 a) public returns(bool);
|
||||
}
|
||||
|
||||
contract NewContract {
|
||||
function f(uint8 a) public returns (bool) {
|
||||
return OldLibrary.someFunction(a);
|
||||
}
|
||||
}
|
||||
contract NewContract {
|
||||
function f(uint8 a) public returns (bool) {
|
||||
return OldLibrary.someFunction(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Example
|
||||
@ -368,144 +368,144 @@ Old version:
|
||||
|
||||
::
|
||||
|
||||
// This will not compile
|
||||
pragma solidity ^0.4.25;
|
||||
// This will not compile
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
contract OtherContract {
|
||||
uint x;
|
||||
function f(uint y) external {
|
||||
x = y;
|
||||
}
|
||||
function() payable external {}
|
||||
}
|
||||
contract OtherContract {
|
||||
uint x;
|
||||
function f(uint y) external {
|
||||
x = y;
|
||||
}
|
||||
function() payable external {}
|
||||
}
|
||||
|
||||
contract Old {
|
||||
OtherContract other;
|
||||
uint myNumber;
|
||||
contract Old {
|
||||
OtherContract other;
|
||||
uint myNumber;
|
||||
|
||||
// Function mutability not provided, not an error.
|
||||
function someInteger() internal returns (uint) { return 2; }
|
||||
// Function mutability not provided, not an error.
|
||||
function someInteger() internal returns (uint) { return 2; }
|
||||
|
||||
// Function visibility not provided, not an error.
|
||||
// Function mutability not provided, not an error.
|
||||
function f(uint x) returns (bytes) {
|
||||
// Var is fine in this version.
|
||||
var z = someInteger();
|
||||
x += z;
|
||||
// Throw is fine in this version.
|
||||
if (x > 100)
|
||||
throw;
|
||||
bytes b = new bytes(x);
|
||||
y = -3 >> 1;
|
||||
// y == -1 (wrong, should be -2)
|
||||
do {
|
||||
x += 1;
|
||||
if (x > 10) continue;
|
||||
// 'Continue' causes an infinite loop.
|
||||
} while (x < 11);
|
||||
// Call returns only a Bool.
|
||||
bool success = address(other).call("f");
|
||||
if (!success)
|
||||
revert();
|
||||
else {
|
||||
// Local variables could be declared after their use.
|
||||
int y;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
// Function visibility not provided, not an error.
|
||||
// Function mutability not provided, not an error.
|
||||
function f(uint x) returns (bytes) {
|
||||
// Var is fine in this version.
|
||||
var z = someInteger();
|
||||
x += z;
|
||||
// Throw is fine in this version.
|
||||
if (x > 100)
|
||||
throw;
|
||||
bytes b = new bytes(x);
|
||||
y = -3 >> 1;
|
||||
// y == -1 (wrong, should be -2)
|
||||
do {
|
||||
x += 1;
|
||||
if (x > 10) continue;
|
||||
// 'Continue' causes an infinite loop.
|
||||
} while (x < 11);
|
||||
// Call returns only a Bool.
|
||||
bool success = address(other).call("f");
|
||||
if (!success)
|
||||
revert();
|
||||
else {
|
||||
// Local variables could be declared after their use.
|
||||
int y;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// No need for an explicit data location for 'arr'
|
||||
function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
|
||||
otherContract.transfer(1 ether);
|
||||
// No need for an explicit data location for 'arr'
|
||||
function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
|
||||
otherContract.transfer(1 ether);
|
||||
|
||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||
// the first 4 bytes of x will be lost. This might lead to
|
||||
// unexpected behavior since bytesX are right padded.
|
||||
uint32 y = uint32(x);
|
||||
myNumber += y + msg.value;
|
||||
}
|
||||
}
|
||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||
// the first 4 bytes of x will be lost. This might lead to
|
||||
// unexpected behavior since bytesX are right padded.
|
||||
uint32 y = uint32(x);
|
||||
myNumber += y + msg.value;
|
||||
}
|
||||
}
|
||||
|
||||
New version:
|
||||
|
||||
::
|
||||
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
|
||||
contract OtherContract {
|
||||
uint x;
|
||||
function f(uint y) external {
|
||||
x = y;
|
||||
}
|
||||
function() payable external {}
|
||||
}
|
||||
contract OtherContract {
|
||||
uint x;
|
||||
function f(uint y) external {
|
||||
x = y;
|
||||
}
|
||||
function() payable external {}
|
||||
}
|
||||
|
||||
contract New {
|
||||
OtherContract other;
|
||||
uint myNumber;
|
||||
contract New {
|
||||
OtherContract other;
|
||||
uint myNumber;
|
||||
|
||||
// Function mutability must be specified.
|
||||
function someInteger() internal pure returns (uint) { return 2; }
|
||||
// Function mutability must be specified.
|
||||
function someInteger() internal pure returns (uint) { return 2; }
|
||||
|
||||
// Function visibility must be specified.
|
||||
// Function mutability must be specified.
|
||||
function f(uint x) public returns (bytes memory) {
|
||||
// The type must now be explicitly given.
|
||||
uint z = someInteger();
|
||||
x += z;
|
||||
// Throw is now disallowed.
|
||||
require(x > 100);
|
||||
int y = -3 >> 1;
|
||||
// y == -2 (correct)
|
||||
do {
|
||||
x += 1;
|
||||
if (x > 10) continue;
|
||||
// 'Continue' jumps to the condition below.
|
||||
} while (x < 11);
|
||||
// Function visibility must be specified.
|
||||
// Function mutability must be specified.
|
||||
function f(uint x) public returns (bytes memory) {
|
||||
// The type must now be explicitly given.
|
||||
uint z = someInteger();
|
||||
x += z;
|
||||
// Throw is now disallowed.
|
||||
require(x > 100);
|
||||
int y = -3 >> 1;
|
||||
require(y == -2);
|
||||
do {
|
||||
x += 1;
|
||||
if (x > 10) continue;
|
||||
// 'Continue' jumps to the condition below.
|
||||
} while (x < 11);
|
||||
|
||||
// Call returns (bool, bytes).
|
||||
// Data location must be specified.
|
||||
(bool success, bytes memory data) = address(other).call("f");
|
||||
if (!success)
|
||||
revert();
|
||||
return data;
|
||||
}
|
||||
// Call returns (bool, bytes).
|
||||
// Data location must be specified.
|
||||
(bool success, bytes memory data) = address(other).call("f");
|
||||
if (!success)
|
||||
revert();
|
||||
return data;
|
||||
}
|
||||
|
||||
using address_make_payable for address;
|
||||
// Data location for 'arr' must be specified
|
||||
function g(uint[] memory arr, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
|
||||
// 'otherContract.transfer' is not provided.
|
||||
// Since the code of 'OtherContract' is known and has the fallback
|
||||
// function, address(otherContract) has type 'address payable'.
|
||||
address(otherContract).transfer(1 ether);
|
||||
using address_make_payable for address;
|
||||
// Data location for 'arr' must be specified
|
||||
function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
|
||||
// 'otherContract.transfer' is not provided.
|
||||
// Since the code of 'OtherContract' is known and has the fallback
|
||||
// function, address(otherContract) has type 'address payable'.
|
||||
address(otherContract).transfer(1 ether);
|
||||
|
||||
// 'unknownContract.transfer' is not provided.
|
||||
// 'address(unknownContract).transfer' is not provided
|
||||
// since 'address(unknownContract)' is not 'address payable'.
|
||||
// If the function takes an 'address' which you want to send
|
||||
// funds to, you can convert it to 'address payable' via 'uint160'.
|
||||
// Note: This is not recommended and the explicit type
|
||||
// 'address payable' should be used whenever possible.
|
||||
// To increase clarity, we suggest the use of a library for
|
||||
// the conversion (provided after the contract in this example).
|
||||
address payable addr = unknownContract.make_payable();
|
||||
require(addr.send(1 ether));
|
||||
// 'unknownContract.transfer' is not provided.
|
||||
// 'address(unknownContract).transfer' is not provided
|
||||
// since 'address(unknownContract)' is not 'address payable'.
|
||||
// If the function takes an 'address' which you want to send
|
||||
// funds to, you can convert it to 'address payable' via 'uint160'.
|
||||
// Note: This is not recommended and the explicit type
|
||||
// 'address payable' should be used whenever possible.
|
||||
// To increase clarity, we suggest the use of a library for
|
||||
// the conversion (provided after the contract in this example).
|
||||
address payable addr = unknownContract.make_payable();
|
||||
require(addr.send(1 ether));
|
||||
|
||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||
// the conversion is not allowed.
|
||||
// We need to convert to a common size first:
|
||||
bytes4 x4 = bytes4(x); // Padding happens on the right
|
||||
uint32 y = uint32(x4); // Conversion is consistent
|
||||
// 'msg.value' cannot be used in a 'non-payable' function.
|
||||
// We need to make the function payable
|
||||
myNumber += y + msg.value;
|
||||
}
|
||||
}
|
||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||
// the conversion is not allowed.
|
||||
// We need to convert to a common size first:
|
||||
bytes4 x4 = bytes4(x); // Padding happens on the right
|
||||
uint32 y = uint32(x4); // Conversion is consistent
|
||||
// 'msg.value' cannot be used in a 'non-payable' function.
|
||||
// We need to make the function payable
|
||||
myNumber += y + msg.value;
|
||||
}
|
||||
}
|
||||
|
||||
// We can define a library for explicitly converting ``address``
|
||||
// to ``address payable`` as a workaround.
|
||||
library address_make_payable {
|
||||
function make_payable(address x) internal pure returns (address payable) {
|
||||
return address(uint160(x));
|
||||
}
|
||||
}
|
||||
// We can define a library for explicitly converting ``address``
|
||||
// to ``address payable`` as a workaround.
|
||||
library address_make_payable {
|
||||
function make_payable(address x) internal pure returns (address payable) {
|
||||
return address(uint160(x));
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
// public state variable
|
||||
uint[] public myArray;
|
||||
contract arrayExample {
|
||||
// public state variable
|
||||
uint[] public myArray;
|
||||
|
||||
// Getter function generated by the compiler
|
||||
/*
|
||||
function myArray(uint i) returns (uint) {
|
||||
return myArray[i];
|
||||
// Getter function generated by the compiler
|
||||
/*
|
||||
function myArray(uint i) public view returns (uint) {
|
||||
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
|
||||
``myArray(i)``, which returns a single element per call.
|
||||
|
@ -37,7 +37,7 @@ breaking changes. These releases always have versions of the form
|
||||
|
||||
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,
|
||||
and it also does not work on a compiler starting from version 0.6.0 (this
|
||||
|
@ -49,22 +49,22 @@ The following example shows a contract and a function using all available tags.
|
||||
|
||||
.. code:: solidity
|
||||
|
||||
pragma solidity ^0.5.6;
|
||||
pragma solidity ^0.5.6;
|
||||
|
||||
/// @title A simulator for trees
|
||||
/// @author Larry A. Gardner
|
||||
/// @notice You can use this contract for only the most basic simulation
|
||||
/// @dev All function calls are currently implemented without side effects
|
||||
contract Tree {
|
||||
/// @author Mary A. Botanist
|
||||
/// @notice Calculate tree age in years, rounded up, for live trees
|
||||
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
||||
/// @param rings The number of rings from dendrochronological sample
|
||||
/// @return age in years, rounded up for partial years
|
||||
function age(uint256 rings) external pure returns (uint256) {
|
||||
return rings + 1;
|
||||
}
|
||||
}
|
||||
/// @title A simulator for trees
|
||||
/// @author Larry A. Gardner
|
||||
/// @notice You can use this contract for only the most basic simulation
|
||||
/// @dev All function calls are currently implemented without side effects
|
||||
contract Tree {
|
||||
/// @author Mary A. Botanist
|
||||
/// @notice Calculate tree age in years, rounded up, for live trees
|
||||
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
||||
/// @param rings The number of rings from dendrochronological sample
|
||||
/// @return age in years, rounded up for partial years
|
||||
function age(uint256 rings) external pure returns (uint256) {
|
||||
return rings + 1;
|
||||
}
|
||||
}
|
||||
|
||||
.. _header-tags:
|
||||
|
||||
|
@ -499,26 +499,26 @@ not mean loss of proving power.
|
||||
|
||||
::
|
||||
|
||||
pragma solidity >=0.5.0;
|
||||
pragma experimental SMTChecker;
|
||||
pragma solidity >=0.5.0;
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract Recover
|
||||
{
|
||||
function f(
|
||||
bytes32 hash,
|
||||
uint8 _v1, uint8 _v2,
|
||||
bytes32 _r1, bytes32 _r2,
|
||||
bytes32 _s1, bytes32 _s2
|
||||
) public pure returns (address) {
|
||||
address a1 = ecrecover(hash, _v1, _r1, _s1);
|
||||
require(_v1 == _v2);
|
||||
require(_r1 == _r2);
|
||||
require(_s1 == _s2);
|
||||
address a2 = ecrecover(hash, _v2, _r2, _s2);
|
||||
assert(a1 == a2);
|
||||
return a1;
|
||||
}
|
||||
}
|
||||
contract Recover
|
||||
{
|
||||
function f(
|
||||
bytes32 hash,
|
||||
uint8 _v1, uint8 _v2,
|
||||
bytes32 _r1, bytes32 _r2,
|
||||
bytes32 _s1, bytes32 _s2
|
||||
) public pure returns (address) {
|
||||
address a1 = ecrecover(hash, _v1, _r1, _s1);
|
||||
require(_v1 == _v2);
|
||||
require(_r1 == _r2);
|
||||
require(_s1 == _s2);
|
||||
address a2 = ecrecover(hash, _v2, _r2, _s2);
|
||||
assert(a1 == a2);
|
||||
return a1;
|
||||
}
|
||||
}
|
||||
|
||||
In the example above, the SMTChecker is not expressive enough to actually
|
||||
compute ``ecrecover``, but by modelling the function calls as uninterpreted
|
||||
@ -552,34 +552,34 @@ types.
|
||||
|
||||
::
|
||||
|
||||
pragma solidity >=0.5.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This will not compile
|
||||
contract Aliasing
|
||||
{
|
||||
uint[] array;
|
||||
function f(
|
||||
uint[] memory a,
|
||||
uint[] memory b,
|
||||
uint[][] memory c,
|
||||
uint[] storage d
|
||||
) internal view {
|
||||
require(array[0] == 42);
|
||||
require(a[0] == 2);
|
||||
require(c[0][0] == 2);
|
||||
require(d[0] == 2);
|
||||
b[0] = 1;
|
||||
// Erasing knowledge about memory references should not
|
||||
// erase knowledge about state variables.
|
||||
assert(array[0] == 42);
|
||||
// Fails because `a == b` is possible.
|
||||
assert(a[0] == 2);
|
||||
// Fails because `c[i] == b` is possible.
|
||||
assert(c[0][0] == 2);
|
||||
assert(d[0] == 2);
|
||||
assert(b[0] == 1);
|
||||
}
|
||||
}
|
||||
pragma solidity >=0.5.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This will report a warning
|
||||
contract Aliasing
|
||||
{
|
||||
uint[] array;
|
||||
function f(
|
||||
uint[] memory a,
|
||||
uint[] memory b,
|
||||
uint[][] memory c,
|
||||
uint[] storage d
|
||||
) internal view {
|
||||
require(array[0] == 42);
|
||||
require(a[0] == 2);
|
||||
require(c[0][0] == 2);
|
||||
require(d[0] == 2);
|
||||
b[0] = 1;
|
||||
// Erasing knowledge about memory references should not
|
||||
// erase knowledge about state variables.
|
||||
assert(array[0] == 42);
|
||||
// Fails because `a == b` is possible.
|
||||
assert(a[0] == 2);
|
||||
// Fails because `c[i] == b` is possible.
|
||||
assert(c[0][0] == 2);
|
||||
assert(d[0] == 2);
|
||||
assert(b[0] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -39,6 +39,7 @@ def extract_test_cases(path):
|
||||
# and abort a line not indented properly.
|
||||
def extract_docs_cases(path):
|
||||
inside = False
|
||||
extractedLines = []
|
||||
tests = []
|
||||
|
||||
# Collect all snippets of indented blocks
|
||||
@ -46,15 +47,23 @@ def extract_docs_cases(path):
|
||||
if l != '':
|
||||
if not inside and l.startswith(' '):
|
||||
# start new test
|
||||
tests += ['']
|
||||
extractedLines += ['']
|
||||
inside = l.startswith(' ')
|
||||
if inside:
|
||||
tests[-1] += l + '\n'
|
||||
# Filter all tests that do not contain Solidity
|
||||
return [
|
||||
test for test in tests
|
||||
if re.search(r'^ [ ]*(pragma solidity|contract |library |interface )', test, re.MULTILINE)
|
||||
]
|
||||
extractedLines[-1] += l + '\n'
|
||||
|
||||
codeStart = "(pragma solidity|contract.*{|library.*{|interface.*{)"
|
||||
|
||||
# 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):
|
||||
cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
|
||||
|
Loading…
Reference in New Issue
Block a user