Merge pull request #4788 from ethereum/noWarnDoc

Test that documentation does not contain any warnings.
This commit is contained in:
chriseth 2018-08-14 16:33:39 +02:00 committed by GitHub
commit 414559bd07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 262 additions and 180 deletions

View File

@ -494,8 +494,8 @@ As an example, the code
contract Test { contract Test {
struct S { uint a; uint[] b; T[] c; } struct S { uint a; uint[] b; T[] c; }
struct T { uint x; uint y; } struct T { uint x; uint y; }
function f(S memory s, T memory t, uint a) public { } function f(S memory s, T memory t, uint a) public;
function g() public returns (S memory s, T memory t, uint a) {} function g() public returns (S memory s, T memory t, uint a);
} }
would result in the JSON: would result in the JSON:

View File

@ -82,7 +82,7 @@ you really know what you are doing.
library VectorSum { library VectorSum {
// This function is less efficient because the optimizer currently fails to // This function is less efficient because the optimizer currently fails to
// remove the bounds checks in array access. // remove the bounds checks in array access.
function sumSolidity(uint[] memory _data) public view returns (uint o_sum) { function sumSolidity(uint[] memory _data) public pure returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i) for (uint i = 0; i < _data.length; ++i)
o_sum += _data[i]; o_sum += _data[i];
} }
@ -90,7 +90,7 @@ you really know what you are doing.
// We know that we only access the array in bounds, so we can avoid the check. // We know that we only access the array in bounds, so we can avoid the check.
// 0x20 needs to be added to an array because the first slot contains the // 0x20 needs to be added to an array because the first slot contains the
// array length. // array length.
function sumAsm(uint[] memory _data) public view returns (uint o_sum) { function sumAsm(uint[] memory _data) public pure returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i) { for (uint i = 0; i < _data.length; ++i) {
assembly { assembly {
o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20)))) o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
@ -99,7 +99,7 @@ you really know what you are doing.
} }
// Same as above, but accomplish the entire code within inline assembly. // Same as above, but accomplish the entire code within inline assembly.
function sumPureAsm(uint[] memory _data) public view returns (uint o_sum) { function sumPureAsm(uint[] memory _data) public pure returns (uint o_sum) {
assembly { assembly {
// Load the length (first 32 bytes) // Load the length (first 32 bytes)
let len := mload(_data) let len := mload(_data)
@ -378,23 +378,13 @@ used ``x_slot`` and to retrieve the byte-offset you used ``x_offset``.
In assignments (see below), we can even use local Solidity variables to assign to. In assignments (see below), we can even use local Solidity variables to assign to.
Functions external to inline assembly can also be accessed: The assembly will
push their entry label (with virtual function resolution applied). The calling semantics
in solidity are:
- the caller pushes ``return label``, ``arg1``, ``arg2``, ..., ``argn``
- the call returns with ``ret1``, ``ret2``, ..., ``retm``
This feature is still a bit cumbersome to use, because the stack offset essentially
changes during the call, and thus references to local variables will be wrong.
.. code:: .. code::
pragma solidity ^0.4.11; pragma solidity ^0.4.11;
contract C { contract C {
uint b; uint b;
function f(uint x) public returns (uint r) { function f(uint x) public view returns (uint r) {
assembly { assembly {
r := mul(x, sload(b_slot)) // ignore the offset, we know it is zero r := mul(x, sload(b_slot)) // ignore the offset, we know it is zero
} }

View File

@ -198,7 +198,7 @@ restrictions highly readable.
); );
_; _;
if (msg.value > _amount) if (msg.value > _amount)
msg.sender.send(msg.value - _amount); msg.sender.transfer(msg.value - _amount);
} }
function forceOwnerChange(address _newOwner) function forceOwnerChange(address _newOwner)

View File

@ -110,11 +110,11 @@ This means that cyclic creation dependencies are impossible.
function isTokenTransferOK(address currentOwner, address newOwner) function isTokenTransferOK(address currentOwner, address newOwner)
public public
view pure
returns (bool ok) returns (bool ok)
{ {
// Check some arbitrary condition. // Check some arbitrary condition.
return currentOwner != newOwner; return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
} }
} }
@ -137,16 +137,16 @@ Functions have to be specified as being ``external``,
For state variables, ``external`` is not possible. For state variables, ``external`` is not possible.
``external``: ``external``:
External functions are part of the contract External functions are part of the contract interface,
interface, which means they can be called from other contracts and which means they can be called from other contracts and
via transactions. An external function ``f`` cannot be called via transactions. An external function ``f`` cannot be called
internally (i.e. ``f()`` does not work, but ``this.f()`` works). internally (i.e. ``f()`` does not work, but ``this.f()`` works).
External functions are sometimes more efficient when External functions are sometimes more efficient when
they receive large arrays of data. they receive large arrays of data.
``public``: ``public``:
Public functions are part of the contract Public functions are part of the contract interface
interface and can be either called internally or via and can be either called internally or via
messages. For public state variables, an automatic getter messages. For public state variables, an automatic getter
function (see below) is generated. function (see below) is generated.
@ -187,8 +187,6 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value
:: ::
// This will not compile
pragma solidity ^0.4.0; pragma solidity ^0.4.0;
contract C { contract C {
@ -200,6 +198,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value
function compute(uint a, uint b) internal pure returns (uint) { return a + b; } function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
} }
// This will not compile
contract D { contract D {
function readData() public { function readData() public {
C c = new C(); C c = new C();
@ -227,8 +226,8 @@ The compiler automatically creates getter functions for
all **public** state variables. For the contract given below, the compiler will all **public** state variables. For the contract given below, the compiler will
generate a function called ``data`` that does not take any generate a function called ``data`` that does not take any
arguments and returns a ``uint``, the value of the state arguments and returns a ``uint``, the value of the state
variable ``data``. The initialization of state variables can variable ``data``. State variables can be initialized
be done at declaration. when they are declared.
:: ::
@ -240,8 +239,8 @@ be done at declaration.
contract Caller { contract Caller {
C c = new C(); C c = new C();
function f() public { function f() public view returns (uint) {
uint local = c.data(); return c.data();
} }
} }
@ -256,9 +255,9 @@ it is evaluated as a state variable. If it is accessed externally
contract C { contract C {
uint public data; uint public data;
function x() public { function x() public returns (uint) {
data = 3; // internal access data = 3; // internal access
uint val = this.data(); // external access return this.data(); // external access
} }
} }
@ -615,14 +614,13 @@ Like any function, the fallback function can execute complex operations as long
} }
contract Caller { contract Caller {
function callTest(Test test) public { function callTest(Test test) public returns (bool) {
address(test).call(abi.encodeWithSignature("nonExistingFunction()")); require(address(test).call(abi.encodeWithSignature("nonExistingFunction()")));
// results in test.x becoming == 1. // results in test.x becoming == 1.
// If someone sends ether to that contract, // If someone sends ether to that contract,
// the transaction will fail and reject the // the transfer will fail, i.e. this returns false here.
// Ether. return address(test).send(2 ether);
address(test).send(2 ether);
} }
} }
@ -633,9 +631,11 @@ Like any function, the fallback function can execute complex operations as long
Function Overloading Function Overloading
==================== ====================
A Contract can have multiple functions of the same name but with different arguments. A contract can have multiple functions of the same name but with different parameter
This also applies to inherited functions. The following example shows overloading of the types.
``f`` function in the scope of contract ``A``. This process is called "overloading" and also applies to inherited functions.
The following example shows overloading of the function
``f`` in the scope of contract ``A``.
:: ::
@ -643,11 +643,12 @@ This also applies to inherited functions. The following example shows overloadin
contract A { contract A {
function f(uint _in) public pure returns (uint out) { function f(uint _in) public pure returns (uint out) {
out = 1; out = _in;
} }
function f(uint _in, bytes32 _key) public pure returns (uint out) { function f(uint _in, bool _really) public pure returns (uint out) {
out = 2; if (_really)
out = _in;
} }
} }
@ -656,9 +657,9 @@ externally visible functions differ by their Solidity types but not by their ext
:: ::
// This will not compile
pragma solidity ^0.4.16; pragma solidity ^0.4.16;
// This will not compile
contract A { contract A {
function f(B _in) public pure returns (B out) { function f(B _in) public pure returns (B out) {
out = _in; out = _in;
@ -1037,10 +1038,12 @@ derived contracts need to specify all of them. This can be done in two ways::
constructor(uint _x) public { x = _x; } constructor(uint _x) public { x = _x; }
} }
// Either directly specify in the inheritance list...
contract Derived1 is Base(7) { contract Derived1 is Base(7) {
constructor(uint _y) public {} constructor() public {}
} }
// or through a "modifier" of the derived constructor.
contract Derived2 is Base { contract Derived2 is Base {
constructor(uint _y) Base(_y * _y) public {} constructor(uint _y) Base(_y * _y) public {}
} }
@ -1079,12 +1082,11 @@ error "Linearization of inheritance graph impossible".
:: ::
// This will not compile
pragma solidity ^0.4.0; pragma solidity ^0.4.0;
contract X {} contract X {}
contract A is X {} contract A is X {}
// This will not compile
contract C is A, X {} contract C is A, X {}
The reason for this is that ``C`` requests ``X`` to override ``A`` The reason for this is that ``C`` requests ``X`` to override ``A``
@ -1342,6 +1344,7 @@ custom types without the overhead of external function calls:
BigInt.bigint memory x = BigInt.fromUint(7); BigInt.bigint memory x = BigInt.fromUint(7);
BigInt.bigint memory y = BigInt.fromUint(uint(-1)); BigInt.bigint memory y = BigInt.fromUint(uint(-1));
BigInt.bigint memory z = x.add(y); BigInt.bigint memory z = x.add(y);
assert(z.limb(1) > 0);
} }
} }

View File

@ -23,8 +23,9 @@ something like::
pragma solidity ^0.4.16; pragma solidity ^0.4.16;
contract Simple { contract Simple {
function taker(uint _a, uint _b) public pure { uint sum;
// do something with _a and _b. function taker(uint _a, uint _b) public {
sum = _a + _b;
} }
} }
@ -102,7 +103,7 @@ this nonsensical example::
pragma solidity ^0.4.16; pragma solidity ^0.4.16;
contract C { contract C {
function g(uint a) public pure returns (uint ret) { return f(); } function g(uint a) public pure returns (uint ret) { return a + f(); }
function f() internal pure returns (uint ret) { return g(7) + f(); } function f() internal pure returns (uint ret) { return g(7) + f(); }
} }
@ -158,8 +159,8 @@ throws an exception or goes out of gas.
.. warning:: .. warning::
Any interaction with another contract imposes a potential danger, especially Any interaction with another contract imposes a potential danger, especially
if the source code of the contract is not known in advance. The current if the source code of the contract is not known in advance. The
contract hands over control to the called contract and that may potentially current contract hands over control to the called contract and that may potentially
do just about anything. Even if the called contract inherits from a known parent contract, do just about anything. Even if the called contract inherits from a known parent contract,
the inheriting contract is only required to have a correct interface. The the inheriting contract is only required to have a correct interface. The
implementation of the contract, however, can be completely arbitrary and thus, implementation of the contract, however, can be completely arbitrary and thus,
@ -184,14 +185,16 @@ parameters from the function declaration, but can be in arbitrary order.
pragma solidity ^0.4.0; pragma solidity ^0.4.0;
contract C { contract C {
function f(uint key, uint value) public { mapping(uint => uint) data;
// ...
function f() public {
set({value: 2, key: 3});
} }
function g() public { function set(uint key, uint value) public {
// named arguments data[key] = value;
f({value: 2, key: 3});
} }
} }
Omitted Function Parameter Names Omitted Function Parameter Names
@ -228,7 +231,7 @@ creation-dependencies are not possible.
pragma solidity >0.4.24; pragma solidity >0.4.24;
contract D { contract D {
uint x; uint public x;
constructor(uint a) public payable { constructor(uint a) public payable {
x = a; x = a;
} }
@ -239,11 +242,13 @@ creation-dependencies are not possible.
function createD(uint arg) public { function createD(uint arg) public {
D newD = new D(arg); D newD = new D(arg);
newD.x();
} }
function createAndEndowD(uint arg, uint amount) public payable { function createAndEndowD(uint arg, uint amount) public payable {
// Send ether along with the creation // Send ether along with the creation
D newD = (new D).value(amount)(arg); D newD = (new D).value(amount)(arg);
newD.x();
} }
} }
@ -287,12 +292,13 @@ These can then either be assigned to newly declared variables or to pre-existing
} }
function g() public { function g() public {
// Variables declared with type and assigned from the returned tuple. // Variables declared with type and assigned from the returned tuple,
(uint x, bool b, uint y) = f(); // not all elements have to be specified (but the number must match).
(uint x, , uint y) = f();
// Common trick to swap values -- does not work for non-value storage types. // Common trick to swap values -- does not work for non-value storage types.
(x, y) = (y, x); (x, y) = (y, x);
// Components can be left out (also for variable declarations). // Components can be left out (also for variable declarations).
(data.length,,) = f(); // Sets the length to 7 (data.length, , ) = f(); // Sets the length to 7
} }
} }
@ -338,11 +344,13 @@ the two variables have the same name but disjoint scopes.
contract C { contract C {
function minimalScoping() pure public { function minimalScoping() pure public {
{ {
uint same2 = 0; uint same;
same = 1;
} }
{ {
uint same2 = 0; uint same;
same = 3;
} }
} }
} }
@ -354,6 +362,7 @@ In any case, you will get a warning about the outer variable being shadowed.
:: ::
pragma solidity >0.4.24; pragma solidity >0.4.24;
// This will report a warning
contract C { contract C {
function f() pure public returns (uint) { function f() pure public returns (uint) {
uint x = 1; uint x = 1;
@ -372,9 +381,8 @@ In any case, you will get a warning about the outer variable being shadowed.
:: ::
// This will not compile
pragma solidity >0.4.24; pragma solidity >0.4.24;
// This will not compile
contract C { contract C {
function f() pure public returns (uint) { function f() pure public returns (uint) {
x = 2; x = 2;

View File

@ -62,7 +62,8 @@ Example::
contract C { contract C {
function f() public pure returns (uint8[5] memory) { function f() public pure returns (uint8[5] memory) {
string[4] memory adaArr = ["This", "is", "an", "array"]; string[4] memory adaArr = ["This", "is", "an", "array"];
return ([1, 2, 3, 4, 5]); adaArr[0] = "That";
return [1, 2, 3, 4, 5];
} }
} }
@ -186,9 +187,10 @@ If you do not want to throw, you can return a pair::
function checkCounter(uint index) public view { function checkCounter(uint index) public view {
(uint counter, bool error) = getCounter(index); (uint counter, bool error) = getCounter(index);
if (error) { if (error) {
// ... // Handle the error
} else { } else {
// ... // Do something with counter.
require(counter > 7, "Invalid counter value");
} }
} }
} }
@ -372,15 +374,14 @@ contract level) with ``arrayname.length = <some new length>;``. If you get the
:: ::
// This will not compile
pragma solidity ^0.4.18; pragma solidity ^0.4.18;
// This will not compile
contract C { contract C {
int8[] dynamicStorageArray; int8[] dynamicStorageArray;
int8[5] fixedStorageArray; int8[5] fixedStorageArray;
function f() { function f() public {
int8[] memory memArr; // Case 1 int8[] memory memArr; // Case 1
memArr.length++; // illegal memArr.length++; // illegal

View File

@ -204,7 +204,7 @@ for the two input parameters and two returned values.
* @return s The calculated surface. * @return s The calculated surface.
* @return p The calculated perimeter. * @return p The calculated perimeter.
*/ */
function rectangle(uint w, uint h) public returns (uint s, uint p) { function rectangle(uint w, uint h) public pure returns (uint s, uint p) {
s = w * h; s = w * h;
p = 2 * (w + h); p = 2 * (w + h);
} }

View File

@ -467,22 +467,22 @@ high or low invalid bids.
uint refund; uint refund;
for (uint i = 0; i < length; i++) { for (uint i = 0; i < length; i++) {
Bid storage bid = bids[msg.sender][i]; Bid storage bidToCheck = bids[msg.sender][i];
(uint value, bool fake, bytes32 secret) = (uint value, bool fake, bytes32 secret) =
(_values[i], _fake[i], _secret[i]); (_values[i], _fake[i], _secret[i]);
if (bid.blindedBid != keccak256(abi.encodePacked(value, fake, secret))) { if (bidToCheck.blindedBid != keccak256(abi.encodePacked(value, fake, secret))) {
// Bid was not actually revealed. // Bid was not actually revealed.
// Do not refund deposit. // Do not refund deposit.
continue; continue;
} }
refund += bid.deposit; refund += bidToCheck.deposit;
if (!fake && bid.deposit >= value) { if (!fake && bidToCheck.deposit >= value) {
if (placeBid(msg.sender, value)) if (placeBid(msg.sender, value))
refund -= value; refund -= value;
} }
// Make it impossible for the sender to re-claim // Make it impossible for the sender to re-claim
// the same deposit. // the same deposit.
bid.blindedBid = bytes32(0); bidToCheck.blindedBid = bytes32(0);
} }
msg.sender.transfer(refund); msg.sender.transfer(refund);
} }

View File

@ -75,7 +75,7 @@ Function modifiers can be used to amend the semantics of functions in a declarat
_; _;
} }
function abort() public onlySeller { // Modifier usage function abort() public view onlySeller { // Modifier usage
// ... // ...
} }
} }

View File

@ -52,31 +52,35 @@ Surround top level declarations in solidity source with two blank lines.
Yes:: Yes::
pragma solidity ^0.4.0;
contract A { contract A {
... // ...
} }
contract B { contract B {
... // ...
} }
contract C { contract C {
... // ...
} }
No:: No::
pragma solidity ^0.4.0;
contract A { contract A {
... // ...
} }
contract B { contract B {
... // ...
} }
contract C { contract C {
... // ...
} }
Within a contract surround function declarations with a single blank line. Within a contract surround function declarations with a single blank line.
@ -85,30 +89,34 @@ Blank lines may be omitted between groups of related one-liners (such as stub fu
Yes:: Yes::
pragma solidity ^0.4.0;
contract A { contract A {
function spam() public; function spam() public pure;
function ham() public; function ham() public pure;
} }
contract B is A { contract B is A {
function spam() public { function spam() public pure {
... // ...
} }
function ham() public { function ham() public pure {
... // ...
} }
} }
No:: No::
pragma solidity ^0.4.0;
contract A { contract A {
function spam() public { function spam() public pure {
... // ...
} }
function ham() public { function ham() public pure {
... // ...
} }
} }
@ -229,22 +237,24 @@ Import statements should always be placed at the top of the file.
Yes:: Yes::
pragma solidity ^0.4.0;
import "./Owned.sol"; import "./Owned.sol";
contract A { contract A {
... // ...
} }
contract B is Owned { contract B is Owned {
... // ...
} }
No:: No::
pragma solidity ^0.4.0;
contract A { contract A {
... // ...
} }
@ -252,7 +262,7 @@ No::
contract B is Owned { contract B is Owned {
... // ...
} }
Order of Functions Order of Functions
@ -273,13 +283,15 @@ Within a grouping, place the ``view`` and ``pure`` functions last.
Yes:: Yes::
pragma solidity ^0.4.0;
contract A { contract A {
constructor() public { constructor() public {
... // ...
} }
function() external { function() external {
... // ...
} }
// External functions // External functions
@ -303,13 +315,15 @@ Yes::
No:: No::
pragma solidity ^0.4.0;
contract A { contract A {
// External functions // External functions
// ... // ...
function() external { function() external {
... // ...
} }
// Private functions // Private functions
@ -319,7 +333,7 @@ No::
// ... // ...
constructor() public { constructor() public {
... // ...
} }
// Internal functions // Internal functions
@ -397,6 +411,8 @@ should:
Yes:: Yes::
pragma solidity ^0.4.0;
contract Coin { contract Coin {
struct Bank { struct Bank {
address owner; address owner;
@ -406,6 +422,8 @@ Yes::
No:: No::
pragma solidity ^0.4.0;
contract Coin contract Coin
{ {
struct Bank { struct Bank {
@ -705,7 +723,25 @@ manner as modifiers if the function declaration is long or hard to read.
Yes:: Yes::
pragma solidity ^0.4.0;
// Base contracts just to make this compile
contract B {
constructor(uint) public {
}
}
contract C {
constructor(uint, uint) public {
}
}
contract D {
constructor(uint) public {
}
}
contract A is B, C, D { contract A is B, C, D {
uint x;
constructor(uint param1, uint param2, uint param3, uint param4, uint param5) constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
B(param1) B(param1)
C(param2, param3) C(param2, param3)
@ -713,29 +749,50 @@ Yes::
public public
{ {
// do something with param5 // do something with param5
x = param5;
} }
} }
No:: No::
pragma solidity ^0.4.0;
// Base contracts just to make this compile
contract B {
constructor(uint) public {
}
}
contract C {
constructor(uint, uint) public {
}
}
contract D {
constructor(uint) public {
}
}
contract A is B, C, D { contract A is B, C, D {
uint x;
constructor(uint param1, uint param2, uint param3, uint param4, uint param5) constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
B(param1) B(param1)
C(param2, param3) C(param2, param3)
D(param4) D(param4)
public public
{ {
// do something with param5 x = param5;
} }
} }
contract A is B, C, D { contract X is B, C, D {
uint x;
constructor(uint param1, uint param2, uint param3, uint param4, uint param5) constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
B(param1) B(param1)
C(param2, param3) C(param2, param3)
D(param4) D(param4)
public { public {
// do something with param5 x = param5;
} }
} }
@ -875,6 +932,8 @@ As shown in the example below, if the contract name is `Congress` and the librar
Yes:: Yes::
pragma solidity ^0.4.0;
// Owned.sol // Owned.sol
contract Owned { contract Owned {
address public owner; address public owner;
@ -897,11 +956,13 @@ Yes::
import "./Owned.sol"; import "./Owned.sol";
contract Congress is Owned, TokenRecipient { contract Congress is Owned, TokenRecipient {
... //...
} }
No:: No::
pragma solidity ^0.4.0;
// owned.sol // owned.sol
contract owned { contract owned {
address public owner; address public owner;
@ -924,7 +985,7 @@ No::
import "./owned.sol"; import "./owned.sol";
contract Congress is owned, tokenRecipient { contract Congress is owned, tokenRecipient {
... //...
} }

View File

@ -447,7 +447,7 @@ which returns the :ref:`ABI function selector <abi_function_selector>`::
pragma solidity ^0.4.16; pragma solidity ^0.4.16;
contract Selector { contract Selector {
function f() public view returns (bytes4) { function f() public pure returns (bytes4) {
return this.f.selector; return this.f.selector;
} }
} }
@ -510,15 +510,15 @@ Another example that uses external function types::
contract Oracle { contract Oracle {
struct Request { struct Request {
bytes data; bytes data;
function(bytes memory) external callback; function(uint) external callback;
} }
Request[] requests; Request[] requests;
event NewRequest(uint); event NewRequest(uint);
function query(bytes memory data, function(bytes memory) external callback) public { function query(bytes memory data, function(uint) external callback) public {
requests.push(Request(data, callback)); requests.push(Request(data, callback));
emit NewRequest(requests.length - 1); emit NewRequest(requests.length - 1);
} }
function reply(uint requestID, bytes memory response) public { function reply(uint requestID, uint response) public {
// Here goes the check that the reply comes from a trusted source // Here goes the check that the reply comes from a trusted source
requests[requestID].callback(response); requests[requestID].callback(response);
} }
@ -526,15 +526,16 @@ Another example that uses external function types::
contract OracleUser { contract OracleUser {
Oracle constant oracle = Oracle(0x1234567); // known contract Oracle constant oracle = Oracle(0x1234567); // known contract
uint exchangeRate;
function buySomething() public { function buySomething() public {
oracle.query("USD", this.oracleResponse); oracle.query("USD", this.oracleResponse);
} }
function oracleResponse(bytes memory response) public { function oracleResponse(uint response) public {
require( require(
msg.sender == address(oracle), msg.sender == address(oracle),
"Only oracle can call this." "Only oracle can call this."
); );
// Use the data exchangeRate = response;
} }
} }
@ -601,8 +602,8 @@ memory-stored reference type do not create a copy.
h(x); // calls h and creates an independent, temporary copy in memory h(x); // calls h and creates an independent, temporary copy in memory
} }
function g(uint[] storage storageArray) internal {} function g(uint[] storage) internal pure {}
function h(uint[] memory memoryArray) public {} function h(uint[] memory) public pure {}
} }
Summary Summary
@ -659,8 +660,9 @@ Allocating Memory Arrays
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
Creating arrays with variable length in memory can be done using the ``new`` keyword. Creating arrays with variable length in memory can be done using the ``new`` keyword.
As opposed to storage arrays, it is **not** possible to resize memory arrays by assigning to As opposed to storage arrays, it is **not** possible to resize memory arrays (e.g. by assigning to
the ``.length`` member. the ``.length`` member). You either have to calculate the required size in advance
or create a new memory array and copy every element.
:: ::
@ -670,7 +672,8 @@ the ``.length`` member.
function f(uint len) public pure { function f(uint len) public pure {
uint[] memory a = new uint[](7); uint[] memory a = new uint[](7);
bytes memory b = new bytes(len); bytes memory b = new bytes(len);
// Here we have a.length == 7 and b.length == len assert(a.length == 7);
assert(b.length == len);
a[6] = 8; a[6] = 8;
} }
} }
@ -691,7 +694,7 @@ assigned to a variable right away.
function f() public pure { function f() public pure {
g([uint(1), 2, 3]); g([uint(1), 2, 3]);
} }
function g(uint[3] memory _data) public pure { function g(uint[3] memory) public pure {
// ... // ...
} }
} }
@ -706,10 +709,9 @@ possible:
:: ::
// This will not compile.
pragma solidity ^0.4.0; pragma solidity ^0.4.0;
// This will not compile.
contract C { contract C {
function f() public { function f() public {
// The next line creates a type error because uint[3] memory // The next line creates a type error because uint[3] memory
@ -752,9 +754,12 @@ Members
uint[2**20] m_aLotOfIntegers; uint[2**20] m_aLotOfIntegers;
// Note that the following is not a pair of dynamic arrays but a // Note that the following is not a pair of dynamic arrays but a
// dynamic array of pairs (i.e. of fixed size arrays of length two). // dynamic array of pairs (i.e. of fixed size arrays of length two).
// Because of that, T[] is always a dynamic array of T, even if T
// itself is an array.
bool[2][] m_pairsOfFlags; bool[2][] m_pairsOfFlags;
// newPairs is stored in memory - the default for function arguments
// newPairs is stored in memory - the only possibility
// for public function arguments
function setAllFlagPairs(bool[2][] memory newPairs) public { function setAllFlagPairs(bool[2][] memory newPairs) public {
// assignment to a storage array replaces the complete array // assignment to a storage array replaces the complete array
m_pairsOfFlags = newPairs; m_pairsOfFlags = newPairs;
@ -797,6 +802,11 @@ Members
function createMemoryArray(uint size) public pure returns (bytes memory) { function createMemoryArray(uint size) public pure returns (bytes memory) {
// Dynamic memory arrays are created using `new`: // Dynamic memory arrays are created using `new`:
uint[2][] memory arrayOfPairs = new uint[2][](size); uint[2][] memory arrayOfPairs = new uint[2][](size);
// Inline arrays are always statically-sized and if you only
// use literals, you have to provide at least one type.
arrayOfPairs[0] = [uint(1), 2];
// Create a dynamic byte array: // Create a dynamic byte array:
bytes memory b = new bytes(200); bytes memory b = new bytes(200);
for (uint i = 0; i < b.length; i++) for (uint i = 0; i < b.length; i++)
@ -968,6 +978,7 @@ It is important to note that ``delete a`` really behaves like an assignment to `
// y is affected which is an alias to the storage object // y is affected which is an alias to the storage object
// On the other hand: "delete y" is not valid, as assignments to local variables // On the other hand: "delete y" is not valid, as assignments to local variables
// referencing storage objects can only be made from existing storage objects. // referencing storage objects can only be made from existing storage objects.
assert(y.length == 0);
} }
} }

View File

@ -35,43 +35,26 @@ def extract_test_cases(path):
return tests return tests
# Contract sources are indented by 4 spaces. # Contract sources are indented by 4 spaces.
# Look for `pragma solidity` and abort a line not indented properly. # Look for `pragma solidity`, `contract`, `library` or `interface`
# If the comment `// This will not compile` is above the pragma, # and abort a line not indented properly.
# the code is skipped.
def extract_docs_cases(path): def extract_docs_cases(path):
# Note: this code works, because splitlines() removes empty new lines
# and thus even if the empty new lines are missing indentation
lines = open(path, 'rb').read().splitlines()
ignore = False
inside = False inside = False
tests = [] tests = []
for l in lines: # Collect all snippets of indented blocks
if inside: for l in open(path, 'rb').read().splitlines():
# Abort if indentation is missing if l != '':
m = re.search(r'^[^ ]+', l) if not inside and l.startswith(' '):
if m: # start new test
inside = False tests += ['']
else: inside = l.startswith(' ')
tests[-1] += l + '\n' if inside:
else: tests[-1] += l + '\n'
m = re.search(r'^ // This will not compile', l) # Filter all tests that do not contain Solidity
if m: return [
ignore = True test for test in tests
if re.search(r'^ [ ]*(pragma solidity|contract |library |interface )', test, re.MULTILINE)
if ignore: ]
# Abort if indentation is missing
m = re.search(r'^[^ ]+', l)
if m:
ignore = False
else:
m = re.search(r'^ pragma solidity .*[0-9]+\.[0-9]+\.[0-9]+;$', l)
if m:
inside = True
tests += [l]
return tests
def write_cases(tests): def write_cases(tests):
for test in tests: for test in tests:

View File

@ -43,18 +43,42 @@ function printError() { echo "$(tput setaf 1)$1$(tput sgr0)"; }
function compileFull() function compileFull()
{ {
local expected_exit_code=0
local expect_output=0
if [[ $1 = '-e' ]]
then
expected_exit_code=1
expect_output=1
shift;
fi
if [[ $1 = '-w' ]]
then
expect_output=1
shift;
fi
local files="$*" local files="$*"
local output failed local output
local stderr_path=$(mktemp)
set +e set +e
output=$( ("$SOLC" $FULLARGS $files) 2>&1 ) "$SOLC" $FULLARGS $files >/dev/null 2>"$stderr_path"
failed=$? local exit_code=$?
local errors=$(grep -v -E 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|\^-------------------------------\^' < "$stderr_path")
set -e set -e
rm "$stderr_path"
if [ $failed -ne 0 ] if [[ \
"$exit_code" -ne "$expected_exit_code" || \
( $expect_output -eq 0 && -n "$errors" ) || \
( $expect_output -ne 0 && -z "$errors" ) \
]]
then then
printError "Compilation failed on:" printError "Unexpected compilation result:"
echo "$output" printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output"
printError "Was failure: $exit_code"
echo "$errors"
printError "While calling:" printError "While calling:"
echo "\"$SOLC\" $FULLARGS $files" echo "\"$SOLC\" $FULLARGS $files"
printError "Inside directory:" printError "Inside directory:"
@ -63,22 +87,6 @@ function compileFull()
fi fi
} }
function compileWithoutWarning()
{
local files="$*"
local output failed
set +e
output=$("$SOLC" $files 2>&1)
failed=$?
# Remove the pre-release warning from the compiler output
output=$(echo "$output" | grep -v 'pre-release')
echo "$output"
set -e
test -z "$output" -a "$failed" -eq 0
}
printTask "Testing unknown options..." printTask "Testing unknown options..."
( (
set +e set +e
@ -157,7 +165,7 @@ do
then then
echo " - $dir" echo " - $dir"
cd "$dir" cd "$dir"
compileFull *.sol */*.sol compileFull -w *.sol */*.sol
cd .. cd ..
fi fi
done done
@ -173,8 +181,25 @@ TMPDIR=$(mktemp -d)
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs "$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs
for f in *.sol for f in *.sol
do do
# The contributors guide uses syntax tests, but we cannot
# really handle them here.
if grep -E 'DeclarationError:|// ----' "$f" >/dev/null
then
continue
fi
echo "$f" echo "$f"
compileFull "$TMPDIR/$f" opts=''
# We expect errors if explicitly stated, or if imports
# are used (in the style guide)
if grep -E "This will not compile|import \"" "$f" >/dev/null
then
opts="-e"
fi
if grep "This will report a warning" "$f" >/dev/null
then
opts="$opts -w"
fi
compileFull $opts "$TMPDIR/$f"
done done
) )
rm -rf "$TMPDIR" rm -rf "$TMPDIR"