diff options
author | chriseth <chris@ethereum.org> | 2017-09-14 00:29:13 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-14 00:29:13 +0800 |
commit | 3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d (patch) | |
tree | 5a8f36e2b2491e07534d9c1570b8f40a2235c4c5 /test | |
parent | 72b7e001aa837ab59b3b14bfbabf69bbd102ded1 (diff) | |
parent | 172704a58fa2b7562107b8df299c5a81ba702d12 (diff) | |
download | dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.tar dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.tar.gz dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.tar.bz2 dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.tar.lz dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.tar.xz dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.tar.zst dexon-solidity-3f3bcc4f8a0d12e9b92d6b63e7cfd92cbbfa775d.zip |
Merge pull request #2848 from ethereum/checkViewPure
Enforce view and pure.
Diffstat (limited to 'test')
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 30 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 142 | ||||
-rw-r--r-- | test/libsolidity/ViewPureChecker.cpp | 398 |
3 files changed, 484 insertions, 86 deletions
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 73dd7d22..fa4d675c 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -6525,7 +6525,7 @@ BOOST_AUTO_TEST_CASE(state_variable_under_contract_name) contract Scope { uint stateVar = 42; - function getStateVar() constant returns (uint stateVar) { + function getStateVar() view returns (uint stateVar) { stateVar = Scope.stateVar; } } @@ -6791,7 +6791,7 @@ BOOST_AUTO_TEST_CASE(fixed_arrays_as_return_type) { char const* sourceCode = R"( contract A { - function f(uint16 input) constant returns (uint16[5] arr) + function f(uint16 input) pure returns (uint16[5] arr) { arr[0] = input; arr[1] = ++input; @@ -6820,7 +6820,7 @@ BOOST_AUTO_TEST_CASE(internal_types_in_library) { char const* sourceCode = R"( library Lib { - function find(uint16[] storage _haystack, uint16 _needle) constant returns (uint) + function find(uint16[] storage _haystack, uint16 _needle) view returns (uint) { for (uint i = 0; i < _haystack.length; ++i) if (_haystack[i] == _needle) @@ -9913,12 +9913,12 @@ BOOST_AUTO_TEST_CASE(keccak256_assembly) { char const* sourceCode = R"( contract C { - function f() returns (bytes32 ret) { + function f() pure returns (bytes32 ret) { assembly { ret := keccak256(0, 0) } } - function g() returns (bytes32 ret) { + function g() pure returns (bytes32 ret) { assembly { 0 0 @@ -9926,12 +9926,12 @@ BOOST_AUTO_TEST_CASE(keccak256_assembly) =: ret } } - function h() returns (bytes32 ret) { + function h() pure returns (bytes32 ret) { assembly { ret := sha3(0, 0) } } - function i() returns (bytes32 ret) { + function i() pure returns (bytes32 ret) { assembly { 0 0 @@ -9979,7 +9979,7 @@ BOOST_AUTO_TEST_CASE(inlineasm_empty_let) { char const* sourceCode = R"( contract C { - function f() returns (uint a, uint b) { + function f() pure returns (uint a, uint b) { assembly { let x let y, z @@ -9998,13 +9998,13 @@ BOOST_AUTO_TEST_CASE(bare_call_invalid_address) char const* sourceCode = R"( contract C { /// Calling into non-existant account is successful (creates the account) - function f() external constant returns (bool) { + function f() external view returns (bool) { return address(0x4242).call(); } - function g() external constant returns (bool) { + function g() external view returns (bool) { return address(0x4242).callcode(); } - function h() external constant returns (bool) { + function h() external view returns (bool) { return address(0x4242).delegatecall(); } } @@ -10023,16 +10023,16 @@ BOOST_AUTO_TEST_CASE(delegatecall_return_value) function set(uint _value) external { value = _value; } - function get() external constant returns (uint) { + function get() external view returns (uint) { return value; } - function get_delegated() external constant returns (bool) { + function get_delegated() external view returns (bool) { return this.delegatecall(bytes4(sha3("get()"))); } - function assert0() external constant { + function assert0() external view { assert(value == 0); } - function assert0_delegated() external constant returns (bool) { + function assert0_delegated() external view returns (bool) { return this.delegatecall(bytes4(sha3("assert0()"))); } } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 1fbc55a2..04d3d2d3 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1546,7 +1546,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base) { char const* sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { uint8 x = 100; return 10**x; } @@ -1555,7 +1555,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base) CHECK_WARNING(sourceCode, "might overflow"); sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { uint8 x = 100; return uint8(10)**x; } @@ -1564,7 +1564,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base) CHECK_SUCCESS(sourceCode); sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { return 2**80; } } @@ -1576,7 +1576,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base) { char const* sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { uint8 x = 100; return 10 << x; } @@ -1585,7 +1585,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base) CHECK_WARNING(sourceCode, "might overflow"); sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { uint8 x = 100; return uint8(10) << x; } @@ -1594,7 +1594,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base) CHECK_SUCCESS(sourceCode); sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { return 2 << 80; } } @@ -1602,7 +1602,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base) CHECK_SUCCESS(sourceCode); sourceCode = R"( contract test { - function f() returns(uint) { + function f() pure returns(uint) { uint8 x = 100; return 10 >> x; } @@ -1615,7 +1615,7 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero) { char const* sourceCode = R"( contract test { - function f() returns (uint) { + function f() pure returns (uint) { var i = 1; return i; } @@ -1624,7 +1624,7 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero) CHECK_WARNING(sourceCode, "uint8, which can hold values between 0 and 255"); sourceCode = R"( contract test { - function f() { + function f() pure { var i = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; i; } @@ -1633,7 +1633,7 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero) CHECK_WARNING(sourceCode, "uint256, which can hold values between 0 and 115792089237316195423570985008687907853269984665640564039457584007913129639935"); sourceCode = R"( contract test { - function f() { + function f() pure { var i = -2; i; } @@ -1642,7 +1642,7 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero) CHECK_WARNING(sourceCode, "int8, which can hold values between -128 and 127"); sourceCode = R"( contract test { - function f() { + function f() pure { for (var i = 0; i < msg.data.length; i++) { } } } @@ -2642,7 +2642,7 @@ BOOST_AUTO_TEST_CASE(uninitialized_mapping_array_variable) { char const* sourceCode = R"( contract C { - function f() { + function f() pure { mapping(uint => uint)[] storage x; x; } @@ -3973,7 +3973,7 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation) { char const* text = R"( contract test { - function f() { + function f() pure { ufixed16x2 a = 3.25; fixed16x2 b = -3.25; a; b; @@ -3983,7 +3983,7 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation) CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract test { - function f() { + function f() pure { ufixed16x2 a = +3.25; fixed16x2 b = -3.25; a; b; @@ -3993,7 +3993,7 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation) CHECK_WARNING(text, "Use of unary + is deprecated"); text = R"( contract test { - function f(uint x) { + function f(uint x) pure { uint y = +x; y; } @@ -4006,7 +4006,7 @@ BOOST_AUTO_TEST_CASE(leading_zero_rationals_convert) { char const* text = R"( contract A { - function f() { + function f() pure { ufixed16x2 a = 0.5; ufixed256x52 b = 0.0000000000000006661338147750939242541790008544921875; fixed16x2 c = -0.5; @@ -4519,7 +4519,7 @@ BOOST_AUTO_TEST_CASE(warn_about_callcode) { char const* text = R"( contract test { - function f() { + function f() pure { var x = address(0x12).callcode; x; } @@ -4532,7 +4532,7 @@ BOOST_AUTO_TEST_CASE(no_warn_about_callcode_as_function) { char const* text = R"( contract test { - function callcode() { + function callcode() pure { test.callcode(); } } @@ -5234,7 +5234,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_variable_access_out_of_functions) char const* text = R"( contract test { uint a; - function f() { + function f() pure { assembly { function g() -> x { x := a_slot } } @@ -5275,7 +5275,7 @@ BOOST_AUTO_TEST_CASE(warns_msg_value_in_non_payable_public_function) { char const* text = R"( contract C { - function f() { + function f() view { msg.value; } } @@ -5299,7 +5299,7 @@ BOOST_AUTO_TEST_CASE(does_not_warn_msg_value_in_internal_function) { char const* text = R"( contract C { - function f() internal { + function f() view internal { msg.value; } } @@ -5311,7 +5311,7 @@ BOOST_AUTO_TEST_CASE(does_not_warn_msg_value_in_library) { char const* text = R"( library C { - function f() { + function f() view { msg.value; } } @@ -5323,7 +5323,7 @@ BOOST_AUTO_TEST_CASE(does_not_warn_msg_value_in_modifier_following_non_payable_p { char const* text = R"( contract c { - function f() { } + function f() pure { } modifier m() { msg.value; _; } } )"; @@ -5402,7 +5402,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_checksum) { char const* text = R"( contract C { - function f() { + function f() pure { address x = 0xFA0bFc97E48458494Ccd857e1A85DC91F7F0046E; x; } @@ -5415,7 +5415,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_no_checksum) { char const* text = R"( contract C { - function f() { + function f() pure { address x = 0xfa0bfc97e48458494ccd857e1a85dc91f7f0046e; x; } @@ -5428,7 +5428,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_length) { char const* text = R"( contract C { - function f() { + function f() pure { address x = 0xA0bFc97E48458494Ccd857e1A85DC91F7F0046E; x; } @@ -5678,7 +5678,7 @@ BOOST_AUTO_TEST_CASE(warn_about_throw) { char const* text = R"( contract C { - function f() { + function f() pure { throw; } } @@ -5690,7 +5690,7 @@ BOOST_AUTO_TEST_CASE(bare_revert) { char const* text = R"( contract C { - function f(uint x) { + function f(uint x) pure { if (x > 7) revert; } @@ -5701,17 +5701,17 @@ BOOST_AUTO_TEST_CASE(bare_revert) BOOST_AUTO_TEST_CASE(bare_others) { - CHECK_WARNING("contract C { function f() { selfdestruct; } }", "Statement has no effect."); - CHECK_WARNING("contract C { function f() { assert; } }", "Statement has no effect."); - CHECK_WARNING("contract C { function f() { require; } }", "Statement has no effect."); - CHECK_WARNING("contract C { function f() { suicide; } }", "Statement has no effect."); + CHECK_WARNING("contract C { function f() pure { selfdestruct; } }", "Statement has no effect."); + CHECK_WARNING("contract C { function f() pure { assert; } }", "Statement has no effect."); + CHECK_WARNING("contract C { function f() pure { require; } }", "Statement has no effect."); + CHECK_WARNING("contract C { function f() pure { suicide; } }", "Statement has no effect."); } BOOST_AUTO_TEST_CASE(pure_statement_in_for_loop) { char const* text = R"( contract C { - function f() { + function f() pure { for (uint x = 0; x < 10; true) x++; } @@ -5724,7 +5724,7 @@ BOOST_AUTO_TEST_CASE(pure_statement_check_for_regular_for_loop) { char const* text = R"( contract C { - function f() { + function f() pure { for (uint x = 0; true; x++) {} } @@ -5780,7 +5780,7 @@ BOOST_AUTO_TEST_CASE(nowarn_swap_memory) char const* text = R"( contract C { struct S { uint a; uint b; } - function f() { + function f() pure { S memory x; S memory y; (x, y) = (y, x); @@ -5811,7 +5811,7 @@ BOOST_AUTO_TEST_CASE(warn_unused_local) { char const* text = R"( contract C { - function f() { + function f() pure { uint a; } } @@ -5823,7 +5823,7 @@ BOOST_AUTO_TEST_CASE(warn_unused_local_assigned) { char const* text = R"( contract C { - function f() { + function f() pure { uint a = 1; } } @@ -5835,14 +5835,14 @@ BOOST_AUTO_TEST_CASE(warn_unused_function_parameter) { char const* text = R"( contract C { - function f(uint a) { + function f(uint a) pure { } } )"; CHECK_WARNING(text, "Unused function parameter. Remove or comment out the variable name to silence this warning."); text = R"( contract C { - function f(uint a) { + function f(uint a) pure { } } )"; @@ -5853,14 +5853,14 @@ BOOST_AUTO_TEST_CASE(warn_unused_return_parameter) { char const* text = R"( contract C { - function f() returns (uint a) { + function f() pure returns (uint a) { } } )"; CHECK_WARNING(text, "Unused function parameter. Remove or comment out the variable name to silence this warning."); text = R"( contract C { - function f() returns (uint a) { + function f() pure returns (uint a) { return; } } @@ -5868,14 +5868,14 @@ BOOST_AUTO_TEST_CASE(warn_unused_return_parameter) CHECK_WARNING(text, "Unused function parameter. Remove or comment out the variable name to silence this warning."); text = R"( contract C { - function f() returns (uint) { + function f() pure returns (uint) { } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { - function f() returns (uint a) { + function f() pure returns (uint a) { a = 1; } } @@ -5883,7 +5883,7 @@ BOOST_AUTO_TEST_CASE(warn_unused_return_parameter) CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { - function f() returns (uint a) { + function f() pure returns (uint a) { return 1; } } @@ -5895,7 +5895,7 @@ BOOST_AUTO_TEST_CASE(no_unused_warnings) { char const* text = R"( contract C { - function f(uint a) returns (uint b) { + function f(uint a) pure returns (uint b) { uint c = 1; b = a + c; } @@ -5908,7 +5908,7 @@ BOOST_AUTO_TEST_CASE(no_unused_dec_after_use) { char const* text = R"( contract C { - function f() { + function f() pure { a = 7; uint a; } @@ -5921,7 +5921,7 @@ BOOST_AUTO_TEST_CASE(no_unused_inline_asm) { char const* text = R"( contract C { - function f() { + function f() pure { uint a; assembly { a := 1 @@ -5936,7 +5936,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_functions) { char const* text = R"( contract C { - function keccak256() {} + function keccak256() pure {} } )"; CHECK_WARNING(text, "shadows a builtin symbol"); @@ -5946,7 +5946,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_variables) { char const* text = R"( contract C { - function f() { + function f() pure { uint msg; msg; } @@ -5978,7 +5978,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_parameters) { char const* text = R"( contract C { - function f(uint require) { + function f(uint require) pure { require = 2; } } @@ -5990,7 +5990,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_return_parameters) { char const* text = R"( contract C { - function f() returns (uint require) { + function f() pure returns (uint require) { require = 2; } } @@ -6034,8 +6034,8 @@ BOOST_AUTO_TEST_CASE(function_overload_is_not_shadowing) { char const* text = R"( contract C { - function f() {} - function f(uint) {} + function f() pure {} + function f(uint) pure {} } )"; CHECK_SUCCESS_NO_WARNINGS(text); @@ -6044,9 +6044,9 @@ BOOST_AUTO_TEST_CASE(function_overload_is_not_shadowing) BOOST_AUTO_TEST_CASE(function_override_is_not_shadowing) { char const* text = R"( - contract D { function f() {} } + contract D { function f() pure {} } contract C is D { - function f(uint) {} + function f(uint) pure {} } )"; CHECK_SUCCESS_NO_WARNINGS(text); @@ -6140,7 +6140,7 @@ BOOST_AUTO_TEST_CASE(does_not_error_transfer_regular_function) { char const* text = R"( contract A { - function transfer() {} + function transfer() pure {} } contract B { @@ -6176,7 +6176,7 @@ BOOST_AUTO_TEST_CASE(warn_unspecified_storage) contract C { struct S { uint a; string b; } S x; - function f() { + function f() view { S storage y = x; y; } @@ -6187,7 +6187,7 @@ BOOST_AUTO_TEST_CASE(warn_unspecified_storage) contract C { struct S { uint a; } S x; - function f() { + function f() view { S y = x; y; } @@ -6213,21 +6213,21 @@ BOOST_AUTO_TEST_CASE(too_large_arrays_for_calldata) { char const* text = R"( contract C { - function f(uint[85678901234] a) external { + function f(uint[85678901234] a) pure external { } } )"; CHECK_ERROR(text, TypeError, "Array is too large to be encoded."); text = R"( contract C { - function f(uint[85678901234] a) internal { + function f(uint[85678901234] a) pure internal { } } )"; CHECK_ERROR(text, TypeError, "Array is too large to be encoded."); text = R"( contract C { - function f(uint[85678901234] a) { + function f(uint[85678901234] a) pure { } } )"; @@ -6238,7 +6238,7 @@ BOOST_AUTO_TEST_CASE(explicit_literal_to_storage_string) { char const* text = R"( contract C { - function f() { + function f() pure { string memory x = "abc"; x; } @@ -6247,7 +6247,7 @@ BOOST_AUTO_TEST_CASE(explicit_literal_to_storage_string) CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { - function f() { + function f() pure { string storage x = "abc"; } } @@ -6255,7 +6255,7 @@ BOOST_AUTO_TEST_CASE(explicit_literal_to_storage_string) CHECK_ERROR(text, TypeError, "Type literal_string \"abc\" is not implicitly convertible to expected type string storage pointer."); text = R"( contract C { - function f() { + function f() pure { string x = "abc"; } } @@ -6263,7 +6263,7 @@ BOOST_AUTO_TEST_CASE(explicit_literal_to_storage_string) CHECK_ERROR(text, TypeError, "Type literal_string \"abc\" is not implicitly convertible to expected type string storage pointer."); text = R"( contract C { - function f() { + function f() pure { string("abc"); } } @@ -6292,7 +6292,7 @@ BOOST_AUTO_TEST_CASE(using_this_in_constructor) function C() { this.f(); } - function f() { + function f() pure { } } )"; @@ -6559,7 +6559,7 @@ BOOST_AUTO_TEST_CASE(tight_packing_literals) { char const* text = R"( contract C { - function f() returns (bytes32) { + function f() pure returns (bytes32) { return keccak256(1); } } @@ -6567,7 +6567,7 @@ BOOST_AUTO_TEST_CASE(tight_packing_literals) CHECK_WARNING(text, "The type of \"int_const 1\" was inferred as uint8."); text = R"( contract C { - function f() returns (bytes32) { + function f() pure returns (bytes32) { return keccak256(uint8(1)); } } @@ -6575,7 +6575,7 @@ BOOST_AUTO_TEST_CASE(tight_packing_literals) CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { - function f() returns (bytes32) { + function f() pure returns (bytes32) { return sha3(1); } } @@ -6583,7 +6583,7 @@ BOOST_AUTO_TEST_CASE(tight_packing_literals) CHECK_WARNING(text, "The type of \"int_const 1\" was inferred as uint8."); text = R"( contract C { - function f() returns (bytes32) { + function f() pure returns (bytes32) { return sha256(1); } } @@ -6591,7 +6591,7 @@ BOOST_AUTO_TEST_CASE(tight_packing_literals) CHECK_WARNING(text, "The type of \"int_const 1\" was inferred as uint8."); text = R"( contract C { - function f() returns (bytes32) { + function f() pure returns (bytes32) { return ripemd160(1); } } diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp new file mode 100644 index 00000000..9cea9850 --- /dev/null +++ b/test/libsolidity/ViewPureChecker.cpp @@ -0,0 +1,398 @@ +/* + 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/>. +*/ +/** + * Unit tests for the view and pure checker. + */ + +#include <test/libsolidity/AnalysisFramework.h> + +#include <boost/test/unit_test.hpp> + +#include <string> + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +BOOST_FIXTURE_TEST_SUITE(ViewPureChecker, AnalysisFramework) + +BOOST_AUTO_TEST_CASE(smoke_test) +{ + char const* text = R"( + contract C { + uint x; + function g() pure {} + function f() view returns (uint) { return now; } + function h() { x = 2; } + function i() payable { x = 2; } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(call_internal_functions_success) +{ + char const* text = R"( + contract C { + function g() pure { g(); } + function f() view returns (uint) { f(); g(); } + function h() { h(); g(); f(); } + function i() payable { i(); h(); g(); f(); } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(suggest_pure) +{ + char const* text = R"( + contract C { + function g() view { } + } + )"; + CHECK_WARNING(text, "can be restricted to pure"); +} + +BOOST_AUTO_TEST_CASE(suggest_view) +{ + char const* text = R"( + contract C { + uint x; + function g() returns (uint) { return x; } + } + )"; + CHECK_WARNING(text, "can be restricted to view"); +} + +BOOST_AUTO_TEST_CASE(call_internal_functions_fail) +{ + CHECK_ERROR( + "contract C{ function f() pure { g(); } function g() view {} }", + TypeError, + "Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires \"view\"" + ); +} + +BOOST_AUTO_TEST_CASE(write_storage_fail) +{ + CHECK_WARNING( + "contract C{ uint x; function f() view { x = 2; } }", + "Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable." + ); +} + +BOOST_AUTO_TEST_CASE(environment_access) +{ + vector<string> view{ + "block.coinbase", + "block.timestamp", + "block.blockhash(7)", + "block.difficulty", + "block.number", + "block.gaslimit", + "msg.gas", + "msg.value", + "msg.sender", + "tx.origin", + "tx.gasprice", + "this", + "address(1).balance" + }; + vector<string> pure{ + "msg.data", + "msg.data[0]", + "msg.sig", + "block.blockhash", // Not evaluating the function + "msg", + "block", + "tx" + }; + for (string const& x: view) + { + CHECK_ERROR( + "contract C { function f() pure { var x = " + x + "; x; } }", + TypeError, + "Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires \"view\"" + ); + } + for (string const& x: pure) + { + CHECK_WARNING( + "contract C { function f() view { var x = " + x + "; x; } }", + "restricted to pure" + ); + } +} + +BOOST_AUTO_TEST_CASE(modifiers) +{ + string text = R"( + contract D { + uint x; + modifier purem(uint) { _; } + modifier viewm(uint) { uint a = x; _; a; } + modifier nonpayablem(uint) { x = 2; _; } + } + contract C is D { + function f() purem(0) pure {} + function g() viewm(0) view {} + function h() nonpayablem(0) {} + function i() purem(x) view {} + function j() viewm(x) view {} + function k() nonpayablem(x) {} + function l() purem(x = 2) {} + function m() viewm(x = 2) {} + function n() nonpayablem(x = 2) {} + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(interface) +{ + string text = R"( + interface D { + function f() view; + } + contract C is D { + function f() view {} + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(overriding) +{ + string text = R"( + contract D { + uint x; + function f() { x = 2; } + } + contract C is D { + function f() {} + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(returning_structs) +{ + string text = R"( + contract C { + struct S { uint x; } + S s; + function f() view internal returns (S storage) { + return s; + } + function g() + { + f().x = 2; + } + function h() view + { + f(); + f().x; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(mappings) +{ + string text = R"( + contract C { + mapping(uint => uint) a; + function f() view { + a; + } + function g() view { + a[2]; + } + function h() { + a[2] = 3; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(local_storage_variables) +{ + string text = R"( + contract C { + struct S { uint a; } + S s; + function f() view { + S storage x = s; + x; + } + function g() view { + S storage x = s; + x = s; + } + function i() { + s.a = 2; + } + function h() { + S storage x = s; + x.a = 2; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(builtin_functions) +{ + string text = R"( + contract C { + function f() { + this.transfer(1); + require(this.send(2)); + selfdestruct(this); + require(this.delegatecall()); + require(this.call()); + } + function g() pure { + var x = keccak256("abc"); + var y = sha256("abc"); + var z = ecrecover(1, 2, 3, 4); + require(true); + assert(true); + x; y; z; + } + function() payable {} + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(function_types) +{ + string text = R"( + contract C { + function f() pure { + function () external nonpayFun; + function () external view viewFun; + function () external pure pureFun; + + nonpayFun; + viewFun; + pureFun; + pureFun(); + } + function g() view { + function () external view viewFun; + + viewFun(); + } + function h() { + function () external nonpayFun; + + nonpayFun(); + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(creation) +{ + string text = R"( + contract D {} + contract C { + function f() { new D(); } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(assembly) +{ + string text = R"( + contract C { + struct S { uint x; } + S s; + function e() pure { + assembly { mstore(keccak256(0, 20), mul(s_slot, 2)) } + } + function f() pure { + uint x; + assembly { x := 7 } + } + function g() view { + assembly { for {} 1 { pop(sload(0)) } { } } + } + function h() view { + assembly { function g() { pop(blockhash(20)) } } + } + function j() { + assembly { pop(call(0, 1, 2, 3, 4, 5, 6)) } + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_CASE(assembly_staticcall) +{ + string text = R"( + contract C { + function i() view { + assembly { pop(staticcall(0, 1, 2, 3, 4, 5)) } + } + } + )"; + CHECK_WARNING(text, "only available after the Metropolis"); +} + +BOOST_AUTO_TEST_CASE(assembly_jump) +{ + string text = R"( + contract C { + function k() { + assembly { jump(2) } + } + } + )"; + CHECK_WARNING(text, "low-level EVM features"); +} + +BOOST_AUTO_TEST_CASE(constant) +{ + string text = R"( + contract C { + uint constant x = 2; + function k() pure returns (uint) { + return x; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} |