aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-02-14 12:00:41 +0800
committerGitHub <noreply@github.com>2018-02-14 12:00:41 +0800
commit3155dd8058672ce8f04bc2c0f2536cb549067d0a (patch)
tree7ddb56e276c74db30671eb17ffdde5eda027142d /test
parentc4cbbb054b5ed3b8ceaa21ee5b47b0704762ff40 (diff)
parentef8292c6bb337d3c4b27836da6732b85021d1c5d (diff)
downloaddexon-solidity-3155dd8058672ce8f04bc2c0f2536cb549067d0a.tar.gz
dexon-solidity-3155dd8058672ce8f04bc2c0f2536cb549067d0a.tar.zst
dexon-solidity-3155dd8058672ce8f04bc2c0f2536cb549067d0a.zip
Merge pull request #3503 from ethereum/develop
Merge develop into release for v0.4.20.
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt4
-rwxr-xr-xtest/externalTests.sh85
-rw-r--r--test/fuzzer.cpp2
-rw-r--r--test/libdevcore/StringUtils.cpp88
-rw-r--r--test/libjulia/Common.cpp87
-rw-r--r--test/libjulia/Common.h55
-rw-r--r--test/libjulia/Disambiguator.cpp105
-rw-r--r--test/libjulia/FunctionGrouper.cpp85
-rw-r--r--test/libjulia/FunctionHoister.cpp85
-rw-r--r--test/libjulia/Inliner.cpp199
-rw-r--r--test/libjulia/Parser.cpp12
-rw-r--r--test/libjulia/Rematerialiser.cpp179
-rw-r--r--test/libjulia/Simplifier.cpp142
-rw-r--r--test/libjulia/UnusedPruner.cpp129
-rw-r--r--test/libsolidity/AnalysisFramework.cpp29
-rw-r--r--test/libsolidity/AnalysisFramework.h49
-rw-r--r--test/libsolidity/Assembly.cpp54
-rw-r--r--test/libsolidity/ErrorCheck.cpp39
-rw-r--r--test/libsolidity/ErrorCheck.h7
-rw-r--r--test/libsolidity/InlineAssembly.cpp91
-rw-r--r--test/libsolidity/JSONCompiler.cpp2
-rw-r--r--test/libsolidity/SMTChecker.cpp154
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp3
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp50
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp376
-rw-r--r--test/libsolidity/SolidityParser.cpp10
-rw-r--r--test/libsolidity/StandardCompiler.cpp105
-rw-r--r--test/libsolidity/ViewPureChecker.cpp65
-rwxr-xr-xtest/solcjsTests.sh63
29 files changed, 2140 insertions, 214 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6a8a4399..f36ad4c5 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -3,7 +3,7 @@ list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/fuzzer.cpp")
file(GLOB_RECURSE headers "*.h")
add_executable(soltest ${sources} ${headers})
-target_link_libraries(soltest PRIVATE soljson solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
+target_link_libraries(soltest PRIVATE libsolc solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
add_executable(solfuzzer fuzzer.cpp)
-target_link_libraries(solfuzzer soljson evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES})
+target_link_libraries(solfuzzer PRIVATE libsolc evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES})
diff --git a/test/externalTests.sh b/test/externalTests.sh
index 1cc0af19..2a5ff7ef 100755
--- a/test/externalTests.sh
+++ b/test/externalTests.sh
@@ -36,61 +36,32 @@ fi
SOLJSON="$1"
-DIR=$(mktemp -d)
-(
- echo "Running Zeppelin tests..."
- git clone --depth 1 https://github.com/OpenZeppelin/zeppelin-solidity.git "$DIR"
- cd "$DIR"
- npm install
- find . -name soljson.js -exec cp "$SOLJSON" {} \;
+function test_truffle
+{
+ name="$1"
+ repo="$2"
+ echo "Running $name tests..."
+ DIR=$(mktemp -d)
+ (
+ git clone --depth 1 "$repo" "$DIR"
+ cd "$DIR"
+ npm install
+ find . -name soljson.js -exec cp "$SOLJSON" {} \;
+ if [ "$name" == "Zeppelin" ]; then
+ # Fix some things that look like bugs (only seemed to fail on Node 6 and not Node 8)
+ # FIXME: report upstream or to web3.js?
+ sed -i -e 's/let token = await ERC827TokenMock.new();//;' test/token/ERC827/ERC827Token.js
+ sed -i -e 's/CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0)/CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, this.token.address)/' test/crowdsale/CappedCrowdsale.test.js
+ sed -i -e 's/RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, { from: owner })/RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, this.token.address, { from: owner })/' test/crowdsale/RefundableCrowdsale.test.js
+ fi
+ if [ "$name" == "Gnosis" ]; then
+ # Replace fixed-version pragmas in Gnosis (part of Consensys best practice)
+ find contracts test -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity 0/pragma solidity ^0/'
+ fi
+ npm run test
+ )
+ rm -rf "$DIR"
+}
- # This is a patch that lets truffle ignore the pre-release compiler warning
- cat > truffle.patch <<EOF
---- node_modules/truffle/build/cli.bundled.js 2017-11-27 16:56:47.114830112 +0100
-+++ /tmp/patched 2017-11-27 16:52:31.887064115 +0100
-@@ -313846,9 +313846,12 @@
- });
-
- output = JSON.parse(output);
-+ var errors = output.errors.filter(function(solidity_error) {
-+ return solidity_error.formattedMessage.indexOf("pre-release compiler") < 0;
-+ });
-
-- if (output.errors) {
-- throw new CompileError(output.errors[0].formattedMessage);
-+ if (errors) {
-+ throw new CompileError(errors[0].formattedMessage);
- }
-
- return {
-@@ -313901,9 +313904,13 @@
- return {error: importErrorKey};
- });
-
-- output = JSON.parse(output);
-+ output = JSON.parse(output);
-+
-+ var errors = output.errors.filter(function(solidity_error) {
-+ return solidity_error.formattedMessage.indexOf("pre-release compiler") < 0;
-+ });
-
-- var nonImportErrors = output.errors.filter(function(solidity_error) {
-+ var nonImportErrors = errors.filter(function(solidity_error) {
- // If the import error key is not found, we must not have an import error.
- // This means we have a *different* parsing error which we should show to the user.
- // Note: solc can return multiple parsing errors at once.
-@@ -313917,7 +313924,7 @@
-
- // Now, all errors must be import errors.
- // Filter out our forced import, then get the import paths of the rest.
-- var imports = output.errors.filter(function(solidity_error) {
-+ var imports = errors.filter(function(solidity_error) {
- return solidity_error.message.indexOf(failingImportFileName) < 0;
- }).map(function(solidity_error) {
- var matches = solidity_error.formattedMessage.match(/import[^'"]+("|')([^'"]+)("|');/);
-EOF
-
- patch node_modules/truffle/build/cli.bundled.js ./truffle.patch
- npm run test
-)
-rm -rf "$DIR"
+test_truffle Gnosis https://github.com/gnosis/gnosis-contracts.git
+test_truffle Zeppelin https://github.com/OpenZeppelin/zeppelin-solidity.git
diff --git a/test/fuzzer.cpp b/test/fuzzer.cpp
index 53ba7201..578e63a4 100644
--- a/test/fuzzer.cpp
+++ b/test/fuzzer.cpp
@@ -20,7 +20,7 @@
#include <libevmasm/Assembly.h>
#include <libevmasm/ConstantOptimiser.h>
-#include <solc/jsonCompiler.h>
+#include <libsolc/libsolc.h>
#include <json/json.h>
diff --git a/test/libdevcore/StringUtils.cpp b/test/libdevcore/StringUtils.cpp
new file mode 100644
index 00000000..597457cc
--- /dev/null
+++ b/test/libdevcore/StringUtils.cpp
@@ -0,0 +1,88 @@
+/*
+ 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 StringUtils routines.
+ */
+
+#include <libdevcore/StringUtils.h>
+
+#include "../TestHelper.h"
+
+using namespace std;
+
+namespace dev
+{
+namespace test
+{
+
+BOOST_AUTO_TEST_SUITE(StringUtils)
+
+BOOST_AUTO_TEST_CASE(test_similarity)
+{
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hello", 0), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hello", 1), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hellw", 1), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "helol", 1), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "helo", 1), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "helllo", 1), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hlllo", 1), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hllllo", 1), false);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hllllo", 2), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("hello", "hlllo", 2), true);
+ BOOST_CHECK_EQUAL(stringWithinDistance("a", "", 2), false);
+ BOOST_CHECK_EQUAL(stringWithinDistance("abc", "ba", 2), false);
+ BOOST_CHECK_EQUAL(stringWithinDistance("abc", "abcdef", 2), false);
+ BOOST_CHECK_EQUAL(stringWithinDistance("abcd", "wxyz", 2), false);
+ BOOST_CHECK_EQUAL(stringWithinDistance("", "", 2), true);
+}
+
+BOOST_AUTO_TEST_CASE(test_dldistance)
+{
+ BOOST_CHECK_EQUAL(stringDistance("hello", "hellw"), 1);
+ BOOST_CHECK_EQUAL(stringDistance("hello", "helol"), 1);
+ BOOST_CHECK_EQUAL(stringDistance("hello", "helo"), 1);
+ BOOST_CHECK_EQUAL(stringDistance("hello", "helllo"), 1);
+ BOOST_CHECK_EQUAL(stringDistance("hello", "hlllo"), 1);
+ BOOST_CHECK_EQUAL(stringDistance("hello", "hllllo"), 2);
+ BOOST_CHECK_EQUAL(stringDistance("a", ""), 1);
+ BOOST_CHECK_EQUAL(stringDistance("abc", "ba"), 2);
+ BOOST_CHECK_EQUAL(stringDistance("abc", "abcdef"), 3);
+ BOOST_CHECK_EQUAL(stringDistance("abcd", "wxyz"), 4);
+ BOOST_CHECK_EQUAL(stringDistance("", ""), 0);
+ BOOST_CHECK_EQUAL(stringDistance("abcdefghijklmnopqrstuvwxyz", "abcabcabcabcabcabcabcabca"), 23);
+
+}
+
+BOOST_AUTO_TEST_CASE(test_alternatives_list)
+{
+ vector<string> strings;
+ BOOST_CHECK_EQUAL(quotedAlternativesList(strings), "");
+ strings.push_back("a");
+ BOOST_CHECK_EQUAL(quotedAlternativesList(strings), "\"a\"");
+ strings.push_back("b");
+ BOOST_CHECK_EQUAL(quotedAlternativesList(strings), "\"a\" or \"b\"");
+ strings.push_back("c");
+ BOOST_CHECK_EQUAL(quotedAlternativesList(strings), "\"a\", \"b\" or \"c\"");
+ strings.push_back("d");
+ BOOST_CHECK_EQUAL(quotedAlternativesList(strings), "\"a\", \"b\", \"c\" or \"d\"");
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
diff --git a/test/libjulia/Common.cpp b/test/libjulia/Common.cpp
new file mode 100644
index 00000000..e1ab8215
--- /dev/null
+++ b/test/libjulia/Common.cpp
@@ -0,0 +1,87 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Common functions the iulia tests.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/Disambiguator.h>
+
+#include <libsolidity/parsing/Scanner.h>
+
+#include <libsolidity/inlineasm/AsmParser.h>
+#include <libsolidity/inlineasm/AsmAnalysis.h>
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <libsolidity/interface/SourceReferenceFormatter.h>
+#include <libsolidity/interface/ErrorReporter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia;
+using namespace dev::solidity;
+
+void dev::julia::test::printErrors(ErrorList const& _errors, Scanner const& _scanner)
+{
+ for (auto const& error: _errors)
+ SourceReferenceFormatter::printExceptionInformation(
+ cout,
+ *error,
+ (error->type() == Error::Type::Warning) ? "Warning" : "Error",
+ [&](std::string const&) -> Scanner const& { return _scanner; }
+ );
+}
+
+
+pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::julia::test::parse(string const& _source, bool _julia)
+{
+ auto flavour = _julia ? assembly::AsmFlavour::IULIA : assembly::AsmFlavour::Strict;
+ ErrorList errors;
+ ErrorReporter errorReporter(errors);
+ auto scanner = make_shared<Scanner>(CharStream(_source), "");
+ auto parserResult = assembly::Parser(errorReporter, flavour).parse(scanner);
+ if (parserResult)
+ {
+ BOOST_REQUIRE(errorReporter.errors().empty());
+ auto analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
+ assembly::AsmAnalyzer analyzer(*analysisInfo, errorReporter, flavour);
+ if (analyzer.analyze(*parserResult))
+ {
+ BOOST_REQUIRE(errorReporter.errors().empty());
+ return make_pair(parserResult, analysisInfo);
+ }
+ }
+ printErrors(errors, *scanner);
+ BOOST_FAIL("Invalid source.");
+
+ // Unreachable.
+ return {};
+}
+
+assembly::Block dev::julia::test::disambiguate(string const& _source, bool _julia)
+{
+ auto result = parse(_source, _julia);
+ return boost::get<Block>(Disambiguator(*result.second)(*result.first));
+}
+
+string dev::julia::test::format(string const& _source, bool _julia)
+{
+ return assembly::AsmPrinter(_julia)(*parse(_source, _julia).first);
+}
diff --git a/test/libjulia/Common.h b/test/libjulia/Common.h
new file mode 100644
index 00000000..1371101c
--- /dev/null
+++ b/test/libjulia/Common.h
@@ -0,0 +1,55 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Common functions the iulia tests.
+ */
+
+#pragma once
+
+#include <libsolidity/inlineasm/AsmData.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace dev
+{
+namespace solidity
+{
+class Scanner;
+class Error;
+using ErrorList = std::vector<std::shared_ptr<Error const>>;
+namespace assembly
+{
+struct AsmAnalysisInfo;
+}
+}
+namespace julia
+{
+namespace test
+{
+
+void printErrors(solidity::ErrorList const& _errors, solidity::Scanner const& _scanner);
+std::pair<std::shared_ptr<solidity::assembly::Block>, std::shared_ptr<solidity::assembly::AsmAnalysisInfo>>
+parse(std::string const& _source, bool _julia = true);
+solidity::assembly::Block disambiguate(std::string const& _source, bool _julia = true);
+std::string format(std::string const& _source, bool _julia = true);
+
+}
+}
+}
diff --git a/test/libjulia/Disambiguator.cpp b/test/libjulia/Disambiguator.cpp
new file mode 100644
index 00000000..a6338449
--- /dev/null
+++ b/test/libjulia/Disambiguator.cpp
@@ -0,0 +1,105 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia name disambiguator.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p(true);\
+ string result = p(disambiguate(_original));\
+ BOOST_CHECK_EQUAL(result, format(_expectation));\
+ BOOST_CHECK_EQUAL(result, p(disambiguate(result)));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaDisambiguator)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(variables)
+{
+ CHECK(
+ "{ { let a:u256 } { let a:u256 } }",
+ "{ { let a:u256 } { let a_1:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(variables_clash)
+{
+ CHECK(
+ "{ { let a:u256 let a_1:u256 } { let a:u256 } }",
+ "{ { let a:u256 let a_1:u256 } { let a_2:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(variables_inside_functions)
+{
+ CHECK(
+ "{ { let c:u256 let b:u256 } function f(a:u256, c:u256) -> b:u256 { let x:u256 } { let a:u256 let x:u256 } }",
+ "{ { let c:u256 let b:u256 } function f(a:u256, c_1:u256) -> b_1:u256 { let x:u256 } { let a_1:u256 let x_1:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(function_call)
+{
+ CHECK(
+ "{ { let a:u256, b:u256, c:u256, d:u256, f:u256 } { function f(a:u256) -> c:u256, d:u256 { let b:u256, c_1:u256 := f(a) } } }",
+ "{ { let a:u256, b:u256, c:u256, d:u256, f:u256 } { function f_1(a_1:u256) -> c_1:u256, d_1:u256 { let b_1:u256, c_1_1:u256 := f_1(a_1) } } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(for_statement)
+{
+ CHECK(
+ "{ { let a:u256, b:u256 } { for { let a:u256 } a { a := a } { let b:u256 := a } } }",
+ "{ { let a:u256, b:u256 } { for { let a_1:u256 } a_1 { a_1 := a_1 } { let b_1:u256 := a_1 } } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(switch_statement)
+{
+ CHECK(
+ "{ { let a:u256, b:u256, c:u256 } { let a:u256 switch a case 0:u256 { let b:u256 := a } default { let c:u256 := a } } }",
+ "{ { let a:u256, b:u256, c:u256 } { let a_1:u256 switch a_1 case 0:u256 { let b_1:u256 := a_1 } default { let c_1:u256 := a_1 } } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(if_statement)
+{
+ CHECK(
+ "{ { let a:u256, b:u256, c:u256 } { let a:bool if a { let b:bool := a } } }",
+ "{ { let a:u256, b:u256, c:u256 } { let a_1:bool if a_1 { let b_1:bool := a_1 } } }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/FunctionGrouper.cpp b/test/libjulia/FunctionGrouper.cpp
new file mode 100644
index 00000000..78f382cb
--- /dev/null
+++ b/test/libjulia/FunctionGrouper.cpp
@@ -0,0 +1,85 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia function grouper.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/FunctionGrouper.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p(true);\
+ Block b = disambiguate(_original);\
+ (FunctionGrouper{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaFunctionGrouper)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ { } }");
+}
+
+BOOST_AUTO_TEST_CASE(single_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() {} }",
+ "{ { let a:u256 } function f() {} }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_fun_mixed)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 } let c:u256 function g() { let d:u256 } let e:u256 }",
+ "{ { let a:u256 let c:u256 let e:u256 } function f() { let b:u256 } function g() { let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(nested_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 function g() { let c:u256} let d:u256 } }",
+ "{ { let a:u256 } function f() { let b:u256 function g() { let c:u256} let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(empty_block)
+{
+ CHECK(
+ "{ let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }",
+ "{ { let a:u256 { } } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/FunctionHoister.cpp b/test/libjulia/FunctionHoister.cpp
new file mode 100644
index 00000000..3d6fff85
--- /dev/null
+++ b/test/libjulia/FunctionHoister.cpp
@@ -0,0 +1,85 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia function hoister.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/FunctionHoister.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p(true);\
+ Block b = disambiguate(_original);\
+ (FunctionHoister{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaFunctionHoister)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(single_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() {} }",
+ "{ let a:u256 function f() {} }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_fun_mixed)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 } let c:u256 function g() { let d:u256 } let e:u256 }",
+ "{ let a:u256 let c:u256 let e:u256 function f() { let b:u256 } function g() { let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(nested_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 function g() { let c:u256} let d:u256 } }",
+ "{ let a:u256 function g() { let c:u256 } function f() { let b:u256 let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(empty_block)
+{
+ CHECK(
+ "{ let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }",
+ "{ let a:u256 function f() -> x:bool { let b:u256 := 4:u256 for {} f() {} {} } }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/Inliner.cpp b/test/libjulia/Inliner.cpp
new file mode 100644
index 00000000..88b51f28
--- /dev/null
+++ b/test/libjulia/Inliner.cpp
@@ -0,0 +1,199 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia function inliner.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/ExpressionInliner.h>
+#include <libjulia/optimiser/InlinableExpressionFunctionFinder.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <boost/range/adaptors.hpp>
+#include <boost/algorithm/string/join.hpp>
+
+using namespace std;
+using namespace dev;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+namespace
+{
+string inlinableFunctions(string const& _source)
+{
+ auto ast = disambiguate(_source);
+
+ InlinableExpressionFunctionFinder funFinder;
+ funFinder(ast);
+
+ return boost::algorithm::join(
+ funFinder.inlinableFunctions() | boost::adaptors::map_keys,
+ ","
+ );
+}
+
+string inlineFunctions(string const& _source, bool _julia = true)
+{
+ auto ast = disambiguate(_source, _julia);
+ ExpressionInliner(ast).run();
+ return assembly::AsmPrinter(_julia)(ast);
+}
+}
+
+BOOST_AUTO_TEST_SUITE(IuliaInlinableFunctionFilter)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ }"), "");
+}
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := 2:u256 } }"), "f");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{"
+ "function g(a:u256) -> b:u256 { b := a }"
+ "function f() -> x:u256 { x := g(2:u256) }"
+ "}"), "f,g");
+}
+
+BOOST_AUTO_TEST_CASE(simple_inside_structures)
+{
+ BOOST_CHECK_EQUAL(inlinableFunctions("{"
+ "switch 2:u256 "
+ "case 2:u256 {"
+ "function g(a:u256) -> b:u256 { b := a }"
+ "function f() -> x:u256 { x := g(2:u256) }"
+ "}"
+ "}"), "f,g");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{"
+ "for {"
+ "function g(a:u256) -> b:u256 { b := a }"
+ "} 1:u256 {"
+ "function f() -> x:u256 { x := g(2:u256) }"
+ "}"
+ "{"
+ "function h() -> y:u256 { y := 2:u256 }"
+ "}"
+ "}"), "f,g,h");
+}
+
+BOOST_AUTO_TEST_CASE(negative)
+{
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { } }"), "");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := 2:u256 {} } }"), "");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := f() } }"), "");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := x } }"), "");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256, y:u256 { x := 2:u256 } }"), "");
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(IuliaFunctionInliner)
+
+BOOST_AUTO_TEST_CASE(simple)
+{
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{ function f() -> x:u256 { x := 2:u256 } let y:u256 := f() }"),
+ format("{ function f() -> x:u256 { x := 2:u256 } let y:u256 := 2:u256 }")
+ );
+}
+
+BOOST_AUTO_TEST_CASE(with_args)
+{
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{ function f(a:u256) -> x:u256 { x := a } let y:u256 := f(7:u256) }"),
+ format("{ function f(a:u256) -> x:u256 { x := a } let y:u256 := 7:u256 }")
+ );
+}
+
+BOOST_AUTO_TEST_CASE(no_inline_with_mload)
+{
+ // Does not inline because mload could be moved out of sequence
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{ function f(a) -> x { x := a } let y := f(mload(2)) }", false),
+ format("{ function f(a) -> x { x := a } let y := f(mload(2)) }", false)
+ );
+}
+
+BOOST_AUTO_TEST_CASE(no_move_with_side_effects)
+{
+ // The calls to g and h cannot be moved because g and h are not movable. Therefore, the call
+ // to f is not inlined.
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{"
+ "function f(a, b) -> x { x := add(b, a) }"
+ "function g() -> y { y := mload(0) mstore(0, 4) }"
+ "function h() -> z { mstore(0, 4) z := mload(0) }"
+ "let r := f(g(), h())"
+ "}", false),
+ format("{"
+ "function f(a, b) -> x { x := add(b, a) }"
+ "function g() -> y { y := mload(0) mstore(0, 4) }"
+ "function h() -> z { mstore(0, 4) z := mload(0) }"
+ "let r := f(g(), h())"
+ "}", false)
+ );
+}
+
+BOOST_AUTO_TEST_CASE(complex_with_evm)
+{
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{ function f(a) -> x { x := add(a, a) } let y := f(calldatasize()) }", false),
+ format("{ function f(a) -> x { x := add(a, a) } let y := add(calldatasize(), calldatasize()) }", false)
+ );
+}
+
+BOOST_AUTO_TEST_CASE(double_calls)
+{
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{"
+ "function f(a) -> x { x := add(a, a) }"
+ "function g(b, c) -> y { y := mul(mload(c), f(b)) }"
+ "let y := g(calldatasize(), 7)"
+ "}", false),
+ format("{"
+ "function f(a) -> x { x := add(a, a) }"
+ "function g(b, c) -> y { y := mul(mload(c), add(b, b)) }"
+ "let y_1 := mul(mload(7), add(calldatasize(), calldatasize()))"
+ "}", false)
+ );
+}
+
+BOOST_AUTO_TEST_CASE(double_recursive_calls)
+{
+ BOOST_CHECK_EQUAL(
+ inlineFunctions("{"
+ "function f(a, r) -> x { x := g(a, g(r, r)) }"
+ "function g(b, s) -> y { y := f(b, f(s, s)) }"
+ "let y := g(calldatasize(), 7)"
+ "}", false),
+ format("{"
+ "function f(a, r) -> x { x := g(a, f(r, f(r, r))) }"
+ "function g(b, s) -> y { y := f(b, g(s, f(s, f(s, s))))}"
+ "let y_1 := f(calldatasize(), g(7, f(7, f(7, 7))))"
+ "}", false)
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp
index 9aa325a4..a8a41b3c 100644
--- a/test/libjulia/Parser.cpp
+++ b/test/libjulia/Parser.cpp
@@ -52,11 +52,11 @@ bool parse(string const& _source, ErrorReporter& errorReporter)
try
{
auto scanner = make_shared<Scanner>(CharStream(_source));
- auto parserResult = assembly::Parser(errorReporter, true).parse(scanner);
+ auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::IULIA).parse(scanner);
if (parserResult)
{
assembly::AsmAnalysisInfo analysisInfo;
- return (assembly::AsmAnalyzer(analysisInfo, errorReporter, true)).analyze(*parserResult);
+ return (assembly::AsmAnalyzer(analysisInfo, errorReporter, assembly::AsmFlavour::IULIA)).analyze(*parserResult);
}
}
catch (FatalError const&)
@@ -196,6 +196,14 @@ BOOST_AUTO_TEST_CASE(empty_call)
CHECK_ERROR("{ () }", ParserError, "Literal or identifier expected.");
}
+BOOST_AUTO_TEST_CASE(tokens_as_identifers)
+{
+ BOOST_CHECK(successParse("{ let return:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let byte:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let address:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let bool:u256 := 1:u256 }"));
+}
+
BOOST_AUTO_TEST_CASE(lacking_types)
{
CHECK_ERROR("{ let x := 1:u256 }", ParserError, "Expected token Identifier got 'Assign'");
diff --git a/test/libjulia/Rematerialiser.cpp b/test/libjulia/Rematerialiser.cpp
new file mode 100644
index 00000000..8f928f8e
--- /dev/null
+++ b/test/libjulia/Rematerialiser.cpp
@@ -0,0 +1,179 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the rematerialiser optimizer stage.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/Rematerialiser.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <boost/range/adaptors.hpp>
+#include <boost/algorithm/string/join.hpp>
+
+using namespace std;
+using namespace dev;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p;\
+ Block b = disambiguate(_original, false);\
+ (Rematerialiser{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation, false));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaRematerialiser)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(trivial)
+{
+ CHECK(
+ "{ let a := 1 let b := a mstore(0, b) }",
+ "{ let a := 1 let b := 1 mstore(0, 1) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(expression)
+{
+ CHECK(
+ "{ let a := add(mul(calldatasize(), 2), number()) let b := add(a, a) }",
+ "{ let a := add(mul(calldatasize(), 2), number()) let b := add("
+ "add(mul(calldatasize(), 2), number()),"
+ "add(mul(calldatasize(), 2), number())"
+ ") }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(reassign)
+{
+ CHECK(
+ "{ let a := extcodesize(0) let b := a let c := b a := 2 let d := add(b, c) pop(a) pop(b) pop(c) pop(d) }",
+ "{ let a := extcodesize(0) let b := a let c := a a := 2 let d := add(b, c) pop(2) pop(b) pop(c) pop(add(b, c)) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(non_movable_instr)
+{
+ CHECK(
+ "{ let a := 1 let b := mload(a) let c := a mstore(add(a, b), c) }",
+ "{ let a := 1 let b := mload(1) let c := 1 mstore(add(1, b), 1) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(non_movable_fun)
+{
+ CHECK(
+ "{ function f(x) -> y {} let a := 1 let b := f(a) let c := a mstore(add(a, b), c) }",
+ "{ function f(x) -> y {} let a := 1 let b := f(1) let c := 1 mstore(add(1, b), 1) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(branches_if)
+{
+ CHECK(
+ "{ let a := 1 let b := 2 if b { pop(b) b := a } let c := b }",
+ "{ let a := 1 let b := 2 if 2 { pop(2) b := 1 } let c := b }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(branches_switch)
+{
+ CHECK(
+ "{ let a := 1 let b := 2 switch number() case 1 { b := a } default { let x := a let y := b b := a } pop(add(a, b)) }",
+ "{ let a := 1 let b := 2 switch number() case 1 { b := 1 } default { let x := 1 let y := b b := 1 } pop(add(1, b)) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(branches_for)
+{
+ CHECK(
+ "{ let a := 1 for { pop(a) } a { pop(a) } { pop(a) } }",
+ "{ let a := 1 for { pop(1) } 1 { pop(1) } { pop(1) } }"
+ );
+ CHECK(
+ "{ let a := 1 for { pop(a) } a { pop(a) } { a := 7 let c := a } let x := a }",
+ "{ let a := 1 for { pop(1) } a { pop(7) } { a := 7 let c := 7 } let x := a }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(branches_for_declared_in_init)
+{
+ CHECK(
+ "{ let b := 0 for { let a := 1 pop(a) } a { pop(a) } { b := 1 pop(a) } }",
+ "{ let b := 0 for { let a := 1 pop(1) } 1 { pop(1) } { b := 1 pop(1) } }"
+ );
+ CHECK(
+ "{ let b := 0 for { let a := 1 pop(a) } lt(a, 0) { pop(a) a := add(a, 3) } { b := 1 pop(a) } }",
+ "{ let b := 0 for { let a := 1 pop(1) } lt(a, 0) { pop(a) a := add(a, 3) } { b := 1 pop(a) } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(reassignment)
+{
+ CHECK(
+ "{ let a := 1 pop(a) if a { a := 2 } let b := mload(a) pop(b) }",
+ "{ let a := 1 pop(1) if 1 { a := 2 } let b := mload(a) pop(b) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(update_assignment_remat)
+{
+ // We cannot substitute `a` in `let b := a`
+ CHECK(
+ "{ let a := extcodesize(0) a := mul(a, 2) let b := a }",
+ "{ let a := extcodesize(0) a := mul(a, 2) let b := a }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(do_not_move_out_of_scope)
+{
+ // Cannot replace by `let b := x` by `let b := a` since a is out of scope.
+ CHECK(
+ "{ let x { let a := sload(0) x := a } let b := x }",
+ "{ let x { let a := sload(0) x := a } let b := x }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(do_not_remat_large_amounts_of_code)
+{
+ CHECK(
+ "{ let x := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) let b := x }",
+ "{ let x := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) let b := x }"
+ );
+ CHECK(
+ "{ let x := add(mul(calldataload(2), calldataload(4)), calldatasize()) let b := x }",
+ "{ let x := add(mul(calldataload(2), calldataload(4)), calldatasize()) let b := add(mul(calldataload(2), calldataload(4)), calldatasize()) }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/Simplifier.cpp b/test/libjulia/Simplifier.cpp
new file mode 100644
index 00000000..4d4e8d53
--- /dev/null
+++ b/test/libjulia/Simplifier.cpp
@@ -0,0 +1,142 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the expression simplifier optimizer stage.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/ExpressionSimplifier.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <boost/range/adaptors.hpp>
+#include <boost/algorithm/string/join.hpp>
+
+using namespace std;
+using namespace dev;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p;\
+ Block b = *(parse(_original, false).first);\
+ (ExpressionSimplifier{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation, false));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaSimplifier)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(constants)
+{
+ CHECK(
+ "{ let a := add(1, mul(3, 4)) }",
+ "{ let a := 13 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(invariant)
+{
+ CHECK(
+ "{ let a := mload(sub(7, 7)) let b := sub(a, 0) }",
+ "{ let a := mload(0) let b := a }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(reversed)
+{
+ CHECK(
+ "{ let a := add(0, mload(0)) }",
+ "{ let a := mload(0) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(constant_propagation)
+{
+ CHECK(
+ "{ let a := add(7, sub(mload(0), 7)) }",
+ "{ let a := mload(0) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(identity_rules_simple)
+{
+ CHECK(
+ "{ let a := mload(0) let b := sub(a, a) }",
+ "{ let a := mload(0) let b := 0 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(identity_rules_complex)
+{
+ CHECK(
+ "{ let a := sub(calldataload(0), calldataload(0)) }",
+ "{ let a := 0 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(identity_rules_negative)
+{
+ CHECK(
+ "{ let a := sub(calldataload(1), calldataload(0)) }",
+ "{ let a := sub(calldataload(1), calldataload(0)) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(including_function_calls)
+{
+ CHECK(
+ "{ function f() -> a {} let b := add(7, sub(f(), 7)) }",
+ "{ function f() -> a {} let b := f() }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(inside_for)
+{
+ CHECK(
+ "{ for { let a := 10 } iszero(eq(a, 0)) { a := add(a, 1) } {} }",
+ "{ for { let a := 10 } iszero(iszero(a)) { a := add(a, 1) } {} }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(mod_and)
+{
+ CHECK(
+ "{ mstore(0, mod(calldataload(0), exp(2, 8))) }",
+ "{ mstore(0, and(calldataload(0), 255)) }"
+ );
+ CHECK(
+ "{ mstore(0, mod(calldataload(0), exp(2, 255))) }",
+ "{ mstore(0, and(calldataload(0), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/UnusedPruner.cpp b/test/libjulia/UnusedPruner.cpp
new file mode 100644
index 00000000..b86a54b3
--- /dev/null
+++ b/test/libjulia/UnusedPruner.cpp
@@ -0,0 +1,129 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the pruning of unused variables and functions.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/UnusedPruner.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <boost/range/adaptors.hpp>
+#include <boost/algorithm/string/join.hpp>
+
+using namespace std;
+using namespace dev;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p;\
+ Block b = disambiguate(_original, false);\
+ UnusedPruner::runUntilStabilised(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation, false));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaUnusedPruner)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(trivial)
+{
+ CHECK(
+ "{ let a := 1 let b := 1 mstore(0, 1) }",
+ "{ mstore(0, 1) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_declarations)
+{
+ CHECK(
+ "{ let x, y }",
+ "{ }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_assignments)
+{
+ CHECK(
+ "{ let x, y x := 1 y := 2 }",
+ "{ let x, y x := 1 y := 2 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_partial_assignments)
+{
+ CHECK(
+ "{ let x, y x := 1 }",
+ "{ let x, y x := 1 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(functions)
+{
+ CHECK(
+ "{ function f() { let a := 1 } function g() { f() } }",
+ "{ }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(intermediate_assignment)
+{
+ CHECK(
+ "{ let a := 1 a := 4 let b := 1 }",
+ "{ let a := 1 a := 4 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(intermediate_multi_assignment){
+ CHECK(
+ "{ let a, b function f() -> x { } a := f() b := 1 }",
+ "{ let a, b function f() -> x { } a := f() b := 1 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_declare)
+{
+ CHECK(
+ "{ function f() -> x, y { } let a, b := f() }",
+ "{ function f() -> x, y { } let a, b := f() }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_assign)
+{
+ CHECK(
+ "{ let a let b function f() -> x, y { } a, b := f() }",
+ "{ let a let b function f() -> x, y { } a, b := f() }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index ea9703ea..a27e3222 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -36,7 +36,7 @@ using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::test;
-pair<SourceUnit const*, shared_ptr<Error const>>
+pair<SourceUnit const*, ErrorList>
AnalysisFramework::parseAnalyseAndReturnError(
string const& _source,
bool _reportWarnings,
@@ -53,7 +53,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
m_compiler.analyze();
- std::shared_ptr<Error const> firstError;
+ ErrorList errors;
for (auto const& currentError: m_compiler.errors())
{
solAssert(currentError->comment(), "");
@@ -72,16 +72,15 @@ AnalysisFramework::parseAnalyseAndReturnError(
if (_reportWarnings || (currentError->type() != Error::Type::Warning))
{
- if (firstError && !_allowMultipleErrors)
+ if (!_allowMultipleErrors && !errors.empty())
{
BOOST_FAIL("Multiple errors found: " + formatErrors());
}
- if (!firstError)
- firstError = currentError;
+ errors.emplace_back(std::move(currentError));
}
}
- return make_pair(&m_compiler.ast(""), firstError);
+ return make_pair(&m_compiler.ast(""), errors);
}
SourceUnit const* AnalysisFramework::parseAndAnalyse(string const& _source)
@@ -89,23 +88,23 @@ SourceUnit const* AnalysisFramework::parseAndAnalyse(string const& _source)
auto sourceAndError = parseAnalyseAndReturnError(_source);
BOOST_REQUIRE(!!sourceAndError.first);
string message;
- if (sourceAndError.second)
- message = "Unexpected error: " + formatError(*sourceAndError.second);
- BOOST_REQUIRE_MESSAGE(!sourceAndError.second, message);
+ if (!sourceAndError.second.empty())
+ message = "Unexpected error: " + formatErrors();
+ BOOST_REQUIRE_MESSAGE(sourceAndError.second.empty(), message);
return sourceAndError.first;
}
bool AnalysisFramework::success(string const& _source)
{
- return !parseAnalyseAndReturnError(_source).second;
+ return parseAnalyseAndReturnError(_source).second.empty();
}
-Error AnalysisFramework::expectError(std::string const& _source, bool _warning, bool _allowMultiple)
+ErrorList AnalysisFramework::expectError(std::string const& _source, bool _warning, bool _allowMultiple)
{
- auto sourceAndError = parseAnalyseAndReturnError(_source, _warning, true, _allowMultiple);
- BOOST_REQUIRE(!!sourceAndError.second);
- BOOST_REQUIRE_MESSAGE(!!sourceAndError.first, "Expected error, but no error happened.");
- return *sourceAndError.second;
+ auto sourceAndErrors = parseAnalyseAndReturnError(_source, _warning, true, _allowMultiple);
+ BOOST_REQUIRE(!sourceAndErrors.second.empty());
+ BOOST_REQUIRE_MESSAGE(!!sourceAndErrors.first, "Expected error, but no error happened.");
+ return sourceAndErrors.second;
}
string AnalysisFramework::formatErrors()
diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h
index a566ba1d..6ecf4a5a 100644
--- a/test/libsolidity/AnalysisFramework.h
+++ b/test/libsolidity/AnalysisFramework.h
@@ -45,7 +45,7 @@ class AnalysisFramework
{
protected:
- virtual std::pair<SourceUnit const*, std::shared_ptr<Error const>>
+ virtual std::pair<SourceUnit const*, ErrorList>
parseAnalyseAndReturnError(
std::string const& _source,
bool _reportWarnings = false,
@@ -55,7 +55,7 @@ protected:
SourceUnit const* parseAndAnalyse(std::string const& _source);
bool success(std::string const& _source);
- Error expectError(std::string const& _source, bool _warning = false, bool _allowMultiple = false);
+ ErrorList expectError(std::string const& _source, bool _warning = false, bool _allowMultiple = false);
std::string formatErrors();
std::string formatError(Error const& _error);
@@ -70,34 +70,51 @@ protected:
dev::solidity::CompilerStack m_compiler;
};
+// Asserts that the compilation down to typechecking
+// emits multiple errors of different types and messages, provided in the second argument.
+#define CHECK_ALLOW_MULTI(text, expectations) \
+do \
+{ \
+ ErrorList errors = expectError((text), true, true); \
+ auto message = searchErrors(errors, (expectations)); \
+ BOOST_CHECK_MESSAGE(message.empty(), message); \
+} while(0)
-#define CHECK_ERROR_OR_WARNING(text, typ, substring, warning, allowMulti) \
+#define CHECK_ERROR_OR_WARNING(text, typ, substrings, warning, allowMulti) \
do \
{ \
- Error err = expectError((text), (warning), (allowMulti)); \
- BOOST_CHECK(err.type() == (Error::Type::typ)); \
- BOOST_CHECK(searchErrorMessage(err, (substring))); \
+ ErrorList errors = expectError((text), (warning), (allowMulti)); \
+ std::vector<std::pair<Error::Type, std::string>> expectations; \
+ for (auto const& str: substrings) \
+ expectations.emplace_back((Error::Type::typ), str); \
+ auto message = searchErrors(errors, expectations); \
+ BOOST_CHECK_MESSAGE(message.empty(), message); \
} while(0)
// [checkError(text, type, substring)] asserts that the compilation down to typechecking
// emits an error of type [type] and with a message containing [substring].
#define CHECK_ERROR(text, type, substring) \
-CHECK_ERROR_OR_WARNING(text, type, substring, false, false)
+CHECK_ERROR_OR_WARNING(text, type, std::vector<std::string>{(substring)}, false, false)
// [checkError(text, type, substring)] asserts that the compilation down to typechecking
-// emits an error of type [type] and with a message containing [substring].
-#define CHECK_ERROR_ALLOW_MULTI(text, type, substring) \
-CHECK_ERROR_OR_WARNING(text, type, substring, false, true)
+// emits multiple errors of the same type [type] and with a messages containing [substrings].
+// Because of the limitations of the preprocessor, you cannot use {{T1, "abc"}, {T2, "def"}} as arguments,
+// but have to replace them by (std::vector<std::pair<Error::Type, std::string>>{"abc", "def"})
+// (note the parentheses)
+#define CHECK_ERROR_ALLOW_MULTI(text, type, substrings) \
+CHECK_ERROR_OR_WARNING(text, type, substrings, false, true)
// [checkWarning(text, substring)] asserts that the compilation down to typechecking
// emits a warning and with a message containing [substring].
#define CHECK_WARNING(text, substring) \
-CHECK_ERROR_OR_WARNING(text, Warning, substring, true, false)
+CHECK_ERROR_OR_WARNING(text, Warning, std::vector<std::string>{(substring)}, true, false)
// [checkWarningAllowMulti(text, substring)] aserts that the compilation down to typechecking
// emits a warning and with a message containing [substring].
-#define CHECK_WARNING_ALLOW_MULTI(text, substring) \
-CHECK_ERROR_OR_WARNING(text, Warning, substring, true, true)
+// Because of the limitations of the preprocessor, you cannot use {"abc", "def"} as arguments,
+// but have to replace them by (std::vector<std::string>{"abc", "def"}) (note the parentheses)
+#define CHECK_WARNING_ALLOW_MULTI(text, substrings) \
+CHECK_ERROR_OR_WARNING(text, Warning, substrings, true, true)
// [checkSuccess(text)] asserts that the compilation down to typechecking succeeds.
#define CHECK_SUCCESS(text) do { BOOST_CHECK(success((text))); } while(0)
@@ -107,9 +124,9 @@ do \
{ \
auto sourceAndError = parseAnalyseAndReturnError((text), true); \
std::string message; \
- if (sourceAndError.second) \
- message = formatError(*sourceAndError.second); \
- BOOST_CHECK_MESSAGE(!sourceAndError.second, message); \
+ if (!sourceAndError.second.empty()) \
+ message = formatErrors();\
+ BOOST_CHECK_MESSAGE(sourceAndError.second.empty(), message); \
} \
while(0)
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 358d3c72..59af6d41 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -86,23 +86,59 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
return AssemblyItems();
}
+void printAssemblyLocations(AssemblyItems const& _items)
+{
+ auto printRepeated = [](SourceLocation const& _loc, size_t _repetitions)
+ {
+ cout <<
+ "\t\tvector<SourceLocation>(" <<
+ _repetitions <<
+ ", SourceLocation(" <<
+ _loc.start <<
+ ", " <<
+ _loc.end <<
+ ", make_shared<string>(\"" <<
+ *_loc.sourceName <<
+ "\"))) +" << endl;
+ };
+
+ vector<SourceLocation> locations;
+ for (auto const& item: _items)
+ locations.push_back(item.location());
+ size_t repetitions = 0;
+ SourceLocation const* previousLoc = nullptr;
+ for (size_t i = 0; i < locations.size(); ++i)
+ {
+ SourceLocation& loc = locations[i];
+ if (previousLoc && *previousLoc == loc)
+ repetitions++;
+ else
+ {
+ if (previousLoc)
+ printRepeated(*previousLoc, repetitions);
+ previousLoc = &loc;
+ repetitions = 1;
+ }
+ }
+ if (previousLoc)
+ printRepeated(*previousLoc, repetitions);
+}
+
void checkAssemblyLocations(AssemblyItems const& _items, vector<SourceLocation> const& _locations)
{
BOOST_CHECK_EQUAL(_items.size(), _locations.size());
for (size_t i = 0; i < min(_items.size(), _locations.size()); ++i)
{
- 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));
+ if (_items[i].location() != _locations[i])
+ {
+ BOOST_CHECK_MESSAGE(false, "Location mismatch for item " + to_string(i) + ". Found the following locations:");
+ printAssemblyLocations(_items);
+ return;
+ }
}
}
+
} // end anonymous namespace
BOOST_AUTO_TEST_SUITE(Assembly)
diff --git a/test/libsolidity/ErrorCheck.cpp b/test/libsolidity/ErrorCheck.cpp
index b1e94061..fba2c897 100644
--- a/test/libsolidity/ErrorCheck.cpp
+++ b/test/libsolidity/ErrorCheck.cpp
@@ -23,8 +23,19 @@
#include <libdevcore/Exceptions.h>
#include <string>
+#include <set>
using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+namespace
+{
+std::string errorMessage(Error const& _e)
+{
+ return _e.comment() ? *_e.comment() : "NONE";
+}
+}
bool dev::solidity::searchErrorMessage(Error const& _err, std::string const& _substr)
{
@@ -41,3 +52,31 @@ bool dev::solidity::searchErrorMessage(Error const& _err, std::string const& _su
cout << "Expected error message but found none." << endl;
return _substr.empty();
}
+
+string dev::solidity::searchErrors(ErrorList const& _errors, vector<pair<Error::Type, string>> const& _expectations)
+{
+ auto expectations = _expectations;
+ for (auto const& error: _errors)
+ {
+ string msg = errorMessage(*error);
+ bool found = false;
+ for (auto it = expectations.begin(); it != expectations.end(); ++it)
+ if (msg.find(it->second) != string::npos && error->type() == it->first)
+ {
+ found = true;
+ expectations.erase(it);
+ break;
+ }
+ if (!found)
+ return "Unexpected error: " + error->typeName() + ": " + msg;
+ }
+ if (!expectations.empty())
+ {
+ string msg = "Expected error(s) not present:\n";
+ for (auto const& expectation: expectations)
+ msg += expectation.second + "\n";
+ return msg;
+ }
+
+ return "";
+}
diff --git a/test/libsolidity/ErrorCheck.h b/test/libsolidity/ErrorCheck.h
index a309a9d3..8ad81f85 100644
--- a/test/libsolidity/ErrorCheck.h
+++ b/test/libsolidity/ErrorCheck.h
@@ -23,10 +23,17 @@
#include <libsolidity/interface/Exceptions.h>
+#include <vector>
+#include <tuple>
+
namespace dev
{
namespace solidity
{
bool searchErrorMessage(Error const& _err, std::string const& _substr);
+/// Checks that all provided errors are of the given type and have a given substring in their
+/// description.
+/// If the expectations are not met, returns a nonempty description, otherwise an empty string.
+std::string searchErrors(ErrorList const& _errors, std::vector<std::pair<Error::Type, std::string>> const& _expectations);
}
}
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index e9fb8431..b09eb261 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -51,10 +51,11 @@ boost::optional<Error> parseAndReturnFirstError(
string const& _source,
bool _assemble = false,
bool _allowWarnings = true,
+ AssemblyStack::Language _language = AssemblyStack::Language::Assembly,
AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
)
{
- AssemblyStack stack;
+ AssemblyStack stack(_language);
bool success = false;
try
{
@@ -87,22 +88,29 @@ bool successParse(
string const& _source,
bool _assemble = false,
bool _allowWarnings = true,
+ AssemblyStack::Language _language = AssemblyStack::Language::Assembly,
AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
)
{
- return !parseAndReturnFirstError(_source, _assemble, _allowWarnings, _machine);
+ return !parseAndReturnFirstError(_source, _assemble, _allowWarnings, _language, _machine);
}
-bool successAssemble(string const& _source, bool _allowWarnings = true)
+bool successAssemble(string const& _source, bool _allowWarnings = true, AssemblyStack::Language _language = AssemblyStack::Language::Assembly)
{
- return successParse(_source, true, _allowWarnings, AssemblyStack::Machine::EVM) &&
- successParse(_source, true, _allowWarnings, AssemblyStack::Machine::EVM15);
+ return
+ successParse(_source, true, _allowWarnings, _language, AssemblyStack::Machine::EVM) &&
+ successParse(_source, true, _allowWarnings, _language, AssemblyStack::Machine::EVM15);
}
-Error expectError(std::string const& _source, bool _assemble, bool _allowWarnings = false)
+Error expectError(
+ std::string const& _source,
+ bool _assemble,
+ bool _allowWarnings = false,
+ AssemblyStack::Language _language = AssemblyStack::Language::Assembly
+)
{
- auto error = parseAndReturnFirstError(_source, _assemble, _allowWarnings);
+ auto error = parseAndReturnFirstError(_source, _assemble, _allowWarnings, _language);
BOOST_REQUIRE(error);
return *error;
}
@@ -120,14 +128,17 @@ void parsePrintCompare(string const& _source, bool _canWarn = false)
}
-#define CHECK_ERROR(text, assemble, typ, substring, warnings) \
+#define CHECK_ERROR_LANG(text, assemble, typ, substring, warnings, language) \
do \
{ \
- Error err = expectError((text), (assemble), warnings); \
+ Error err = expectError((text), (assemble), warnings, (language)); \
BOOST_CHECK(err.type() == (Error::Type::typ)); \
BOOST_CHECK(searchErrorMessage(err, (substring))); \
} while(0)
+#define CHECK_ERROR(text, assemble, typ, substring, warnings) \
+CHECK_ERROR_LANG(text, assemble, typ, substring, warnings, AssemblyStack::Language::Assembly)
+
#define CHECK_PARSE_ERROR(text, type, substring) \
CHECK_ERROR(text, false, type, substring, false)
@@ -137,6 +148,14 @@ CHECK_ERROR(text, false, type, substring, false)
#define CHECK_ASSEMBLE_ERROR(text, type, substring) \
CHECK_ERROR(text, true, type, substring, false)
+#define CHECK_STRICT_ERROR(text, type, substring) \
+CHECK_ERROR_LANG(text, false, type, substring, false, AssemblyStack::Language::StrictAssembly)
+
+#define CHECK_STRICT_WARNING(text, type, substring) \
+CHECK_ERROR(text, false, type, substring, false, AssemblyStack::Language::StrictAssembly)
+
+#define SUCCESS_STRICT(text) \
+do { successParse((text), false, false, AssemblyStack::Language::StrictAssembly); } while (false)
BOOST_AUTO_TEST_SUITE(SolidityInlineAssembly)
@@ -266,7 +285,7 @@ BOOST_AUTO_TEST_CASE(if_statement_scope)
BOOST_AUTO_TEST_CASE(if_statement_invalid)
{
- CHECK_PARSE_ERROR("{ if calldatasize {}", ParserError, "Instructions are not supported as conditions for if");
+ CHECK_PARSE_ERROR("{ if mload {} }", ParserError, "Expected token \"(\"");
BOOST_CHECK("{ if calldatasize() {}");
CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
CHECK_PARSE_ERROR("{ if 32 let x := 3 }", ParserError, "Expected token LBrace");
@@ -296,7 +315,7 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case)
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
{
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
- CHECK_PARSE_ERROR("{ switch calldatasize default {} }", ParserError, "Instructions are not supported as expressions for switch");
+ CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected token \"(\"");
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
}
@@ -332,7 +351,7 @@ BOOST_AUTO_TEST_CASE(for_invalid_expression)
CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected token LBrace got 'Number'");
CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected token LBrace got 'Number'");
CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected token LBrace got 'Number'");
- CHECK_PARSE_ERROR("{ for {} calldatasize {} {} }", ParserError, "Instructions are not supported as conditions for the for statement.");
+ CHECK_PARSE_ERROR("{ for {} mload {} {} }", ParserError, "Expected token \"(\"");
CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
}
@@ -455,6 +474,47 @@ BOOST_AUTO_TEST_CASE(multiple_assignment)
BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE(LooseStrictMode)
+
+BOOST_AUTO_TEST_CASE(no_opcodes_in_strict)
+{
+ BOOST_CHECK(successParse("{ pop(callvalue) }"));
+ BOOST_CHECK(successParse("{ callvalue pop }"));
+ CHECK_STRICT_ERROR("{ pop(callvalue) }", ParserError, "Non-functional instructions are not allowed in this context.");
+ CHECK_STRICT_ERROR("{ callvalue pop }", ParserError, "Call or assignment expected");
+ SUCCESS_STRICT("{ pop(callvalue()) }");
+ BOOST_CHECK(successParse("{ switch callvalue case 0 {} }"));
+ CHECK_STRICT_ERROR("{ switch callvalue case 0 {} }", ParserError, "Non-functional instructions are not allowed in this context.");
+}
+
+BOOST_AUTO_TEST_CASE(no_labels_in_strict)
+{
+ BOOST_CHECK(successParse("{ a: }"));
+ CHECK_STRICT_ERROR("{ a: }", ParserError, "Labels are not supported");
+}
+
+BOOST_AUTO_TEST_CASE(no_stack_assign_in_strict)
+{
+ BOOST_CHECK(successParse("{ let x 4 =: x }"));
+ CHECK_STRICT_ERROR("{ let x 4 =: x }", ParserError, "Call or assignment expected.");
+}
+
+BOOST_AUTO_TEST_CASE(no_dup_swap_in_strict)
+{
+ BOOST_CHECK(successParse("{ swap1 }"));
+ CHECK_STRICT_ERROR("{ swap1 }", ParserError, "Call or assignment expected.");
+ BOOST_CHECK(successParse("{ dup1 pop }"));
+ CHECK_STRICT_ERROR("{ dup1 pop }", ParserError, "Call or assignment expected.");
+ BOOST_CHECK(successParse("{ swap2 }"));
+ CHECK_STRICT_ERROR("{ swap2 }", ParserError, "Call or assignment expected.");
+ BOOST_CHECK(successParse("{ dup2 pop }"));
+ CHECK_STRICT_ERROR("{ dup2 pop }", ParserError, "Call or assignment expected.");
+ CHECK_PARSE_ERROR("{ switch dup1 case 0 {} }", ParserError, "Instruction \"dup1\" not allowed in this context");
+ CHECK_STRICT_ERROR("{ switch dup1 case 0 {} }", ParserError, "Instruction \"dup1\" not allowed in this context");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
BOOST_AUTO_TEST_SUITE(Printing)
BOOST_AUTO_TEST_CASE(print_smoke)
@@ -540,7 +600,7 @@ BOOST_AUTO_TEST_CASE(function_calls)
function g(a, b, c)
{
}
- g(1, mul(2, address), f(mul(2, caller)))
+ g(1, mul(2, address()), f(mul(2, caller())))
y()
})";
boost::replace_all(source, "\t", " ");
@@ -712,8 +772,9 @@ BOOST_AUTO_TEST_CASE(jump_warning)
{
CHECK_PARSE_WARNING("{ 1 jump }", Warning, "Jump instructions");
CHECK_PARSE_WARNING("{ 1 2 jumpi }", Warning, "Jump instructions");
- CHECK_PARSE_WARNING("{ a: jump(a) }", Warning, "Jump instructions");
- CHECK_PARSE_WARNING("{ a: jumpi(a, 2) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ jump(44) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ jumpi(44, 2) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ a: }", Warning, "Jump instructions");
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp
index 7dc4808b..0c904c77 100644
--- a/test/libsolidity/JSONCompiler.cpp
+++ b/test/libsolidity/JSONCompiler.cpp
@@ -23,7 +23,7 @@
#include <boost/test/unit_test.hpp>
#include <libdevcore/JSON.h>
#include <libsolidity/interface/Version.h>
-#include <solc/jsonCompiler.h>
+#include <libsolc/libsolc.h>
#include "../Metadata.h"
#include "../TestHelper.h"
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index 667d666b..8c955292 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -42,7 +42,7 @@ public:
}
protected:
- virtual std::pair<SourceUnit const*, std::shared_ptr<Error const>>
+ virtual std::pair<SourceUnit const*, ErrorList>
parseAnalyseAndReturnError(
std::string const& _source,
bool _reportWarnings = false,
@@ -94,6 +94,7 @@ BOOST_AUTO_TEST_CASE(warn_on_typecast)
BOOST_AUTO_TEST_CASE(warn_on_struct)
{
string text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct A { uint a; uint b; }
function f() public pure returns (A) {
@@ -101,8 +102,10 @@ BOOST_AUTO_TEST_CASE(warn_on_struct)
}
}
)";
- /// Multiple warnings, should check for: Assertion checker does not yet implement this expression.
- CHECK_WARNING_ALLOW_MULTI(text, "");
+ CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
+ "Assertion checker does not yet implement this expression.",
+ "Assertion checker does not yet support the type of this variable."
+ }));
}
BOOST_AUTO_TEST_CASE(simple_assert)
@@ -167,9 +170,9 @@ BOOST_AUTO_TEST_CASE(function_call_does_not_clear_local_vars)
CHECK_SUCCESS_NO_WARNINGS(text);
}
-BOOST_AUTO_TEST_CASE(branches_clear_variables)
+BOOST_AUTO_TEST_CASE(branches_merge_variables)
{
- // Only clears accessed variables
+ // Branch does not touch variable a
string text = R"(
contract C {
function f(uint x) public pure {
@@ -181,7 +184,7 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
- // It is just a plain clear and will not combine branches.
+ // Positive branch touches variable a, but assertion should still hold.
text = R"(
contract C {
function f(uint x) public pure {
@@ -193,8 +196,8 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
}
)";
- CHECK_WARNING(text, "Assertion violation happens here");
- // Clear also works on the else branch
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Negative branch touches variable a, but assertion should still hold.
text = R"(
contract C {
function f(uint x) public pure {
@@ -207,8 +210,8 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
}
)";
- CHECK_WARNING(text, "Assertion violation happens here");
- // Variable is not cleared, if it is only read.
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Variable is not merged, if it is only read.
text = R"(
contract C {
function f(uint x) public pure {
@@ -223,6 +226,36 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
+ // Variable is reset in both branches
+ text = R"(
+ contract C {
+ function f(uint x) public pure {
+ uint a = 2;
+ if (x > 10) {
+ a = 3;
+ } else {
+ a = 3;
+ }
+ assert(a == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Variable is reset in both branches
+ text = R"(
+ contract C {
+ function f(uint x) public pure {
+ uint a = 2;
+ if (x > 10) {
+ a = 3;
+ } else {
+ a = 4;
+ }
+ assert(a >= 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
}
BOOST_AUTO_TEST_CASE(branches_assert_condition)
@@ -261,7 +294,7 @@ BOOST_AUTO_TEST_CASE(branches_assert_condition)
CHECK_SUCCESS_NO_WARNINGS(text);
}
-BOOST_AUTO_TEST_CASE(ways_to_clear_variables)
+BOOST_AUTO_TEST_CASE(ways_to_merge_variables)
{
string text = R"(
contract C {
@@ -274,6 +307,7 @@ BOOST_AUTO_TEST_CASE(ways_to_clear_variables)
}
}
)";
+ CHECK_WARNING(text, "Assertion violation happens here");
text = R"(
contract C {
function f(uint x) public pure {
@@ -351,9 +385,9 @@ BOOST_AUTO_TEST_CASE(while_loop_simple)
// Check that side-effects of condition are taken into account
text = R"(
contract C {
- function f(uint x) public pure {
+ function f(uint x, uint y) public pure {
x = 7;
- while ((x = 5) > 0) {
+ while ((x = y) > 0) {
}
assert(x == 7);
}
@@ -458,6 +492,100 @@ BOOST_AUTO_TEST_CASE(for_loop)
CHECK_WARNING(text, "Assertion violation");
}
+BOOST_AUTO_TEST_CASE(division)
+{
+ string text = R"(
+ contract C {
+ function f(uint x, uint y) public pure returns (uint) {
+ return x / y;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Division by zero");
+ text = R"(
+ contract C {
+ function f(uint x, uint y) public pure returns (uint) {
+ require(y != 0);
+ return x / y;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure returns (int) {
+ require(y != 0);
+ return x / y;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Overflow");
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure returns (int) {
+ require(y != 0);
+ require(y != -1);
+ return x / y;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(division_truncates_correctly)
+{
+ string text = R"(
+ contract C {
+ function f(uint x, uint y) public pure {
+ x = 7;
+ y = 2;
+ assert(x / y == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = 7;
+ y = 2;
+ assert(x / y == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = -7;
+ y = 2;
+ assert(x / y == -3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = 7;
+ y = -2;
+ assert(x / y == -3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = -7;
+ y = -2;
+ assert(x / y == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 33962730..26bfb6d0 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -942,6 +942,7 @@ BOOST_AUTO_TEST_CASE(function_type)
BOOST_AUTO_TEST_CASE(return_structs)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct S { uint a; T[] sub; }
struct T { uint[2] x; }
@@ -991,6 +992,7 @@ BOOST_AUTO_TEST_CASE(return_structs)
BOOST_AUTO_TEST_CASE(return_structs_with_contracts)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct S { C[] x; C y; }
function f() returns (S s, C c) {
@@ -1090,6 +1092,7 @@ BOOST_AUTO_TEST_CASE(event_structs)
BOOST_AUTO_TEST_CASE(structs_in_libraries)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
library L {
struct S { uint a; T[] sub; bytes b; }
struct T { uint[2] x; }
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 05dc9ba3..0611e71d 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2971,7 +2971,7 @@ BOOST_AUTO_TEST_CASE(event_no_arguments)
{
char const* sourceCode = R"(
contract ClientReceipt {
- event Deposit;
+ event Deposit();
function deposit() {
Deposit();
}
@@ -3013,7 +3013,7 @@ BOOST_AUTO_TEST_CASE(events_with_same_name)
{
char const* sourceCode = R"(
contract ClientReceipt {
- event Deposit;
+ event Deposit();
event Deposit(address _addr);
event Deposit(address _addr, uint _amount);
function deposit() returns (uint) {
@@ -3059,7 +3059,7 @@ BOOST_AUTO_TEST_CASE(events_with_same_name_inherited)
{
char const* sourceCode = R"(
contract A {
- event Deposit;
+ event Deposit();
}
contract B {
@@ -3543,6 +3543,39 @@ BOOST_AUTO_TEST_CASE(library_call_in_homestead)
ABI_CHECK(callContractFunction("sender()"), encodeArgs(u160(m_sender)));
}
+BOOST_AUTO_TEST_CASE(library_call_protection)
+{
+ // This tests code that reverts a call if it is a direct call to a library
+ // as opposed to a delegatecall.
+ char const* sourceCode = R"(
+ library Lib {
+ struct S { uint x; }
+ // a direct call to this should revert
+ function np(S storage s) public returns (address) { s.x = 3; return msg.sender; }
+ // a direct call to this is fine
+ function v(S storage) public view returns (address) { return msg.sender; }
+ // a direct call to this is fine
+ function pu() public pure returns (uint) { return 2; }
+ }
+ contract Test {
+ Lib.S public s;
+ function np() public returns (address) { return Lib.np(s); }
+ function v() public view returns (address) { return Lib.v(s); }
+ function pu() public pure returns (uint) { return Lib.pu(); }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "Lib");
+ ABI_CHECK(callContractFunction("np(Lib.S storage)"), encodeArgs());
+ ABI_CHECK(callContractFunction("v(Lib.S storage)"), encodeArgs(u160(m_sender)));
+ ABI_CHECK(callContractFunction("pu()"), encodeArgs(2));
+ compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
+ ABI_CHECK(callContractFunction("s()"), encodeArgs(0));
+ ABI_CHECK(callContractFunction("np()"), encodeArgs(u160(m_sender)));
+ ABI_CHECK(callContractFunction("s()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("v()"), encodeArgs(u160(m_sender)));
+ ABI_CHECK(callContractFunction("pu()"), encodeArgs(2));
+}
+
BOOST_AUTO_TEST_CASE(store_bytes)
{
// this test just checks that the copy loop does not mess up the stack
@@ -10186,24 +10219,29 @@ BOOST_AUTO_TEST_CASE(function_types_sig)
{
char const* sourceCode = R"(
contract C {
- function f() returns (bytes4) {
+ uint public x;
+ function f() pure returns (bytes4) {
return this.f.selector;
}
function g() returns (bytes4) {
- function () external returns (bytes4) fun = this.f;
+ function () pure external returns (bytes4) fun = this.f;
return fun.selector;
}
function h() returns (bytes4) {
- function () external returns (bytes4) fun = this.f;
+ function () pure external returns (bytes4) fun = this.f;
var funvar = fun;
return funvar.selector;
}
+ function i() pure returns (bytes4) {
+ return this.x.selector;
+ }
}
)";
compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("f()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
ABI_CHECK(callContractFunction("g()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
ABI_CHECK(callContractFunction("h()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
+ ABI_CHECK(callContractFunction("i()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("x()")).asBytes())));
}
BOOST_AUTO_TEST_CASE(constant_string)
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 97d359e8..315c7c5f 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -122,6 +122,20 @@ BOOST_AUTO_TEST_CASE(undeclared_name)
CHECK_ERROR(text, DeclarationError, "Undeclared identifier.");
}
+BOOST_AUTO_TEST_CASE(undeclared_name_is_not_fatal)
+{
+ char const* text = R"(
+ contract test {
+ uint256 variable;
+ function f(uint256 arg) public {
+ f(notfound);
+ f(notfound);
+ }
+ }
+ )";
+ CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, (vector<string>{"Undeclared identifier", "Undeclared identifier"}));
+}
+
BOOST_AUTO_TEST_CASE(reference_to_later_declaration)
{
char const* text = R"(
@@ -602,6 +616,7 @@ BOOST_AUTO_TEST_CASE(enum_external_type)
BOOST_AUTO_TEST_CASE(external_structs)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract Test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
struct Empty {}
@@ -629,6 +644,7 @@ BOOST_AUTO_TEST_CASE(external_structs)
BOOST_AUTO_TEST_CASE(external_structs_in_libraries)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
library Test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
struct Empty {}
@@ -848,7 +864,7 @@ BOOST_AUTO_TEST_CASE(cyclic_inheritance)
contract A is B { }
contract B is A { }
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Definition of base has to precede definition of derived contract");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (vector<string>{"Definition of base has to precede definition of derived contract"}));
}
BOOST_AUTO_TEST_CASE(legal_override_direct)
@@ -1076,9 +1092,10 @@ BOOST_AUTO_TEST_CASE(modifier_overrides_function)
contract A { modifier mod(uint a) { _; } }
contract B is A { function mod(uint a) public { } }
)";
- // Error: Identifier already declared.
- // Error: Override changes modifier to function.
- CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, "Identifier already declared.");
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, string>>{
+ {Error::Type::DeclarationError, "Identifier already declared"},
+ {Error::Type::TypeError, "Override changes modifier to function"}
+ }));
}
BOOST_AUTO_TEST_CASE(function_overrides_modifier)
@@ -1087,9 +1104,10 @@ BOOST_AUTO_TEST_CASE(function_overrides_modifier)
contract A { function mod(uint a) public { } }
contract B is A { modifier mod(uint a) { _; } }
)";
- // Error: Identifier already declared.
- // Error: Override changes function to modifier.
- CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, "Identifier already declared.");
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, string>>{
+ {Error::Type::DeclarationError, "Identifier already declared"},
+ {Error::Type::TypeError, "Override changes function to modifier"}
+ }));
}
BOOST_AUTO_TEST_CASE(modifier_returns_value)
@@ -1326,7 +1344,10 @@ BOOST_AUTO_TEST_CASE(fallback_function_twice)
function() public { x = 3; }
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, "Function with same name and arguments defined twice.");
+ CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, (vector<string>{
+ "Function with same name and arguments defined twice.",
+ "Only one fallback function is"
+ }));
}
BOOST_AUTO_TEST_CASE(fallback_function_inheritance)
@@ -1661,7 +1682,11 @@ BOOST_AUTO_TEST_CASE(constant_input_parameter)
function f(uint[] constant a) public { }
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Illegal use of \"constant\" specifier.");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (vector<string>{
+ "Illegal use of \"constant\" specifier",
+ "Constants of non-value type not yet implemented",
+ "Uninitialized \"constant\" variable"
+ }));
}
BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
@@ -1727,7 +1752,7 @@ BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
uint256 a;
}
)";
- CHECK_ERROR(sourceCode, TypeError, "Type int_const 115792089237316195423570985008687907853269984665640564039458000000000000000000 is not implicitly convertible to expected type uint256.");
+ CHECK_ERROR(sourceCode, TypeError, "Type int_const 1157...(70 digits omitted)...0000 is not implicitly convertible to expected type uint256.");
}
BOOST_AUTO_TEST_CASE(exp_operator_exponent_too_big)
@@ -1819,7 +1844,10 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero)
}
}
)";
- CHECK_WARNING(sourceCode, "uint8, which can hold values between 0 and 255");
+ CHECK_WARNING_ALLOW_MULTI(sourceCode, (std::vector<std::string>{
+ "uint8, which can hold values between 0 and 255",
+ "Use of the \"var\" keyword is deprecated."
+ }));
sourceCode = R"(
contract test {
function f() pure public {
@@ -1828,7 +1856,10 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero)
}
}
)";
- CHECK_WARNING(sourceCode, "uint256, which can hold values between 0 and 115792089237316195423570985008687907853269984665640564039457584007913129639935");
+ CHECK_WARNING_ALLOW_MULTI(sourceCode, (std::vector<std::string>{
+ "uint256, which can hold values between 0 and 115792089237316195423570985008687907853269984665640564039457584007913129639935",
+ "Use of the \"var\" keyword is deprecated."
+ }));
sourceCode = R"(
contract test {
function f() pure public {
@@ -1837,7 +1868,10 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero)
}
}
)";
- CHECK_WARNING(sourceCode, "int8, which can hold values between -128 and 127");
+ CHECK_WARNING_ALLOW_MULTI(sourceCode, (std::vector<std::string>{
+ "int8, which can hold values between -128 and 127",
+ "Use of the \"var\" keyword is deprecated."
+ }));
sourceCode = R"(
contract test {
function f() pure public {
@@ -1845,7 +1879,10 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero)
}
}
)";
- CHECK_WARNING(sourceCode, "uint8, which can hold");
+ CHECK_WARNING_ALLOW_MULTI(sourceCode, (std::vector<std::string>{
+ "uint8, which can hold",
+ "Use of the \"var\" keyword is deprecated."
+ }));
}
BOOST_AUTO_TEST_CASE(enum_member_access)
@@ -2044,6 +2081,93 @@ BOOST_AUTO_TEST_CASE(external_visibility)
CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier.");
}
+BOOST_AUTO_TEST_CASE(similar_name_suggestions_expected)
+{
+ char const* sourceCode = R"(
+ contract c {
+ function func() {}
+ function g() public { fun(); }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier. Did you mean \"func\"?");
+}
+
+BOOST_AUTO_TEST_CASE(no_name_suggestion)
+{
+ char const* sourceCode = R"(
+ contract c {
+ function g() public { fun(); }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier.");
+}
+
+BOOST_AUTO_TEST_CASE(multiple_similar_suggestions)
+{
+ char const* sourceCode = R"(
+ contract c {
+ function g() public {
+ uint var1 = 1;
+ uint var2 = 1;
+ uint var3 = 1;
+ uint var4 = 1;
+ uint var5 = varx;
+ }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier. Did you mean \"var1\", \"var2\", \"var3\", \"var4\" or \"var5\"?");
+}
+
+BOOST_AUTO_TEST_CASE(multiple_scopes_suggestions)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint log9 = 2;
+ function g() public {
+ uint log8 = 3;
+ uint var1 = lgox;
+ }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier. Did you mean \"log8\", \"log9\", \"log0\", \"log1\", \"log2\", \"log3\" or \"log4\"?");
+}
+
+BOOST_AUTO_TEST_CASE(inheritence_suggestions)
+{
+ char const* sourceCode = R"(
+ contract a { function func() public {} }
+ contract c is a {
+ function g() public {
+ uint var1 = fun();
+ }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier. Did you mean \"func\"?");
+}
+
+BOOST_AUTO_TEST_CASE(no_spurious_suggestions)
+{
+ char const* sourceCode = R"(
+ contract c {
+ function g() public {
+ uint va = 1;
+ uint vb = vaxyz;
+ }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier.");
+
+ sourceCode = R"(
+ contract c {
+ function g() public {
+ uint va = 1;
+ uint vb = x;
+ }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Undeclared identifier.");
+}
+
BOOST_AUTO_TEST_CASE(external_base_visibility)
{
char const* sourceCode = R"(
@@ -2107,7 +2231,7 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
function f(uint a) public { uint8[a] x; }
}
)";
- CHECK_ERROR(text, TypeError, "Identifier must be declared constant.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_with_negative_length)
@@ -2180,6 +2304,16 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
CHECK_ERROR(text, TypeError, "Type uint256[] storage ref is not implicitly convertible to expected type uint256[80] storage ref.");
}
+BOOST_AUTO_TEST_CASE(array_of_undeclared_type)
+{
+ char const* text = R"(
+ contract c {
+ a[] public foo;
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Identifier not found or not unique.");
+}
+
BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_int)
{
char const* text = R"(
@@ -2600,7 +2734,10 @@ BOOST_AUTO_TEST_CASE(equal_overload)
function test(uint a) external {}
}
)";
- CHECK_ERROR_ALLOW_MULTI(sourceCode, DeclarationError, "Function with same name and arguments defined twice.");
+ CHECK_ALLOW_MULTI(sourceCode, (vector<pair<Error::Type, string>>{
+ {Error::Type::DeclarationError, "Function with same name and arguments defined twice."},
+ {Error::Type::TypeError, "Overriding function visibility differs"}
+ }));
}
BOOST_AUTO_TEST_CASE(uninitialized_var)
@@ -3102,7 +3239,10 @@ BOOST_AUTO_TEST_CASE(library_constructor)
function Lib();
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Constructor cannot be defined in libraries.");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (vector<std::string>{
+ "Constructor cannot be defined in libraries.",
+ "Constructor must be implemented if declared."
+ }));
}
BOOST_AUTO_TEST_CASE(valid_library)
@@ -3511,6 +3651,7 @@ BOOST_AUTO_TEST_CASE(using_for_not_used)
BOOST_AUTO_TEST_CASE(library_memory_struct)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
library c {
struct S { uint x; }
function f() public returns (S ) {}
@@ -3605,6 +3746,20 @@ BOOST_AUTO_TEST_CASE(invalid_args_creating_memory_array)
CHECK_ERROR(text, TypeError, "Wrong argument count for function call: 0 arguments given but expected 1.");
}
+BOOST_AUTO_TEST_CASE(invalid_args_creating_struct)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+
+ function f() public {
+ var s = S({a: 1});
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Wrong argument count for struct constructor: 1 arguments given but expected 2.");
+}
+
BOOST_AUTO_TEST_CASE(function_overload_array_type)
{
char const* text = R"(
@@ -3814,7 +3969,10 @@ BOOST_AUTO_TEST_CASE(left_value_in_conditional_expression_not_supported_yet)
}
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Conditional expression as left value is not supported yet.");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{
+ "Conditional expression as left value is not supported yet.",
+ "Expression has to be an lvalue"
+ }));
}
BOOST_AUTO_TEST_CASE(conditional_expression_with_different_struct)
@@ -4033,7 +4191,11 @@ BOOST_AUTO_TEST_CASE(varM_disqualified_as_keyword)
}
}
)";
- CHECK_ERROR(text, DeclarationError, "Identifier not found or not unique.");
+ CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, (std::vector<std::string>{
+ "Identifier not found or not unique.",
+ "Identifier not found or not unique.",
+ "Identifier not found or not unique."
+ }));
}
BOOST_AUTO_TEST_CASE(modifier_is_not_a_valid_typename)
@@ -4050,6 +4212,21 @@ BOOST_AUTO_TEST_CASE(modifier_is_not_a_valid_typename)
CHECK_ERROR(text, TypeError, "Name has to refer to a struct, enum or contract.");
}
+BOOST_AUTO_TEST_CASE(modifier_is_not_a_valid_typename_is_not_fatal)
+{
+ char const* text = R"(
+ contract test {
+ modifier mod() { _; }
+
+ function f() public {
+ mod g;
+ g = f;
+ }
+ }
+ )";
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{"Name has to refer to a struct, enum or contract."}));
+}
+
BOOST_AUTO_TEST_CASE(function_is_not_a_valid_typename)
{
char const* text = R"(
@@ -4395,7 +4572,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
@@ -4407,7 +4584,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion)
@@ -4496,7 +4673,7 @@ BOOST_AUTO_TEST_CASE(rational_index_access)
}
}
)";
- CHECK_ERROR(text, TypeError, "rational_const 1/2 is not implicitly convertible to expected type uint256");
+ CHECK_ERROR(text, TypeError, "rational_const 1 / 2 is not implicitly convertible to expected type uint256");
}
BOOST_AUTO_TEST_CASE(rational_to_fixed_literal_expression)
@@ -4786,7 +4963,10 @@ BOOST_AUTO_TEST_CASE(unused_return_value_callcode)
}
}
)";
- CHECK_WARNING_ALLOW_MULTI(text, "Return value of low-level calls not used");
+ CHECK_WARNING_ALLOW_MULTI(text, (std::vector<std::string>{
+ "Return value of low-level calls not used",
+ "\"callcode\" has been deprecated"
+ }));
}
BOOST_AUTO_TEST_CASE(unused_return_value_delegatecall)
@@ -4806,8 +4986,7 @@ BOOST_AUTO_TEST_CASE(warn_about_callcode)
char const* text = R"(
contract test {
function f() pure public {
- var x = address(0x12).callcode;
- x;
+ address(0x12).callcode;
}
}
)";
@@ -4816,8 +4995,7 @@ BOOST_AUTO_TEST_CASE(warn_about_callcode)
pragma experimental "v0.5.0";
contract test {
function f() pure public {
- var x = address(0x12).callcode;
- x;
+ address(0x12).callcode;
}
}
)";
@@ -4966,9 +5144,9 @@ BOOST_AUTO_TEST_CASE(warn_nonpresent_pragma)
{
char const* text = "contract C {}";
auto sourceAndError = parseAnalyseAndReturnError(text, true, false);
- BOOST_REQUIRE(!!sourceAndError.second);
+ BOOST_REQUIRE(!sourceAndError.second.empty());
BOOST_REQUIRE(!!sourceAndError.first);
- BOOST_CHECK(searchErrorMessage(*sourceAndError.second, "Source file does not specify required compiler version!"));
+ BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file does not specify required compiler version!"));
}
BOOST_AUTO_TEST_CASE(unsatisfied_version)
@@ -4977,10 +5155,10 @@ BOOST_AUTO_TEST_CASE(unsatisfied_version)
pragma solidity ^99.99.0;
)";
auto sourceAndError = parseAnalyseAndReturnError(text, false, false, false);
- BOOST_REQUIRE(!!sourceAndError.second);
+ BOOST_REQUIRE(!sourceAndError.second.empty());
BOOST_REQUIRE(!!sourceAndError.first);
- BOOST_CHECK(sourceAndError.second->type() == Error::Type::SyntaxError);
- BOOST_CHECK(searchErrorMessage(*sourceAndError.second, "Source file requires different compiler version"));
+ BOOST_CHECK(sourceAndError.second.front()->type() == Error::Type::SyntaxError);
+ BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file requires different compiler version"));
}
BOOST_AUTO_TEST_CASE(invalid_constructor_statemutability)
@@ -5115,6 +5293,20 @@ BOOST_AUTO_TEST_CASE(payable_internal_function_type)
CHECK_ERROR(text, TypeError, "Only external function types can be payable.");
}
+BOOST_AUTO_TEST_CASE(payable_internal_function_type_is_not_fatal)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) internal payable returns (uint) x;
+
+ function g() {
+ x = g;
+ }
+ }
+ )";
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{"Only external function types can be payable."}));
+}
+
BOOST_AUTO_TEST_CASE(call_value_on_non_payable_function_type)
{
char const* text = R"(
@@ -5696,6 +5888,7 @@ BOOST_AUTO_TEST_CASE(constructible_internal_constructor)
BOOST_AUTO_TEST_CASE(return_structs)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct S { uint a; T[] sub; }
struct T { uint[] x; }
@@ -5805,7 +5998,10 @@ BOOST_AUTO_TEST_CASE(invalid_address_length_long)
}
}
)";
- CHECK_WARNING_ALLOW_MULTI(text, "This looks like an address but has an invalid checksum.");
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "This looks like an address but has an invalid checksum."},
+ {Error::Type::TypeError, "not implicitly convertible"}
+ }));
}
BOOST_AUTO_TEST_CASE(address_test_for_bug_in_implementation)
@@ -5878,7 +6074,11 @@ BOOST_AUTO_TEST_CASE(cyclic_dependency_for_constants)
uint constant d = 2 + a;
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "a has a cyclic dependency via c");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{
+ "a has a cyclic dependency via c",
+ "c has a cyclic dependency via d",
+ "d has a cyclic dependency via a"
+ }));
text = R"(
contract C {
uint constant a = b * c;
@@ -5906,7 +6106,10 @@ BOOST_AUTO_TEST_CASE(interface_constructor)
function I();
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Constructor cannot be defined in interfaces");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{
+ "Constructor cannot be defined in interfaces",
+ "Constructor must be implemented if declared.",
+ }));
}
BOOST_AUTO_TEST_CASE(interface_functions)
@@ -5945,6 +6148,12 @@ BOOST_AUTO_TEST_CASE(interface_function_external)
BOOST_AUTO_TEST_CASE(interface_function_public)
{
char const* text = R"(
+ interface I {
+ function f() public;
+ }
+ )";
+ CHECK_WARNING(text, "Functions in interfaces should be declared external.");
+ text = R"(
pragma experimental "v0.5.0";
interface I {
function f() public;
@@ -6288,7 +6497,7 @@ BOOST_AUTO_TEST_CASE(no_unused_warning_interface_arguments)
{
char const* text = R"(
interface I {
- function f(uint a) pure public returns (uint b);
+ function f(uint a) pure external returns (uint b);
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
@@ -6583,15 +6792,23 @@ BOOST_AUTO_TEST_CASE(returndatacopy_as_variable)
char const* text = R"(
contract c { function f() public { uint returndatasize; assembly { returndatasize }}}
)";
- CHECK_WARNING_ALLOW_MULTI(text, "Variable is shadowed in inline assembly by an instruction of the same name");
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"},
+ {Error::Type::DeclarationError, "Unbalanced stack"},
+ {Error::Type::Warning, "only available after the Metropolis"}
+ }));
}
BOOST_AUTO_TEST_CASE(create2_as_variable)
{
char const* text = R"(
- contract c { function f() public { uint create2; assembly { create2(0, 0, 0, 0) }}}
+ contract c { function f() public { uint create2; assembly { create2(0, 0, 0, 0) } }}
)";
- CHECK_WARNING_ALLOW_MULTI(text, "Variable is shadowed in inline assembly by an instruction of the same name");
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"},
+ {Error::Type::Warning, "only available after the Metropolis"},
+ {Error::Type::DeclarationError, "Unbalanced stack"}
+ }));
}
BOOST_AUTO_TEST_CASE(warn_unspecified_storage)
@@ -6632,6 +6849,28 @@ BOOST_AUTO_TEST_CASE(warn_unspecified_storage)
CHECK_ERROR(text, TypeError, "Storage location must be specified as either \"memory\" or \"storage\".");
}
+BOOST_AUTO_TEST_CASE(storage_location_non_array_or_struct_disallowed)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint storage a) public { }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Storage location can only be given for array or struct types.");
+}
+
+BOOST_AUTO_TEST_CASE(storage_location_non_array_or_struct_disallowed_is_not_fatal)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint storage a) public {
+ a = f;
+ }
+ }
+ )";
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{"Storage location can only be given for array or struct types."}));
+}
+
BOOST_AUTO_TEST_CASE(implicit_conversion_disallowed)
{
char const* text = R"(
@@ -6752,15 +6991,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig)
CHECK_ERROR(text, TypeError, "Member \"selector\" not found");
text = R"(
contract C {
- function f() view external returns (bytes4) {
- return this.f.selector;
- }
- }
- )";
- CHECK_SUCCESS_NO_WARNINGS(text);
- text = R"(
- contract C {
- function f() view external returns (bytes4) {
+ function f() pure external returns (bytes4) {
return this.f.selector;
}
}
@@ -6776,7 +7007,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig)
}
}
)";
- CHECK_SUCCESS_NO_WARNINGS(text);
+ CHECK_WARNING(text, "Use of the \"var\" keyword is deprecated.");
text = R"(
contract C {
function h() pure external {
@@ -6799,7 +7030,7 @@ BOOST_AUTO_TEST_CASE(function_types_sig)
}
}
)";
- CHECK_SUCCESS_NO_WARNINGS(text);
+ CHECK_WARNING(text, "Use of the \"var\" keyword is deprecated.");
}
BOOST_AUTO_TEST_CASE(using_this_in_constructor)
@@ -6827,7 +7058,11 @@ BOOST_AUTO_TEST_CASE(do_not_crash_on_not_lvalue)
}
}
)";
- CHECK_ERROR_ALLOW_MULTI(text, TypeError, "is not callable");
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{
+ "is not callable",
+ "Expression has to be an lvalue",
+ "Type int_const 2 is not implicitly"
+ }));
}
BOOST_AUTO_TEST_CASE(builtin_reject_gas)
@@ -7030,11 +7265,11 @@ BOOST_AUTO_TEST_CASE(experimental_pragma)
pragma experimental __test;
)";
CHECK_WARNING(text, "Experimental features are turned on. Do not use experimental features on live deployments.");
-// text = R"(
-// pragma experimental __test;
-// pragma experimental __test;
-// )";
-// CHECK_ERROR_ALLOW_MULTI(text, SyntaxError, "Duplicate experimental feature name.");
+ text = R"(
+ pragma experimental __test;
+ pragma experimental __test;
+ )";
+ CHECK_ERROR_ALLOW_MULTI(text, SyntaxError, (std::vector<std::string>{"Duplicate experimental feature name."}));
}
BOOST_AUTO_TEST_CASE(reject_interface_creation)
@@ -7097,7 +7332,10 @@ BOOST_AUTO_TEST_CASE(tight_packing_literals)
}
}
)";
-// CHECK_WARNING(text, "The type of \"int_const 1\" was inferred as uint8.");
+ CHECK_WARNING_ALLOW_MULTI(text, (std::vector<std::string>{
+ "The type of \"int_const 1\" was inferred as uint8.",
+ "\"sha3\" has been deprecated in favour of \"keccak256\""
+ }));
text = R"(
contract C {
function f() pure public returns (bytes32) {
@@ -7200,7 +7438,7 @@ BOOST_AUTO_TEST_CASE(warn_about_sha3)
char const* text = R"(
contract test {
function f() pure public {
- var x = sha3(uint8(1));
+ bytes32 x = sha3(uint8(1));
x;
}
}
@@ -7250,7 +7488,7 @@ BOOST_AUTO_TEST_CASE(array_length_too_large)
uint[8**90] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
@@ -7260,7 +7498,7 @@ BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
uint[true] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_constant_var)
@@ -7282,7 +7520,7 @@ BOOST_AUTO_TEST_CASE(array_length_non_integer_constant_var)
uint[LEN] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
@@ -7293,7 +7531,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
uint[f] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_can_be_recursive_constant)
@@ -7317,7 +7555,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_function_call)
uint[LEN] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_const_cannot_be_fractional)
@@ -7366,7 +7604,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_constant_function_parameter)
}
}
)";
- CHECK_ERROR(text, TypeError, "Constant identifier declaration must have a constant value.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_with_cyclic_constant)
@@ -7405,7 +7643,7 @@ BOOST_AUTO_TEST_CASE(array_length_with_pure_functions)
uint[LEN] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
@@ -7415,25 +7653,25 @@ BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
uint[-true] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[true/1] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[1/true] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[1.111111E1111111111111] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid literal value.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[3/0] ids;
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 72473c3e..861e6408 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -960,6 +960,16 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
BOOST_CHECK(successParse(text));
}
+BOOST_AUTO_TEST_CASE(event_with_no_argument_list_fails)
+{
+ char const* text = R"(
+ contract c {
+ event e;
+ }
+ )";
+ CHECK_PARSE_ERROR(text, "Expected token LParen got 'Semicolon'");
+}
+
BOOST_AUTO_TEST_CASE(visibility_specifiers)
{
char const* text = R"(
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 091207e8..e48624e5 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -234,6 +234,46 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
);
}
+BOOST_AUTO_TEST_CASE(compilation_error)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { function }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(result.isMember("errors"));
+ BOOST_CHECK(result["errors"].size() >= 1);
+ for (auto const& error: result["errors"])
+ {
+ BOOST_REQUIRE(error.isObject());
+ BOOST_REQUIRE(error["message"].isString());
+ if (error["message"].asString().find("pre-release compiler") == string::npos)
+ {
+ BOOST_CHECK_EQUAL(
+ dev::jsonCompactPrint(error),
+ "{\"component\":\"general\",\"formattedMessage\":\"fileA:1:23: ParserError: Expected identifier, got 'RBrace'\\n"
+ "contract A { function }\\n ^\\n\",\"message\":\"Expected identifier, got 'RBrace'\","
+ "\"severity\":\"error\",\"sourceLocation\":{\"end\":22,\"file\":\"fileA\",\"start\":22},\"type\":\"ParserError\"}"
+ );
+ }
+ }
+}
+
BOOST_AUTO_TEST_CASE(output_selection_explicit)
{
char const* input = R"(
@@ -411,6 +451,71 @@ BOOST_AUTO_TEST_CASE(output_selection_dependent_contract_with_import)
BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[{\"constant\":false,\"inputs\":[],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]");
}
+BOOST_AUTO_TEST_CASE(filename_with_colon)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "http://github.com/ethereum/solidity/std/StandardToken.sol": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "http://github.com/ethereum/solidity/std/StandardToken.sol": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "http://github.com/ethereum/solidity/std/StandardToken.sol", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(library_filename_with_colon)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "evm.bytecode"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "import \"git:library.sol\"; contract A { function f() returns (uint) { return L.g(); } }"
+ },
+ "git:library.sol": {
+ "content": "library L { function g() returns (uint) { return 1; } }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"].isArray());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"][0].isObject());
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
index 6353ae8a..3a03c877 100644
--- a/test/libsolidity/ViewPureChecker.cpp
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -136,10 +136,12 @@ BOOST_AUTO_TEST_CASE(environment_access)
}
for (string const& x: pure)
{
- CHECK_WARNING(
+ CHECK_WARNING_ALLOW_MULTI(
"contract C { function f() view public { var x = " + x + "; x; } }",
- "restricted to pure"
- );
+ (std::vector<std::string>{
+ "Function state mutability can be restricted to pure",
+ "Use of the \"var\" keyword is deprecated."
+ }));
}
}
@@ -181,10 +183,10 @@ BOOST_AUTO_TEST_CASE(interface)
{
string text = R"(
interface D {
- function f() view public;
+ function f() view external;
}
contract C is D {
- function f() view public {}
+ function f() view external {}
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
@@ -282,9 +284,9 @@ BOOST_AUTO_TEST_CASE(builtin_functions)
require(this.call());
}
function g() pure public {
- var x = keccak256("abc");
- var y = sha256("abc");
- var z = ecrecover(1, 2, 3, 4);
+ bytes32 x = keccak256("abc");
+ bytes32 y = sha256("abc");
+ address z = ecrecover(1, 2, 3, 4);
require(true);
assert(true);
x; y; z;
@@ -324,6 +326,53 @@ BOOST_AUTO_TEST_CASE(function_types)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(selector)
+{
+ string text = R"(
+ contract C {
+ uint public x;
+ function f() payable public {
+ }
+ function g() pure public returns (bytes4) {
+ return this.f.selector ^ this.x.selector;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(selector_complex)
+{
+ string text = R"(
+ contract C {
+ function f(C c) pure public returns (C) {
+ return c;
+ }
+ function g() pure public returns (bytes4) {
+ // By passing `this`, we read from the state, even if f itself is pure.
+ return f(this).f.selector;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "reads from the environment or state and thus requires \"view\"");
+}
+
+BOOST_AUTO_TEST_CASE(selector_complex2)
+{
+ string text = R"(
+ contract C {
+ function f() payable public returns (C) {
+ return this;
+ }
+ function g() pure public returns (bytes4) {
+ C x = C(0x123);
+ return x.f.selector;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(creation)
{
string text = R"(
diff --git a/test/solcjsTests.sh b/test/solcjsTests.sh
new file mode 100755
index 00000000..27797cb4
--- /dev/null
+++ b/test/solcjsTests.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+#------------------------------------------------------------------------------
+# Bash script to execute the Solidity tests.
+#
+# The documentation for solidity is hosted at:
+#
+# https://solidity.readthedocs.org
+#
+# ------------------------------------------------------------------------------
+# 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) 2017 solidity contributors.
+#------------------------------------------------------------------------------
+
+set -e
+
+if [ ! -f "$1" -o -z "$2" ]
+then
+ echo "Usage: $0 <path to soljson.js> <version>"
+ exit 1
+fi
+
+SOLJSON="$1"
+VERSION="$2"
+
+DIR=$(mktemp -d)
+(
+ echo "Preparing solc-js..."
+ git clone --depth 1 https://github.com/ethereum/solc-js "$DIR"
+ cd "$DIR"
+ # disable "prepublish" script which downloads the latest version
+ # (we will replace it anyway and it is often incorrectly cached
+ # on travis)
+ npm config set script.prepublish ''
+ npm install
+
+ # Replace soljson with current build
+ echo "Replacing soljson.js"
+ rm -f soljson.js
+ cp "$SOLJSON" soljson.js
+
+ # Update version (needed for some tests)
+ echo "Updating package.json to version $VERSION"
+ npm version --no-git-tag-version $VERSION
+
+ echo "Running solc-js tests..."
+ npm run test
+)
+rm -rf "$DIR"