Merge pull request #8502 from mijovic/testDocsPragma

[docs] Compile examples with minimal compiler version
This commit is contained in:
chriseth 2020-03-18 19:45:53 +01:00 committed by GitHub
commit b02a42400b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 244 additions and 115 deletions

View File

@ -122,6 +122,10 @@ defaults:
name: command line tests
command: ./test/cmdlineTests.sh
- run_docs_version_pragma_check: &run_docs_version_pragma_check
name: docs version pragma check
command: ./scripts/docs_version_pragma_check.sh
- test_ubuntu1604_clang: &test_ubuntu1604_clang
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1604-clang-ossfuzz-<< pipeline.parameters.ubuntu-1604-clang-ossfuzz-docker-image-rev >>
@ -605,6 +609,7 @@ jobs:
- attach_workspace:
at: build
- run: *run_cmdline_tests
- run: *run_docs_version_pragma_check
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results

View File

@ -292,8 +292,9 @@ 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;
// This will report a warning until version 0.4.25 of the compiler
// This will not compile after 0.5.0
contract OldContract {
function someOldFunction(uint8 a) {
//...
@ -369,8 +370,8 @@ Old version:
::
// This will not compile
pragma solidity ^0.4.25;
// This will not compile after 0.5.0
contract OtherContract {
uint x;
@ -396,7 +397,7 @@ Old version:
// Throw is fine in this version.
if (x > 100)
throw;
bytes b = new bytes(x);
bytes memory b = new bytes(x);
y = -3 >> 1;
// y == -1 (wrong, should be -2)
do {
@ -431,14 +432,15 @@ New version:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.5.0 <0.5.99;
// This will not compile after 0.6.0
contract OtherContract {
uint x;
function f(uint y) external {
x = y;
}
receive() payable external {}
function() payable external {}
}
contract New {

View File

@ -234,7 +234,6 @@ Given the contract:
pragma solidity >=0.4.16 <0.7.0;
contract Foo {
function bar(bytes3[2] memory) public pure {}
function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; }
@ -583,12 +582,11 @@ As an example, the code
pragma solidity >=0.4.19 <0.7.0;
pragma experimental ABIEncoderV2;
contract Test {
struct S { uint a; uint[] b; T[] c; }
struct T { uint x; uint y; }
function f(S memory s, T memory t, uint a) public {}
function g() public returns (S memory s, T memory t, uint a) {}
function f(S memory, T memory, uint) public pure {}
function g() public pure returns (S memory, T memory, uint) {}
}
would result in the JSON:

View File

@ -41,7 +41,7 @@ without a compiler change.
.. code::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
library GetCode {
function at(address _addr) public view returns (bytes memory o_code) {
@ -136,7 +136,7 @@ Local Solidity variables are available for assignments, for example:
.. code::
pragma solidity >=0.4.11 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
contract C {
uint b;

View File

@ -13,7 +13,7 @@ This can be done by using the ``abstract`` keyword as shown in the following exa
defined as abstract, because the function ``utterance()`` was defined, but no implementation was
provided (no implementation body ``{ }`` was given).::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
abstract contract Feline {
function utterance() public virtual returns (bytes32);

View File

@ -335,7 +335,7 @@ operations as long as there is enough gas passed on to it.
::
pragma solidity >0.6.1 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
contract Test {
// This function is called for all messages sent to

View File

@ -154,7 +154,7 @@ A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it
explicitly in the final override, but this function will bypass
``Base1.destroy``. The way around this is to use ``super``::
pragma solidity >=0.4.22 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract owned {
constructor() public { owner = msg.sender; }
@ -204,7 +204,7 @@ use the ``override`` keyword in the function header as shown in this example:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract Base
{
@ -227,7 +227,7 @@ bases, it has to explicitly override it:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract Base1
{
@ -253,7 +253,7 @@ that already overrides all other functions.
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract A { function f() public pure{} }
contract B is A {}
@ -293,7 +293,7 @@ of the variable:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract A
{
@ -324,7 +324,7 @@ and the ``override`` keyword must be used in the overriding modifier:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract Base
{
@ -342,7 +342,7 @@ explicitly:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract Base1
{
@ -498,7 +498,7 @@ One area where inheritance linearization is especially important and perhaps not
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
contract Base1 {
constructor() public {}

View File

@ -22,7 +22,7 @@ Interfaces are denoted by their own keyword:
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
interface Token {
enum TokenType { Fungible, NonFungible }
@ -42,7 +42,7 @@ inheritance.
::
pragma solidity >0.6.1 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
interface ParentA {
function test() external returns (uint256);

View File

@ -47,12 +47,14 @@ more advanced example to implement a set).
::
pragma solidity >=0.4.22 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
// We define a new struct datatype that will be used to
// hold its data in the calling contract.
struct Data { mapping(uint => bool) flags; }
struct Data {
mapping(uint => bool) flags;
}
library Set {
// Note that the first parameter is of type "storage
@ -123,7 +125,7 @@ custom types without the overhead of external function calls:
::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
struct bigint {
uint[] limbs;
@ -237,7 +239,7 @@ Its value can be obtained from Solidity using the ``.selector`` member as follow
::
pragma solidity >0.5.13 <0.7.0;
pragma solidity >=0.5.14 <0.7.0;
library L {
function f(uint256) external {}

View File

@ -29,7 +29,7 @@ may only be used inside a contract, not inside any of its functions.
Let us rewrite the set example from the
:ref:`libraries` in this way::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
// This is the same code as before, just without comments

View File

@ -68,7 +68,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
contract C {
uint private data;
@ -112,7 +112,7 @@ when they are declared.
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
contract C {
uint public data = 42;
@ -151,7 +151,7 @@ to write a function, for example:
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
contract arrayExample {
// public state variable

View File

@ -41,7 +41,7 @@ Internal Function Calls
Functions of the current contract can be called directly ("internally"), also recursively, as seen in
this nonsensical example::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
contract C {
function g(uint a) public pure returns (uint ret) { return a + f(); }
@ -82,7 +82,7 @@ to the total balance of that contract:
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
contract InfoFeed {
function info() public payable returns (uint ret) { return 42; }
@ -160,7 +160,7 @@ Those parameters will still be present on the stack, but they are inaccessible.
::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
contract C {
// omitted name for parameter
@ -183,7 +183,7 @@ is compiled so recursive creation-dependencies are not possible.
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
contract D {
uint public x;
@ -238,7 +238,7 @@ which only need to be created if there is a dispute.
::
pragma solidity >0.6.1 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
contract D {
uint public x;
@ -307,7 +307,7 @@ groupings of expressions.
::
pragma solidity >0.4.23 <0.7.0;
pragma solidity >=0.5.0 <0.7.0;
contract C {
uint index;
@ -352,7 +352,7 @@ because only a reference and not a copy is passed.
::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
contract C {
uint[20] x;

View File

@ -24,7 +24,7 @@ to receive their money - contracts cannot activate themselves.
::
pragma solidity >=0.4.22 <0.7.0;
pragma solidity >=0.5.0 <0.7.0;
contract SimpleAuction {
// Parameters of the auction. Times are either

View File

@ -338,7 +338,7 @@ The full contract
::
pragma solidity >=0.4.24 <0.7.0;
pragma solidity >=0.5.0 <0.7.0;
contract SimplePaymentChannel {
address payable public sender; // The account sending payments.

View File

@ -19,7 +19,7 @@ and the sum of all balances is an invariant across the lifetime of the contract.
::
pragma solidity >=0.4.22 <0.7.0;
pragma solidity >=0.5.0 <0.7.0;
library Balances {
function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal {

View File

@ -25,7 +25,7 @@ you can use state machine-like constructs inside a contract.
::
pragma solidity >=0.4.22 <0.7.0;
pragma solidity >=0.5.0 <0.7.0;
contract Purchase {
uint public value;

View File

@ -17,7 +17,7 @@ Storage Example
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
contract SimpleStorage {
uint storedData;

View File

@ -284,7 +284,7 @@ for the two function parameters and two return variables.
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.21 <0.7.0;
/** @title Shape calculator. */
contract ShapeCalculator {

View File

@ -81,7 +81,7 @@ as it uses ``call`` which forwards all remaining gas by default:
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.6.2 <0.7.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract Fund {
@ -277,7 +277,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The
::
pragma solidity >=0.5.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract Map {
mapping (uint => uint)[] array;

View File

@ -109,7 +109,7 @@ Yes::
No::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
abstract contract A {
function spam() virtual pure public;
@ -326,7 +326,7 @@ Yes::
No::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity ^0.6.0;
contract A {
@ -745,7 +745,7 @@ manner as modifiers if the function declaration is long or hard to read.
Yes::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
// Base contracts just to make this compile
contract B {
@ -777,7 +777,7 @@ Yes::
No::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
// Base contracts just to make this compile
@ -1000,7 +1000,7 @@ As shown in the example below, if the contract name is `Congress` and the librar
Yes::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
// Owned.sol
@ -1034,7 +1034,7 @@ and in ``Congress.sol``::
No::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
// owned.sol
@ -1138,7 +1138,7 @@ multiline comment starting with `/**` and ending with `*/`.
For example, the contract from `a simple smart contract <simple-smart-contract>`_ with the comments
added looks like the one below::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.16 <0.7.0;
/// @author The Solidity Team

View File

@ -66,7 +66,7 @@ The example below uses ``_allowances`` to record the amount someone else is allo
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.4.22 <0.7.0;
contract MappingExample {
@ -120,7 +120,7 @@ the ``sum`` function iterates over to sum all the values.
::
pragma solidity >=0.5.99 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
struct IndexValue { uint keyIndex; uint value; }
struct KeyFlag { uint key; bool deleted; }

View File

@ -57,7 +57,7 @@ Data locations are not only relevant for persistency of data, but also for the s
::
pragma solidity >=0.4.0 <0.7.0;
pragma solidity >=0.5.0 <0.7.0;
contract C {
// The data location of x is storage.
@ -268,7 +268,7 @@ Array Members
::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract ArrayContract {
uint[2**20] m_aLotOfIntegers;
@ -400,7 +400,7 @@ Array slices are useful to ABI-decode secondary data passed in function paramete
::
pragma solidity >=0.4.99 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
contract Proxy {
/// Address of the client contract managed by proxy i.e., this contract
@ -437,7 +437,7 @@ shown in the following example:
::
pragma solidity >=0.4.11 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
// Defines a new type with two fields.
// Declaring a struct outside of a contract allows

View File

@ -650,7 +650,7 @@ External (or public) functions have the following members:
Example that shows how to use the members::
pragma solidity >=0.4.16 <0.7.0;
pragma solidity >=0.6.0 <0.7.0;
// This will report a warning
contract Example {
@ -670,7 +670,6 @@ Example that shows how to use internal function types::
pragma solidity >=0.4.16 <0.7.0;
library ArrayUtils {
// internal functions can be used in internal library functions because
// they will be part of the same code context

View File

@ -687,7 +687,7 @@ The command above applies all changes as shown below. Please review them careful
.. code-block:: none
pragma solidity >0.4.23;
pragma solidity >=0.6.0 <0.7.0;
abstract contract Updateable {
function run() public view virtual returns (bool);

79
scripts/common_cmdline.sh Normal file
View File

@ -0,0 +1,79 @@
# ------------------------------------------------------------------------------
# vim:ts=4:et
# This file is part of solidity.
#
# solidity is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# solidity is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with solidity. If not, see <http://www.gnu.org/licenses/>
#
# (c) 2016-2019 solidity contributors.
# ------------------------------------------------------------------------------
FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc"
OLDARGS="--optimize --combined-json abi,asm,ast,bin,bin-runtime,devdoc,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc"
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
if [[ $1 = '-o' ]]; then
expect_output=2
shift;
fi
local args=$FULLARGS
if [[ $1 = '-v' ]]; then
if (echo $2 | grep -Po '(?<=0.4.)\d+' >/dev/null); then
patch=$(echo $2 | grep -Po '(?<=0.4.)\d+')
if (( patch < 22 )); then
args=$OLDARGS
fi
fi
shift 2
fi
local files="$*"
local output
local stderr_path=$(mktemp)
set +e
"$SOLC" ${args} ${files} >/dev/null 2>"$stderr_path"
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|^ +--> |^ +\||^[0-9]+ +\|' < "$stderr_path")
set -e
rm "$stderr_path"
if [[ \
("$exit_code" -ne "$expected_exit_code" || \
( $expect_output -eq 0 && -n "$errors" ) || \
( $expect_output -ne 0 && $expected_exit_code -eq 0 && $expect_output -ne 2 && -z "$errors" ))
]]
then
printError "Unexpected compilation result:"
printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output"
printError "Was failure: $exit_code"
echo "$errors"
printError "While calling:"
echo "\"$SOLC\" $ARGS $files"
printError "Inside directory:"
pwd
false
fi
}

View File

@ -0,0 +1,95 @@
#!/usr/bin/env bash
# ------------------------------------------------------------------------------
# This file is part of solidity.
#
# solidity is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# solidity is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with solidity. If not, see <http://www.gnu.org/licenses/>
#
# (c) 2016 solidity contributors.
#------------------------------------------------------------------------------
# This script verifies that the examples compile with the oldest version mentioned in the pragma.
# It does not verify that it cannot be compiled with an older version
# and it also does not verify that it can be compiled with the newest version compatible with the pragma.
set -e
## GLOBAL VARIABLES
REPO_ROOT=$(cd $(dirname "$0")/.. && pwd)
SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build}
source "${REPO_ROOT}/scripts/common.sh"
source "${REPO_ROOT}/scripts/common_cmdline.sh"
printTask "Verifying that all examples from the documentation have the correct version range..."
SOLTMPDIR=$(mktemp -d)
(
set -e
cd "$SOLTMPDIR"
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs
for f in *.sol
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"
opts=''
# We expect errors if explicitly stated, or if imports
# are used (in the style guide)
if ( ! grep -E "This will not compile after" "$f" >/dev/null && \
grep -E "This will not compile|import \"" "$f" >/dev/null )
then
opts="-e"
fi
# ignore warnings in this case
opts="$opts -o"
# Get minimum compiler version defined by pragma
if (grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f" >/dev/null); then
version="$(grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f")"
if (echo $version | grep -Po '(?<=0.4.)\d+' >/dev/null); then
patch=$(echo $version | grep -Po '(?<=0.4.)\d+')
if (( patch < 11 )); then
version="0.4.11" # first available release on github
fi
fi
elif (grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f" >/dev/null); then
version="$(grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f")"
fi
opts="$opts -v $version"
solc_bin="solc-$version"
echo "$solc_bin"
if [[ ! -f "$solc_bin" ]]; then
echo "Downloading release from github..."
wget https://github.com/ethereum/solidity/releases/download/v$version/solc-static-linux
mv solc-static-linux $solc_bin
fi
ln -sf "$solc_bin" "solc"
chmod a+x solc
SOLC="$SOLTMPDIR/solc"
compileFull $opts "$SOLTMPDIR/$f"
done
)
rm -rf "$SOLTMPDIR"
echo "Done."

View File

@ -33,6 +33,7 @@ set -e
REPO_ROOT=$(cd $(dirname "$0")/.. && pwd)
SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build}
source "${REPO_ROOT}/scripts/common.sh"
source "${REPO_ROOT}/scripts/common_cmdline.sh"
case "$OSTYPE" in
msys)
@ -45,6 +46,7 @@ case "$OSTYPE" in
SOLC="$REPO_ROOT/${SOLIDITY_BUILD_DIR}/solc/solc"
;;
esac
echo "${SOLC}"
INTERACTIVE=true
if ! tty -s || [ "$CI" ]
@ -52,8 +54,6 @@ then
INTERACTIVE=""
fi
FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc"
# extend stack size in case we run via ASAN
if [[ -n "${CIRCLECI}" ]] || [[ -n "$CI" ]]; then
ulimit -s 16384
@ -62,57 +62,6 @@ fi
## FUNCTIONS
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
if [[ $1 = '-o' ]]
then
expect_output=2
shift;
fi
local files="$*"
local output
local stderr_path=$(mktemp)
set +e
"$SOLC" $FULLARGS $files >/dev/null 2>"$stderr_path"
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|^ +--> |^ +\||^[0-9]+ +\|' < "$stderr_path")
set -e
rm "$stderr_path"
if [[ \
"$exit_code" -ne "$expected_exit_code" || \
( $expect_output -eq 0 && -n "$errors" ) || \
( $expect_output -eq 1 && -z "$errors" ) \
]]
then
printError "Unexpected compilation result:"
printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output"
printError "Was failure: $exit_code"
echo "$errors"
printError "While calling:"
echo "\"$SOLC\" $FULLARGS $files"
printError "Inside directory:"
pwd
false
fi
}
function ask_expectation_update()
{
if [ $INTERACTIVE ]