aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'test/libsolidity')
-rw-r--r--test/libsolidity/ASTJSON.cpp45
-rw-r--r--test/libsolidity/Assembly.cpp10
-rw-r--r--test/libsolidity/InlineAssembly.cpp23
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp38
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp749
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp37
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp246
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp12
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp28
-rw-r--r--test/libsolidity/SolidityParser.cpp111
10 files changed, 1204 insertions, 95 deletions
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp
index a0fc5dd7..b88218e7 100644
--- a/test/libsolidity/ASTJSON.cpp
+++ b/test/libsolidity/ASTJSON.cpp
@@ -94,20 +94,6 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint");
}
-BOOST_AUTO_TEST_CASE(enum_definition)
-{
- CompilerStack c;
- c.addSource("a", "contract C { enum E {} }");
- c.parse();
- map<string, unsigned> sourceIndices;
- sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
- Json::Value enumDefinition = astJson["children"][0]["children"][0];
- BOOST_CHECK_EQUAL(enumDefinition["name"], "EnumDefinition");
- BOOST_CHECK_EQUAL(enumDefinition["attributes"]["name"], "E");
- BOOST_CHECK_EQUAL(enumDefinition["src"], "13:9:1");
-}
-
BOOST_AUTO_TEST_CASE(enum_value)
{
CompilerStack c;
@@ -211,6 +197,37 @@ BOOST_AUTO_TEST_CASE(non_utf8)
BOOST_CHECK(literal["attributes"]["type"].asString().find("invalid") != string::npos);
}
+BOOST_AUTO_TEST_CASE(function_type)
+{
+ CompilerStack c;
+ c.addSource("a",
+ "contract C { function f(function() external payable returns (uint) x) "
+ "returns (function() external constant returns (uint)) {} }"
+ );
+ c.parse();
+ map<string, unsigned> sourceIndices;
+ sourceIndices["a"] = 1;
+ Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value fun = astJson["children"][0]["children"][0];
+ BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition");
+ Json::Value argument = fun["children"][0]["children"][0];
+ BOOST_CHECK_EQUAL(argument["name"], "VariableDeclaration");
+ BOOST_CHECK_EQUAL(argument["attributes"]["name"], "x");
+ BOOST_CHECK_EQUAL(argument["attributes"]["type"], "function () payable external returns (uint256)");
+ Json::Value funType = argument["children"][0];
+ BOOST_CHECK_EQUAL(funType["attributes"]["constant"], false);
+ BOOST_CHECK_EQUAL(funType["attributes"]["payable"], true);
+ BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external");
+ Json::Value retval = fun["children"][1]["children"][0];
+ BOOST_CHECK_EQUAL(retval["name"], "VariableDeclaration");
+ BOOST_CHECK_EQUAL(retval["attributes"]["name"], "");
+ BOOST_CHECK_EQUAL(retval["attributes"]["type"], "function () constant external returns (uint256)");
+ funType = retval["children"][0];
+ BOOST_CHECK_EQUAL(funType["attributes"]["constant"], true);
+ BOOST_CHECK_EQUAL(funType["attributes"]["payable"], false);
+ BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 8d7a3540..e5ce691b 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -91,8 +91,10 @@ void checkAssemblyLocations(AssemblyItems const& _items, vector<SourceLocation>
BOOST_CHECK_MESSAGE(
_items[i].location() == _locations[i],
"Location mismatch for assembly item " + to_string(i) + ". Found: " +
+ (_items[i].location().sourceName ? *_items[i].location().sourceName + ":" : "(null source name)") +
to_string(_items[i].location().start) + "-" +
to_string(_items[i].location().end) + ", expected: " +
+ (_locations[i].sourceName ? *_locations[i].sourceName + ":" : "(null source name)") +
to_string(_locations[i].start) + "-" +
to_string(_locations[i].end));
}
@@ -111,13 +113,13 @@ BOOST_AUTO_TEST_CASE(location_test)
}
}
)";
- shared_ptr<string const> n = make_shared<string>("source");
+ shared_ptr<string const> n = make_shared<string>("");
AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations =
- vector<SourceLocation>(18, SourceLocation(2, 75, n)) +
- vector<SourceLocation>(31, SourceLocation(20, 72, n)) +
+ vector<SourceLocation>(16, SourceLocation(2, 75, n)) +
+ vector<SourceLocation>(27, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
- vector<SourceLocation>(4, SourceLocation(58, 67, n)) +
+ vector<SourceLocation>(2, SourceLocation(58, 67, n)) +
vector<SourceLocation>(3, SourceLocation(20, 72, n));
checkAssemblyLocations(items, locations);
}
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 6c04367f..185a6215 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -41,7 +41,7 @@ namespace test
namespace
{
-bool successParse(std::string const& _source, bool _assemble = false)
+bool successParse(std::string const& _source, bool _assemble = false, bool _allowWarnings = true)
{
assembly::InlineAssemblyStack stack;
try
@@ -51,8 +51,9 @@ bool successParse(std::string const& _source, bool _assemble = false)
if (_assemble)
{
stack.assemble();
- if (!stack.errors().empty() && !Error::containsOnlyWarnings(stack.errors()))
- return false;
+ if (!stack.errors().empty())
+ if (!_allowWarnings || !Error::containsOnlyWarnings(stack.errors()))
+ return false;
}
}
catch (FatalError const&)
@@ -67,9 +68,9 @@ bool successParse(std::string const& _source, bool _assemble = false)
return true;
}
-bool successAssemble(string const& _source)
+bool successAssemble(string const& _source, bool _allowWarnings = true)
{
- return successParse(_source, true);
+ return successParse(_source, true, _allowWarnings);
}
}
@@ -169,6 +170,18 @@ BOOST_AUTO_TEST_CASE(magic_variables)
BOOST_CHECK(successAssemble("{ let ecrecover := 1 ecrecover }"));
}
+BOOST_AUTO_TEST_CASE(imbalanced_stack)
+{
+ BOOST_CHECK(successAssemble("{ 1 2 mul pop }", false));
+ BOOST_CHECK(!successAssemble("{ 1 }", false));
+ BOOST_CHECK(successAssemble("{ let x := 4 7 add }", false));
+}
+
+BOOST_AUTO_TEST_CASE(error_tag)
+{
+ BOOST_CHECK(successAssemble("{ invalidJumpLabel }"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 073d7d97..a8a39b0b 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -40,14 +40,14 @@ public:
void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
{
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse("pragma solidity >=0.0;\n" + _code), "Parsing contract failed");
- std::string generatedInterfaceString = m_compilerStack.metadata("", DocumentationType::ABIInterface);
- Json::Value generatedInterface;
- m_reader.parse(generatedInterfaceString, generatedInterface);
+
+ Json::Value generatedInterface = m_compilerStack.metadata("", DocumentationType::ABIInterface);
Json::Value expectedInterface;
m_reader.parse(_expectedInterfaceString, expectedInterface);
BOOST_CHECK_MESSAGE(
expectedInterface == generatedInterface,
- "Expected:\n" << expectedInterface.toStyledString() << "\n but got:\n" << generatedInterface.toStyledString()
+ "Expected:\n" << expectedInterface.toStyledString() <<
+ "\n but got:\n" << generatedInterface.toStyledString()
);
}
@@ -524,6 +524,7 @@ BOOST_AUTO_TEST_CASE(constructor_abi)
"type": "bool"
}
],
+ "payable": false,
"type": "constructor"
}
])";
@@ -567,6 +568,7 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi)
"type": "uint8"
}
],
+ "payable": false,
"type": "constructor"
}
]
@@ -684,7 +686,7 @@ BOOST_AUTO_TEST_CASE(payable_function)
checkInterface(sourceCode, interface);
}
-BOOST_AUTO_TEST_CASE(payable_fallback_unction)
+BOOST_AUTO_TEST_CASE(payable_fallback_function)
{
char const* sourceCode = R"(
contract test {
@@ -703,6 +705,32 @@ BOOST_AUTO_TEST_CASE(payable_fallback_unction)
checkInterface(sourceCode, interface);
}
+BOOST_AUTO_TEST_CASE(function_type)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function g(function(uint) external returns (uint) x) {}
+ }
+ )";
+
+ char const* interface = R"(
+ [
+ {
+ "constant" : false,
+ "payable": false,
+ "inputs": [{
+ "name": "x",
+ "type": "function"
+ }],
+ "name": "g",
+ "outputs": [],
+ "type" : "function"
+ }
+ ]
+ )";
+ checkInterface(sourceCode, interface);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 8600443d..4abe0894 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -353,6 +353,34 @@ BOOST_AUTO_TEST_CASE(while_loop)
testSolidityAgainstCppOnRange("f(uint256)", while_loop_cpp, 0, 5);
}
+
+BOOST_AUTO_TEST_CASE(do_while_loop)
+{
+ char const* sourceCode = "contract test {\n"
+ " function f(uint n) returns(uint nfac) {\n"
+ " nfac = 1;\n"
+ " var i = 2;\n"
+ " do { nfac *= i++; } while (i <= n);\n"
+ " }\n"
+ "}\n";
+ compileAndRun(sourceCode);
+
+ auto do_while_loop_cpp = [](u256 const& n) -> u256
+ {
+ u256 nfac = 1;
+ u256 i = 2;
+ do
+ {
+ nfac *= i++;
+ }
+ while (i <= n);
+
+ return nfac;
+ };
+
+ testSolidityAgainstCppOnRange("f(uint256)", do_while_loop_cpp, 0, 5);
+}
+
BOOST_AUTO_TEST_CASE(nested_loops)
{
// tests that break and continue statements in nested loops jump to the correct place
@@ -1309,6 +1337,7 @@ BOOST_AUTO_TEST_CASE(struct_accessor)
BOOST_AUTO_TEST_CASE(balance)
{
char const* sourceCode = "contract test {\n"
+ " function test() payable {}\n"
" function getBalance() returns (uint256 balance) {\n"
" return address(this).balance;\n"
" }\n"
@@ -1320,6 +1349,7 @@ BOOST_AUTO_TEST_CASE(balance)
BOOST_AUTO_TEST_CASE(blockchain)
{
char const* sourceCode = "contract test {\n"
+ " function test() payable {}\n"
" function someInfo() payable returns (uint256 value, address coinbase, uint256 blockNumber) {\n"
" value = msg.value;\n"
" coinbase = block.coinbase;\n"
@@ -1535,6 +1565,7 @@ BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_greater_size)
BOOST_AUTO_TEST_CASE(send_ether)
{
char const* sourceCode = "contract test {\n"
+ " function test() payable {}\n"
" function a(address addr, uint amount) returns (uint ret) {\n"
" addr.send(amount);\n"
" return address(this).balance;\n"
@@ -1647,6 +1678,7 @@ BOOST_AUTO_TEST_CASE(log_in_constructor)
BOOST_AUTO_TEST_CASE(suicide)
{
char const* sourceCode = "contract test {\n"
+ " function test() payable {}\n"
" function a(address receiver) returns (uint ret) {\n"
" suicide(receiver);\n"
" return 10;\n"
@@ -1663,6 +1695,7 @@ BOOST_AUTO_TEST_CASE(suicide)
BOOST_AUTO_TEST_CASE(selfdestruct)
{
char const* sourceCode = "contract test {\n"
+ " function test() payable {}\n"
" function a(address receiver) returns (uint ret) {\n"
" selfdestruct(receiver);\n"
" return 10;\n"
@@ -2928,24 +2961,24 @@ BOOST_AUTO_TEST_CASE(generic_call)
BOOST_AUTO_TEST_CASE(generic_callcode)
{
char const* sourceCode = R"**(
- contract receiver {
+ contract Receiver {
uint public received;
function receive(uint256 x) payable { received = x; }
}
- contract sender {
+ contract Sender {
uint public received;
- function sender() payable { }
+ function Sender() payable { }
function doSend(address rec) returns (uint d)
{
bytes4 signature = bytes4(bytes32(sha3("receive(uint256)")));
rec.callcode.value(2)(signature, 23);
- return receiver(rec).received();
+ return Receiver(rec).received();
}
}
)**";
- compileAndRun(sourceCode, 0, "receiver");
+ compileAndRun(sourceCode, 0, "Receiver");
u160 const c_receiverAddress = m_contractAddress;
- compileAndRun(sourceCode, 50, "sender");
+ compileAndRun(sourceCode, 50, "Sender");
u160 const c_senderAddress = m_contractAddress;
BOOST_CHECK(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(0));
BOOST_CHECK(callContractFunction("received()") == encodeArgs(23));
@@ -2960,16 +2993,18 @@ BOOST_AUTO_TEST_CASE(generic_callcode)
BOOST_AUTO_TEST_CASE(generic_delegatecall)
{
char const* sourceCode = R"**(
- contract receiver {
+ contract Receiver {
uint public received;
address public sender;
uint public value;
+ function Receiver() payable {}
function receive(uint256 x) payable { received = x; sender = msg.sender; value = msg.value; }
}
- contract sender {
+ contract Sender {
uint public received;
address public sender;
uint public value;
+ function Sender() payable {}
function doSend(address rec) payable
{
bytes4 signature = bytes4(bytes32(sha3("receive(uint256)")));
@@ -2977,9 +3012,9 @@ BOOST_AUTO_TEST_CASE(generic_delegatecall)
}
}
)**";
- compileAndRun(sourceCode, 0, "receiver");
+ compileAndRun(sourceCode, 0, "Receiver");
u160 const c_receiverAddress = m_contractAddress;
- compileAndRun(sourceCode, 50, "sender");
+ compileAndRun(sourceCode, 50, "Sender");
u160 const c_senderAddress = m_contractAddress;
BOOST_CHECK(m_sender != c_senderAddress); // just for sanity
BOOST_CHECK(callContractFunctionWithValue("doSend(address)", 11, c_receiverAddress) == encodeArgs());
@@ -3314,6 +3349,42 @@ BOOST_AUTO_TEST_CASE(using_enums)
BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2));
}
+BOOST_AUTO_TEST_CASE(enum_explicit_overflow)
+{
+ char const* sourceCode = R"(
+ contract test {
+ enum ActionChoices { GoLeft, GoRight, GoStraight }
+ function test()
+ {
+ }
+ function getChoiceExp(uint x) returns (uint d)
+ {
+ choice = ActionChoices(x);
+ d = uint256(choice);
+ }
+ function getChoiceFromSigned(int x) returns (uint d)
+ {
+ choice = ActionChoices(x);
+ d = uint256(choice);
+ }
+ function getChoiceFromNegativeLiteral() returns (uint d)
+ {
+ choice = ActionChoices(-1);
+ d = uint256(choice);
+ }
+ ActionChoices choice;
+ }
+ )";
+ compileAndRun(sourceCode);
+ // These should throw
+ BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 3) == encodeArgs());
+ BOOST_CHECK(callContractFunction("getChoiceFromSigned(int256)", -1) == encodeArgs());
+ BOOST_CHECK(callContractFunction("getChoiceFromNegativeLiteral()") == encodeArgs());
+ // These should work
+ BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 2) == encodeArgs(2));
+ BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 0) == encodeArgs(0));
+}
+
BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name)
{
char const* sourceCode = R"(
@@ -4435,6 +4506,67 @@ BOOST_AUTO_TEST_CASE(external_types_in_calls)
BOOST_CHECK(callContractFunction("t2()") == encodeArgs(u256(9)));
}
+BOOST_AUTO_TEST_CASE(invalid_enum_as_external_ret)
+{
+ char const* sourceCode = R"(
+ contract C {
+ enum X { A, B }
+
+ function test_return() returns (X) {
+ X garbled;
+ assembly {
+ garbled := 5
+ }
+ return garbled;
+ }
+ function test_inline_assignment() returns (X _ret) {
+ assembly {
+ _ret := 5
+ }
+ }
+ function test_assignment() returns (X _ret) {
+ X tmp;
+ assembly {
+ tmp := 5
+ }
+ _ret = tmp;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ // both should throw
+ BOOST_CHECK(callContractFunction("test_return()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("test_inline_assignment()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("test_assignment()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(invalid_enum_as_external_arg)
+{
+ char const* sourceCode = R"(
+ contract C {
+ enum X { A, B }
+
+ function tested (X x) returns (uint) {
+ return 1;
+ }
+
+ function test() returns (uint) {
+ X garbled;
+
+ assembly {
+ garbled := 5
+ }
+
+ return this.tested(garbled);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ // should throw
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs());
+}
+
+
BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes)
{
// bug #1798
@@ -4693,6 +4825,7 @@ BOOST_AUTO_TEST_CASE(failing_send)
}
}
contract Main {
+ function Main() payable {}
function callHelper(address _a) returns (bool r, uint bal) {
r = !_a.send(5);
bal = this.balance;
@@ -4715,6 +4848,7 @@ BOOST_AUTO_TEST_CASE(send_zero_ether)
}
}
contract Main {
+ function Main() payable {}
function s() returns (bool) {
var r = new Receiver();
return r.send(0);
@@ -6216,6 +6350,7 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library)
char const* sourceCode = R"(
library lib {}
contract c {
+ function c() payable {}
function f(address x) returns (bool) {
return x.send(1);
}
@@ -6325,6 +6460,20 @@ BOOST_AUTO_TEST_CASE(decayed_tuple)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2)));
}
+BOOST_AUTO_TEST_CASE(inline_tuple_with_rational_numbers)
+{
+ char const* sourceCode = R"(
+ contract c {
+ function f() returns (int8) {
+ int8[5] memory foo3 = [int8(1), -1, 0, 0, 0];
+ return foo3[0];
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
+}
+
BOOST_AUTO_TEST_CASE(destructuring_assignment)
{
char const* sourceCode = R"(
@@ -7140,6 +7289,7 @@ BOOST_AUTO_TEST_CASE(failed_create)
contract D { function D() payable {} }
contract C {
uint public x;
+ function C() payable {}
function f(uint amount) returns (address) {
x++;
return (new D).value(amount)();
@@ -7253,7 +7403,7 @@ BOOST_AUTO_TEST_CASE(mutex)
}
contract Fund is mutexed {
uint shares;
- function Fund() { shares = msg.value; }
+ function Fund() payable { shares = msg.value; }
function withdraw(uint amount) protected returns (uint) {
// NOTE: It is very bad practice to write this function this way.
// Please refer to the documentation of how to do this properly.
@@ -7467,6 +7617,568 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)
BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7)));
}
+BOOST_AUTO_TEST_CASE(calling_uninitialized_function)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function intern() returns (uint) {
+ function (uint) internal returns (uint) x;
+ x(2);
+ return 7;
+ }
+ function extern() returns (uint) {
+ function (uint) external returns (uint) x;
+ x(2);
+ return 7;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ // This should throw exceptions
+ BOOST_CHECK(callContractFunction("intern()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("extern()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function() internal returns (uint) x;
+ int mutex;
+ function t() returns (uint) {
+ if (mutex > 0)
+ return 7;
+ mutex = 1;
+ // Avoid re-executing this function if we jump somewhere.
+ x();
+ return 2;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(pass_function_types_internally)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint x) returns (uint) {
+ return eval(g, x);
+ }
+ function eval(function(uint) returns (uint) x, uint a) internal returns (uint) {
+ return x(a);
+ }
+ function g(uint x) returns (uint) { return x + 1; }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8)));
+}
+
+BOOST_AUTO_TEST_CASE(pass_function_types_externally)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint x) returns (uint) {
+ return this.eval(this.g, x);
+ }
+ function f2(uint x) returns (uint) {
+ return eval(this.g, x);
+ }
+ function eval(function(uint) external returns (uint) x, uint a) returns (uint) {
+ return x(a);
+ }
+ function g(uint x) returns (uint) { return x + 1; }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("f2(uint256)", 7) == encodeArgs(u256(8)));
+}
+
+BOOST_AUTO_TEST_CASE(receive_external_function_type)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function g() returns (uint) { return 7; }
+ function f(function() external returns (uint) g) returns (uint) {
+ return g();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction(
+ "f(function)",
+ m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
+ ) == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(return_external_function_type)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function g() {}
+ function f() returns (function() external) {
+ return this.g;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(
+ callContractFunction("f()") ==
+ m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
+ );
+}
+
+BOOST_AUTO_TEST_CASE(store_function)
+{
+ char const* sourceCode = R"(
+ contract Other {
+ function addTwo(uint x) returns (uint) { return x + 2; }
+ }
+ contract C {
+ function (function (uint) external returns (uint)) returns (uint) ev;
+ function (uint) external returns (uint) x;
+ function store(function(uint) external returns (uint) y) {
+ x = y;
+ }
+ function eval(function(uint) external returns (uint) y) returns (uint) {
+ return y(7);
+ }
+ function t() returns (uint) {
+ ev = eval;
+ this.store((new Other()).addTwo);
+ return ev(x);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(9)));
+}
+
+BOOST_AUTO_TEST_CASE(store_function_in_constructor)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public result_in_constructor;
+ function (uint) internal returns (uint) x;
+ function C () {
+ x = double;
+ result_in_constructor = use(2);
+ }
+ function double(uint _arg) returns (uint _ret) {
+ _ret = _arg * 2;
+ }
+ function use(uint _arg) returns (uint) {
+ return x(_arg);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6)));
+ BOOST_CHECK(callContractFunction("result_in_constructor()") == encodeArgs(u256(4)));
+}
+
+// TODO: store bound internal library functions
+
+BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function () internal returns (uint) x;
+ function C () {
+ x = unused;
+ }
+ function unused() internal returns (uint) {
+ return 7;
+ }
+ function t() returns (uint) {
+ return x();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor)
+{
+ char const* sourceCode = R"(
+ library L { function x() internal returns (uint) { return 7; } }
+ contract C {
+ function () internal returns (uint) x;
+ function C () {
+ x = L.x;
+ }
+ function t() returns (uint) {
+ return x();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public initial;
+ function C() {
+ initial = double(2);
+ }
+ function double(uint _arg) returns (uint _ret) {
+ _ret = _arg * 2;
+ }
+ function runtime(uint _arg) returns (uint) {
+ return double(_arg);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6)));
+ BOOST_CHECK(callContractFunction("initial()") == encodeArgs(u256(4)));
+}
+
+BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function (uint) internal returns (uint) x;
+ function C() {
+ x = double;
+ }
+ function test() returns (bool) {
+ return x == double;
+ }
+ function double(uint _arg) returns (uint _ret) {
+ _ret = _arg * 2;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(true));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_library_internal)
+{
+ char const* sourceCode = R"(
+ library Utils {
+ function reduce(uint[] memory array, function(uint, uint) returns (uint) f, uint init) internal returns (uint) {
+ for (uint i = 0; i < array.length; i++) {
+ init = f(array[i], init);
+ }
+ return init;
+ }
+ function sum(uint a, uint b) internal returns (uint) {
+ return a + b;
+ }
+ }
+ contract C {
+ function f(uint[] x) returns (uint) {
+ return Utils.reduce(x, Utils.sum, 0);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)) == encodeArgs(u256(11)));
+}
+
+
+BOOST_AUTO_TEST_CASE(call_function_returning_function)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f0() returns (uint) {
+ return 2;
+ }
+ function f1() internal returns (function() returns (uint)) {
+ return f0;
+ }
+ function f2() internal returns (function() returns (function () returns (uint))) {
+ return f1;
+ }
+ function f3() internal returns (function() returns (function () returns (function () returns (uint))))
+ {
+ return f2;
+ }
+ function f() returns (uint) {
+ function() returns(function() returns(function() returns(function() returns(uint)))) x;
+ x = f3;
+ return x()()()();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "test");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(mapping_of_functions)
+{
+ char const* sourceCode = R"(
+ contract Flow {
+ bool public success;
+
+ mapping (address => function () internal) stages;
+
+ function stage0() internal {
+ stages[msg.sender] = stage1;
+ }
+
+ function stage1() internal {
+ stages[msg.sender] = stage2;
+ }
+
+ function stage2() internal {
+ success = true;
+ }
+
+ function Flow() {
+ stages[msg.sender] = stage0;
+ }
+
+ function f() returns (uint) {
+ stages[msg.sender]();
+ return 7;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "Flow");
+ BOOST_CHECK(callContractFunction("success()") == encodeArgs(false));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("success()") == encodeArgs(false));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("success()") == encodeArgs(true));
+}
+
+BOOST_AUTO_TEST_CASE(packed_functions)
+{
+ char const* sourceCode = R"(
+ contract C {
+ // these should take the same slot
+ function() returns (uint) a;
+ function() external returns (uint) b;
+ function() external returns (uint) c;
+ function() returns (uint) d;
+ uint8 public x;
+
+ function set() {
+ x = 2;
+ d = g;
+ c = this.h;
+ b = this.h;
+ a = g;
+ }
+ function t1() returns (uint) {
+ return a();
+ }
+ function t2() returns (uint) {
+ return b();
+ }
+ function t3() returns (uint) {
+ return a();
+ }
+ function t4() returns (uint) {
+ return b();
+ }
+ function g() returns (uint) {
+ return 7;
+ }
+ function h() returns (uint) {
+ return 8;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("set()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("t1()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("t2()") == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("t3()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("t4()") == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(function_memory_array)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function a(uint x) returns (uint) { return x + 1; }
+ function b(uint x) returns (uint) { return x + 2; }
+ function c(uint x) returns (uint) { return x + 3; }
+ function d(uint x) returns (uint) { return x + 5; }
+ function e(uint x) returns (uint) { return x + 8; }
+ function test(uint x, uint i) returns (uint) {
+ function(uint) internal returns (uint)[] memory arr =
+ new function(uint) internal returns (uint)[](10);
+ arr[0] = a;
+ arr[1] = b;
+ arr[2] = c;
+ arr[3] = d;
+ arr[4] = e;
+ return arr[i](x);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(0)) == encodeArgs(u256(11)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(1)) == encodeArgs(u256(12)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(2)) == encodeArgs(u256(13)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(3)) == encodeArgs(u256(15)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(4)) == encodeArgs(u256(18)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(5)) == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(function_delete_storage)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function a() returns (uint) { return 7; }
+ function() internal returns (uint) y;
+ function set() returns (uint) {
+ y = a;
+ return y();
+ }
+ function d() returns (uint) {
+ delete y;
+ return 1;
+ }
+ function ca() returns (uint) {
+ return y();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("set()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("ca()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("d()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("ca()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(function_delete_stack)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function a() returns (uint) { return 7; }
+ function test() returns (uint) {
+ var y = a;
+ delete y;
+ y();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(copy_function_storage_array)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function() internal returns (uint)[] x;
+ function() internal returns (uint)[] y;
+ function test() returns (uint) {
+ x.length = 10;
+ x[9] = a;
+ y = x;
+ return y[9]();
+ }
+ function a() returns (uint) {
+ return 7;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(function_array_cross_calls)
+{
+ char const* sourceCode = R"(
+ contract D {
+ function f(function() external returns (function() external returns (uint))[] x)
+ returns (function() external returns (uint)[3] r)
+ {
+ r[0] = x[0]();
+ r[1] = x[1]();
+ r[2] = x[2]();
+ }
+ }
+ contract C {
+ function test() returns (uint, uint, uint) {
+ function() external returns (function() external returns (uint))[] memory x =
+ new function() external returns (function() external returns (uint))[](10);
+ for (uint i = 0; i < x.length; i ++)
+ x[i] = this.h;
+ x[0] = this.htwo;
+ var y = (new D()).f(x);
+ return (y[0](), y[1](), y[2]());
+ }
+ function e() returns (uint) { return 5; }
+ function f() returns (uint) { return 6; }
+ function g() returns (uint) { return 7; }
+ uint counter;
+ function h() returns (function() external returns (uint)) {
+ return counter++ == 0 ? this.f : this.g;
+ }
+ function htwo() returns (function() external returns (uint)) {
+ return this.e;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(5), u256(6), u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function() internal returns (uint)[20] x;
+ int mutex;
+ function one() returns (uint) {
+ function() internal returns (uint)[20] xmem;
+ x = xmem;
+ return 3;
+ }
+ function two() returns (uint) {
+ if (mutex > 0)
+ return 7;
+ mutex = 1;
+ // If this test fails, it might re-execute this function.
+ x[0]();
+ return 2;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("one()") == encodeArgs(u256(3)));
+ BOOST_CHECK(callContractFunction("two()") == encodeArgs());
+}
+
BOOST_AUTO_TEST_CASE(shift_constant_left)
{
char const* sourceCode = R"(
@@ -7553,6 +8265,21 @@ BOOST_AUTO_TEST_CASE(packed_storage_overflow)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe)));
}
+BOOST_AUTO_TEST_CASE(inline_assembly_invalidjumplabel)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() {
+ assembly {
+ jump(invalidJumpLabel)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs());
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index e9a05745..91edfefd 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -325,12 +325,12 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(Instruction::ADD),
byte(Instruction::DUP2),
byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x2,
+ byte(Instruction::PUSH1), 0x0,
byte(Instruction::JUMPI),
byte(Instruction::MOD),
byte(Instruction::DUP2),
byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x2,
+ byte(Instruction::PUSH1), 0x0,
byte(Instruction::JUMPI),
byte(Instruction::DIV),
byte(Instruction::MUL)});
@@ -425,39 +425,6 @@ BOOST_AUTO_TEST_CASE(assignment)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
-BOOST_AUTO_TEST_CASE(function_call)
-{
- char const* sourceCode = "contract test {\n"
- " function f(uint a, uint b) { a += g(a + 1, b) * 2; }\n"
- " function g(uint a, uint b) returns (uint c) {}\n"
- "}\n";
- bytes code = compileFirstExpression(sourceCode, {{"test", "g"}},
- {{"test", "f", "a"}, {"test", "f", "b"}});
-
- // Stack: a, b
- bytes expectation({byte(Instruction::PUSH1), 0x02,
- byte(Instruction::PUSH1), 0x0c,
- byte(Instruction::PUSH1), 0x01,
- byte(Instruction::DUP5),
- byte(Instruction::ADD),
- // Stack here: a b 2 <ret label> (a+1)
- byte(Instruction::DUP4),
- byte(Instruction::PUSH1), 0x13,
- byte(Instruction::JUMP),
- byte(Instruction::JUMPDEST),
- // Stack here: a b 2 g(a+1, b)
- byte(Instruction::MUL),
- // Stack here: a b g(a+1, b)*2
- byte(Instruction::DUP3),
- byte(Instruction::ADD),
- // Stack here: a b a+g(a+1, b)*2
- byte(Instruction::SWAP2),
- byte(Instruction::POP),
- byte(Instruction::DUP2),
- byte(Instruction::JUMPDEST)});
- BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
-}
-
BOOST_AUTO_TEST_CASE(negative_literals_8bits)
{
char const* sourceCode = "contract test {\n"
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 640cc108..865eb7ce 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -57,7 +57,7 @@ parseAnalyseAndReturnError(string const& _source, bool _reportWarnings = false,
{
sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(source)));
if(!sourceUnit)
- return make_pair(sourceUnit, nullptr);
+ BOOST_FAIL("Parsing failed in type checker test.");
SyntaxChecker syntaxChecker(errors);
if (!syntaxChecker.checkSyntax(*sourceUnit))
@@ -1535,6 +1535,21 @@ BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay)
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(enum_to_enum_conversion_is_not_okay)
+{
+ char const* text = R"(
+ contract test {
+ enum Paper { Up, Down, Left, Right }
+ enum Ground { North, South, West, East }
+ function test()
+ {
+ Ground(Paper.Up);
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(enum_duplicate_values)
{
char const* text = R"(
@@ -4015,8 +4030,8 @@ BOOST_AUTO_TEST_CASE(calling_payable)
char const* text = R"(
contract receiver { function pay() payable {} }
contract test {
- funciton f() { (new receiver()).pay.value(10)(); }
- recevier r = new receiver();
+ function f() { (new receiver()).pay.value(10)(); }
+ receiver r = new receiver();
function g() { r.pay.value(10)(); }
}
)";
@@ -4117,6 +4132,231 @@ BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype)
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(function_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ function(uint) returns (uint) x;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_parameter)
+{
+ char const* text = R"(
+ contract C {
+ function f(function(uint) external returns (uint) g) returns (function(uint) external returns (uint)) {
+ return g;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_returned)
+{
+ char const* text = R"(
+ contract C {
+ function f() returns (function(uint) external returns (uint) g) {
+ return g;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(private_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ function(uint) private returns (uint) x;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(public_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ function(uint) public returns (uint) x;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(payable_internal_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) internal payable returns (uint) x;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(call_value_on_non_payable_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) external returns (uint) x;
+ function f() {
+ x.value(2)();
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(external_function_type_returning_internal)
+{
+ char const* text = R"(
+ contract C {
+ function() external returns (function () internal) x;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(external_function_type_taking_internal)
+{
+ char const* text = R"(
+ contract C {
+ function(function () internal) external x;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(call_value_on_payable_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) external payable returns (uint) x;
+ function f() {
+ x.value(2)(1);
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter)
+{
+ // It should not be possible to give internal functions
+ // as parameters to external functions.
+ char const* text = R"(
+ contract C {
+ function f(function(uint) internal returns (uint) x) {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_returned_from_public_function)
+{
+ // It should not be possible to return internal functions from external functions.
+ char const* text = R"(
+ contract C {
+ function f() returns (function(uint) internal returns (uint) x) {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_internal)
+{
+ char const* text = R"(
+ library L {
+ function f(function(uint) internal returns (uint) x) internal {
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_external)
+{
+ char const* text = R"(
+ library L {
+ function f(function(uint) internal returns (uint) x) {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(function_type_arrays)
+{
+ char const* text = R"(
+ contract C {
+ function(uint) external returns (uint)[] public x;
+ function(uint) internal returns (uint)[10] y;
+ function f() {
+ function(uint) returns (uint)[10] memory a;
+ function(uint) returns (uint)[10] storage b = y;
+ function(uint) external returns (uint)[] memory c;
+ c = new function(uint) external returns (uint)[](200);
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(delete_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function(uint) external returns (uint) x;
+ function(uint) internal returns (uint) y;
+ function f() {
+ delete x;
+ var a = y;
+ delete a;
+ delete y;
+ var c = f;
+ delete c;
+ function(uint) internal returns (uint) g;
+ delete g;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(delete_function_type_invalid)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ delete f;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(delete_external_function_type_invalid)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ delete this.f;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
{
char const* text = R"(
diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp
index 1f74e928..49844f15 100644
--- a/test/libsolidity/SolidityNatspecJSON.cpp
+++ b/test/libsolidity/SolidityNatspecJSON.cpp
@@ -45,21 +45,19 @@ public:
bool _userDocumentation
)
{
- std::string generatedDocumentationString;
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse("pragma solidity >=0.0;\n" + _code), "Parsing failed");
+ Json::Value generatedDocumentation;
if (_userDocumentation)
- generatedDocumentationString = m_compilerStack.metadata("", DocumentationType::NatspecUser);
+ generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecUser);
else
- generatedDocumentationString = m_compilerStack.metadata("", DocumentationType::NatspecDev);
- Json::Value generatedDocumentation;
- m_reader.parse(generatedDocumentationString, generatedDocumentation);
+ generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecDev);
Json::Value expectedDocumentation;
m_reader.parse(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(
expectedDocumentation == generatedDocumentation,
- "Expected " << _expectedDocumentationString <<
- "\n but got:\n" << generatedDocumentationString
+ "Expected " << expectedDocumentation.toStyledString() <<
+ "\n but got:\n" << generatedDocumentation.toStyledString()
);
}
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 562b7859..4991cf24 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -365,16 +365,6 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
// BOOST_CHECK_EQUAL(2, numSHA3s);
}
-BOOST_AUTO_TEST_CASE(successor_not_found_bug)
-{
- // This bug was caused because MSVC chose to use the u256->bool conversion
- // instead of u256->unsigned
- char const* sourceCode = R"(
- contract greeter { function greeter() {} }
- )";
- compileBothVersions(sourceCode);
-}
-
BOOST_AUTO_TEST_CASE(incorrect_storage_access_bug)
{
// This bug appeared because a sha3 operation with too low sequence number was used,
@@ -1238,6 +1228,24 @@ BOOST_AUTO_TEST_CASE(inconsistency)
compareVersions("trigger()");
}
+BOOST_AUTO_TEST_CASE(dead_code_elimination_across_assemblies)
+{
+ // This tests that a runtime-function that is stored in storage in the constructor
+ // is not removed as part of dead code elimination.
+ char const* sourceCode = R"(
+ contract DCE {
+ function () internal returns (uint) stored;
+ function DCE() {
+ stored = f;
+ }
+ function f() internal returns (uint) { return 7; }
+ function test() returns (uint) { return stored(); }
+ }
+ )";
+ compileBothVersions(sourceCode);
+ compareVersions("test()");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index a81a9828..914dbc30 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -824,7 +824,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration)
contract c {
enum foo { }
})";
- BOOST_CHECK(successParse(text));
+ BOOST_CHECK(!successParse(text));
}
BOOST_AUTO_TEST_CASE(malformed_enum_declaration)
@@ -1241,6 +1241,115 @@ BOOST_AUTO_TEST_CASE(payable_accessor)
BOOST_CHECK(!successParse(text));
}
+BOOST_AUTO_TEST_CASE(function_type_in_expression)
+{
+ char const* text = R"(
+ contract test {
+ function f(uint x, uint y) returns (uint a) {}
+ function g() {
+ function (uint, uint) internal returns (uint) f1 = f;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable)
+{
+ char const* text = R"(
+ contract test {
+ function (uint, uint) internal returns (uint) f1;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_modifiers)
+{
+ char const* text = R"(
+ contract test {
+ function (uint, uint) modifier1() returns (uint) f1;
+ }
+ )";
+ BOOST_CHECK(!successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_assignment)
+{
+ char const* text = R"(
+ contract test {
+ function f(uint x, uint y) returns (uint a) {}
+ function (uint, uint) internal returns (uint) f1 = f;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_in_struct)
+{
+ char const* text = R"(
+ contract test {
+ struct S {
+ function (uint x, uint y) internal returns (uint a) f;
+ function (uint, uint) external returns (uint) g;
+ uint d;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_parameter)
+{
+ char const* text = R"(
+ contract test {
+ function f(function(uint) external returns (uint) g) internal returns (uint a) {
+ return g(1);
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(calling_function)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ function() returns(function() returns(function() returns(function() returns(uint)))) x;
+ uint y;
+ y = x()()()();
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(mapping_and_array_of_functions)
+{
+ char const* text = R"(
+ contract test {
+ mapping (address => function() internal returns (uint)) a;
+ mapping (address => function() external) b;
+ mapping (address => function() external[]) c;
+ function() external[] d;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_state_variable)
+{
+ char const* text = R"(
+ contract test {
+ function() x;
+ function() y = x;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
}