aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'test/libsolidity')
-rw-r--r--test/libsolidity/ASTJSON.cpp44
-rw-r--r--test/libsolidity/AnalysisFramework.cpp3
-rw-r--r--test/libsolidity/Assembly.cpp17
-rw-r--r--test/libsolidity/GasMeter.cpp17
-rw-r--r--test/libsolidity/Imports.cpp50
-rw-r--r--test/libsolidity/InlineAssembly.cpp26
-rw-r--r--test/libsolidity/JSONCompiler.cpp6
-rw-r--r--test/libsolidity/Metadata.cpp9
-rw-r--r--test/libsolidity/SMTChecker.cpp13
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp7
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp248
-rw-r--r--test/libsolidity/SolidityExecutionFramework.h24
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp56
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp907
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp7
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp4
-rw-r--r--test/libsolidity/SolidityParser.cpp43
-rw-r--r--test/libsolidity/SolidityTypes.cpp15
-rw-r--r--test/libsolidity/StandardCompiler.cpp253
-rw-r--r--test/libsolidity/ViewPureChecker.cpp20
20 files changed, 1666 insertions, 103 deletions
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp
index 31165922..9bf60b64 100644
--- a/test/libsolidity/ASTJSON.cpp
+++ b/test/libsolidity/ASTJSON.cpp
@@ -20,12 +20,16 @@
* Tests for the json ast output.
*/
-#include <string>
-#include <boost/test/unit_test.hpp>
+#include <test/TestHelper.h>
+
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/ast/ASTJsonConverter.h>
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+
using namespace std;
namespace dev
@@ -41,6 +45,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
{
CompilerStack c;
c.addSource("a", "contract C {}");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -52,6 +57,7 @@ BOOST_AUTO_TEST_CASE(source_location)
{
CompilerStack c;
c.addSource("a", "contract C { function f() { var x = 2; x++; } }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -66,6 +72,7 @@ BOOST_AUTO_TEST_CASE(inheritance_specifier)
{
CompilerStack c;
c.addSource("a", "contract C1 {} contract C2 is C1 {}");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -81,6 +88,7 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
{
CompilerStack c;
c.addSource("a", "library L {} contract C { using L for uint; }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -98,6 +106,7 @@ BOOST_AUTO_TEST_CASE(enum_value)
{
CompilerStack c;
c.addSource("a", "contract C { enum E { A, B } }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -115,6 +124,7 @@ BOOST_AUTO_TEST_CASE(modifier_definition)
{
CompilerStack c;
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -129,6 +139,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
{
CompilerStack c;
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -145,6 +156,7 @@ BOOST_AUTO_TEST_CASE(event_definition)
{
CompilerStack c;
c.addSource("a", "contract C { event E(); }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -159,6 +171,7 @@ BOOST_AUTO_TEST_CASE(array_type_name)
{
CompilerStack c;
c.addSource("a", "contract C { uint[] i; }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -172,6 +185,7 @@ BOOST_AUTO_TEST_CASE(placeholder_statement)
{
CompilerStack c;
c.addSource("a", "contract C { modifier M { _; } }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -185,6 +199,7 @@ BOOST_AUTO_TEST_CASE(non_utf8)
{
CompilerStack c;
c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -204,6 +219,7 @@ BOOST_AUTO_TEST_CASE(function_type)
"contract C { function f(function() external payable returns (uint) x) "
"returns (function() external constant returns (uint)) {} }"
);
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
@@ -237,16 +253,32 @@ BOOST_AUTO_TEST_CASE(documentation)
" and has a line-breaking comment.*/"
"contract C {}"
);
+ c.addSource("c",
+ "contract C {"
+ " /** Some comment on Evt.*/ event Evt();"
+ " /** Some comment on mod.*/ modifier mod() { _; }"
+ " /** Some comment on fn.*/ function fn() public {}"
+ "}"
+ );
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 0;
sourceIndices["b"] = 1;
+ sourceIndices["c"] = 2;
Json::Value astJsonA = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value documentationA = astJsonA["children"][0]["attributes"]["documentation"];
BOOST_CHECK_EQUAL(documentationA, "This contract is empty");
Json::Value astJsonB = ASTJsonConverter(true, sourceIndices).toJson(c.ast("b"));
Json::Value documentationB = astJsonB["children"][0]["attributes"]["documentation"];
BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment.");
+ Json::Value astJsonC = ASTJsonConverter(true, sourceIndices).toJson(c.ast("c"));
+ Json::Value documentationC0 = astJsonC["children"][0]["children"][0]["attributes"]["documentation"];
+ Json::Value documentationC1 = astJsonC["children"][0]["children"][1]["attributes"]["documentation"];
+ Json::Value documentationC2 = astJsonC["children"][0]["children"][2]["attributes"]["documentation"];
+ BOOST_CHECK_EQUAL(documentationC0, "Some comment on Evt.");
+ BOOST_CHECK_EQUAL(documentationC1, "Some comment on mod.");
+ BOOST_CHECK_EQUAL(documentationC2, "Some comment on fn.");
//same tests for non-legacy mode
astJsonA = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a"));
documentationA = astJsonA["nodes"][0]["documentation"];
@@ -254,7 +286,13 @@ BOOST_AUTO_TEST_CASE(documentation)
astJsonB = ASTJsonConverter(false, sourceIndices).toJson(c.ast("b"));
documentationB = astJsonB["nodes"][0]["documentation"];
BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment.");
-
+ astJsonC = ASTJsonConverter(false, sourceIndices).toJson(c.ast("c"));
+ documentationC0 = astJsonC["nodes"][0]["nodes"][0]["documentation"];
+ documentationC1 = astJsonC["nodes"][0]["nodes"][1]["documentation"];
+ documentationC2 = astJsonC["nodes"][0]["nodes"][2]["documentation"];
+ BOOST_CHECK_EQUAL(documentationC0, "Some comment on Evt.");
+ BOOST_CHECK_EQUAL(documentationC1, "Some comment on mod.");
+ BOOST_CHECK_EQUAL(documentationC2, "Some comment on fn.");
}
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index a27e3222..7c335a48 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -20,6 +20,8 @@
#include <test/libsolidity/AnalysisFramework.h>
+#include <test/TestHelper.h>
+
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/SourceReferenceFormatter.h>
@@ -46,6 +48,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
{
m_compiler.reset();
m_compiler.addSource("", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source);
+ m_compiler.setEVMVersion(dev::test::Options::get().evmVersion());
if (!m_compiler.parse())
{
BOOST_ERROR("Parsing contract failed in analysis test suite:" + formatErrors());
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 59af6d41..aff610a4 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -20,11 +20,11 @@
* Unit tests for Assembly Items from evmasm/Assembly.h
*/
-#include <string>
-#include <iostream>
-#include <boost/test/unit_test.hpp>
+#include <test/TestHelper.h>
+
#include <libevmasm/SourceLocation.h>
#include <libevmasm/Assembly.h>
+
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h>
#include <libsolidity/analysis/NameAndTypeResolver.h>
@@ -33,6 +33,11 @@
#include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/interface/ErrorReporter.h>
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+#include <iostream>
+
using namespace std;
using namespace dev::eth;
@@ -46,7 +51,7 @@ namespace test
namespace
{
-eth::AssemblyItems compileContract(const string& _sourceCode)
+eth::AssemblyItems compileContract(string const& _sourceCode)
{
ErrorList errors;
ErrorReporter errorReporter(errors);
@@ -69,7 +74,7 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- TypeChecker checker(errorReporter);
+ TypeChecker checker(dev::test::Options::get().evmVersion(), errorReporter);
BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*contract));
if (!Error::containsOnlyWarnings(errorReporter.errors()))
return AssemblyItems();
@@ -77,7 +82,7 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- Compiler compiler;
+ Compiler compiler(dev::test::Options::get().evmVersion());
compiler.compileContract(*contract, map<ContractDefinition const*, Assembly const*>{}, bytes());
return compiler.runtimeAssemblyItems();
diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp
index 86e8201b..fd2017f9 100644
--- a/test/libsolidity/GasMeter.cpp
+++ b/test/libsolidity/GasMeter.cpp
@@ -49,13 +49,14 @@ public:
m_compiler.reset(false);
m_compiler.addSource("", "pragma solidity >=0.0;\n" + _sourceCode);
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
+ m_compiler.setEVMVersion(m_evmVersion);
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
AssemblyItems const* items = m_compiler.runtimeAssemblyItems(m_compiler.lastContractName());
ASTNode const& sourceUnit = m_compiler.ast("");
BOOST_REQUIRE(items != nullptr);
m_gasCosts = GasEstimator::breakToStatementLevel(
- GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
+ GasEstimator(dev::test::Options::get().evmVersion()).structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
{&sourceUnit}
);
}
@@ -64,7 +65,7 @@ public:
{
compileAndRun(_sourceCode);
auto state = make_shared<KnownState>();
- PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName()));
+ PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName()), dev::test::Options::get().evmVersion());
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
// costs for deployment
@@ -73,7 +74,7 @@ public:
gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);
BOOST_REQUIRE(!gas.isInfinite);
- BOOST_CHECK(gas.value == m_gasUsed);
+ BOOST_CHECK_EQUAL(gas.value, m_gasUsed);
}
/// Compares the gas computed by PathGasMeter for the given signature (but unknown arguments)
@@ -90,12 +91,12 @@ public:
gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false));
}
- gas += GasEstimator::functionalEstimation(
+ gas += GasEstimator(dev::test::Options::get().evmVersion()).functionalEstimation(
*m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()),
_sig
);
BOOST_REQUIRE(!gas.isInfinite);
- BOOST_CHECK(gas.value == m_gasUsed);
+ BOOST_CHECK_EQUAL(gas.value, m_gasUsed);
}
static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
@@ -136,8 +137,10 @@ BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
{
BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
auto scannerFromSource = [&](string const& _sourceName) -> Scanner const& { return m_compiler.scanner(_sourceName); };
- SourceReferenceFormatter::printSourceLocation(cout, &first->first->location(), scannerFromSource);
- SourceReferenceFormatter::printSourceLocation(cout, &second->first->location(), scannerFromSource);
+ SourceReferenceFormatter formatter(cout, scannerFromSource);
+
+ formatter.printSourceLocation(&first->first->location());
+ formatter.printSourceLocation(&second->first->location());
}
}
}
diff --git a/test/libsolidity/Imports.cpp b/test/libsolidity/Imports.cpp
index 03287b28..bc81b3b1 100644
--- a/test/libsolidity/Imports.cpp
+++ b/test/libsolidity/Imports.cpp
@@ -21,6 +21,7 @@
*/
#include <test/libsolidity/ErrorCheck.h>
+#include <test/TestHelper.h>
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/CompilerStack.h>
@@ -44,6 +45,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
{
CompilerStack c;
c.addSource("a", "contract C {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -52,6 +54,7 @@ BOOST_AUTO_TEST_CASE(regular_import)
CompilerStack c;
c.addSource("a", "contract C {} pragma solidity >=0.0;");
c.addSource("b", "import \"a\"; contract D is C {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -60,6 +63,7 @@ BOOST_AUTO_TEST_CASE(import_does_not_clutter_importee)
CompilerStack c;
c.addSource("a", "contract C { D d; } pragma solidity >=0.0;");
c.addSource("b", "import \"a\"; contract D is C {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
@@ -69,6 +73,7 @@ BOOST_AUTO_TEST_CASE(import_is_transitive)
c.addSource("a", "contract C { } pragma solidity >=0.0;");
c.addSource("b", "import \"a\"; pragma solidity >=0.0;");
c.addSource("c", "import \"b\"; contract D is C {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -77,6 +82,7 @@ BOOST_AUTO_TEST_CASE(circular_import)
CompilerStack c;
c.addSource("a", "import \"b\"; contract C { D d; } pragma solidity >=0.0;");
c.addSource("b", "import \"a\"; contract D { C c; } pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -86,6 +92,7 @@ BOOST_AUTO_TEST_CASE(relative_import)
c.addSource("a", "import \"./dir/b\"; contract A is B {} pragma solidity >=0.0;");
c.addSource("dir/b", "contract B {} pragma solidity >=0.0;");
c.addSource("dir/c", "import \"../a\"; contract C is A {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -94,6 +101,7 @@ BOOST_AUTO_TEST_CASE(relative_import_multiplex)
CompilerStack c;
c.addSource("a", "contract A {} pragma solidity >=0.0;");
c.addSource("dir/a/b/c", "import \"../../.././a\"; contract B is A {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -102,6 +110,7 @@ BOOST_AUTO_TEST_CASE(simple_alias)
CompilerStack c;
c.addSource("a", "contract A {} pragma solidity >=0.0;");
c.addSource("dir/a/b/c", "import \"../../.././a\" as x; contract B is x.A { function() { x.A r = x.A(20); } } pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -111,6 +120,7 @@ BOOST_AUTO_TEST_CASE(library_name_clash)
c.addSource("a", "library A {} pragma solidity >=0.0;");
c.addSource("b", "library A {} pragma solidity >=0.0;");
c.addSource("c", "import {A} from \"./a\"; import {A} from \"./b\";");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
@@ -119,6 +129,7 @@ BOOST_AUTO_TEST_CASE(library_name_clash_with_contract)
CompilerStack c;
c.addSource("a", "contract A {} pragma solidity >=0.0;");
c.addSource("b", "library A {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -128,6 +139,7 @@ BOOST_AUTO_TEST_CASE(complex_import)
c.addSource("a", "contract A {} contract B {} contract C { struct S { uint a; } } pragma solidity >=0.0;");
c.addSource("b", "import \"a\" as x; import {B as b, C as c, C} from \"a\"; "
"contract D is b { function f(c.S var1, x.C.S var2, C.S var3) internal {} } pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -136,14 +148,19 @@ BOOST_AUTO_TEST_CASE(name_clash_in_import)
CompilerStack c;
c.addSource("a", "contract A {} pragma solidity >=0.0;");
c.addSource("b", "import \"a\"; contract A {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
c.addSource("b", "import \"a\" as A; contract A {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
c.addSource("b", "import {A as b} from \"a\"; contract b {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
c.addSource("b", "import {A} from \"a\"; contract A {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
c.addSource("b", "import {A} from \"a\"; contract B {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -155,6 +172,7 @@ BOOST_AUTO_TEST_CASE(remappings)
c.addSource("b", "import \"t/tee.sol\"; contract A is Tee {} pragma solidity >=0.0;");
c.addSource("s_1.4.6/s.sol", "contract S {} pragma solidity >=0.0;");
c.addSource("Tee/tee.sol", "contract Tee {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -166,6 +184,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings)
c.addSource("b/b.sol", "import \"s/s.sol\"; contract B is SSeven {} pragma solidity >=0.0;");
c.addSource("s_1.4.6/s.sol", "contract SSix {} pragma solidity >=0.0;");
c.addSource("s_1.4.7/s.sol", "contract SSeven {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -174,6 +193,7 @@ BOOST_AUTO_TEST_CASE(filename_with_period)
CompilerStack c;
c.addSource("a/a.sol", "import \".b.sol\"; contract A is B {} pragma solidity >=0.0;");
c.addSource("a/.b.sol", "contract B {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
@@ -185,6 +205,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_pres
c.addSource("vendor/bar/bar.sol", "import \"foo/foo.sol\"; contract Bar {Foo1 foo;} pragma solidity >=0.0;");
c.addSource("vendor/foo_1.0.0/foo.sol", "contract Foo1 {} pragma solidity >=0.0;");
c.addSource("vendor/foo_2.0.0/foo.sol", "contract Foo2 {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
@@ -196,6 +217,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent)
c.addSource("a/b/main.sol", "import \"x/y/z/z.sol\"; contract Main is E {} pragma solidity >=0.0;");
c.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;");
c.addSource("e/y/z/z.sol", "contract E {} pragma solidity >=0.0;");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
CompilerStack d;
d.setRemappings(vector<string>{"a/b:x=e", "a:x/y/z=d"});
@@ -203,6 +225,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent)
d.addSource("a/b/main.sol", "import \"x/y/z/z.sol\"; contract Main is E {} pragma solidity >=0.0;");
d.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;");
d.addSource("e/y/z/z.sol", "contract E {} pragma solidity >=0.0;");
+ d.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(d.compile());
}
@@ -212,6 +235,7 @@ BOOST_AUTO_TEST_CASE(shadowing_via_import)
c.addSource("a", "library A {} pragma solidity >=0.0;");
c.addSource("b", "library A {} pragma solidity >=0.0;");
c.addSource("c", "import {A} from \"./a\"; import {A} from \"./b\";");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
@@ -225,6 +249,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_imports)
contract C {
}
)");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
size_t errorCount = 0;
for (auto const& e: c.errors())
@@ -251,6 +276,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_multiple_imports)
contract C {
}
)");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
auto numErrors = c.errors().size();
// Sometimes we get the prerelease warning, sometimes not.
@@ -266,7 +292,29 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_multiple_imports)
}
}
-
+BOOST_AUTO_TEST_CASE(shadowing_builtins_with_alias)
+{
+ CompilerStack c;
+ c.addSource("B.sol", "contract C {} pragma solidity >=0.0;");
+ c.addSource("b", R"(
+ pragma solidity >=0.0;
+ import {C as msg} from "B.sol";
+ )");
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
+ BOOST_CHECK(c.compile());
+ auto numErrors = c.errors().size();
+ // Sometimes we get the prerelease warning, sometimes not.
+ BOOST_CHECK(1 <= numErrors && numErrors <= 2);
+ for (auto const& e: c.errors())
+ {
+ string const* msg = e->comment();
+ BOOST_REQUIRE(msg);
+ BOOST_CHECK(
+ msg->find("pre-release") != string::npos ||
+ msg->find("shadows a builtin symbol") != string::npos
+ );
+ }
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index b09eb261..a4dcc4d5 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -55,7 +55,7 @@ boost::optional<Error> parseAndReturnFirstError(
AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
)
{
- AssemblyStack stack(_language);
+ AssemblyStack stack(dev::test::Options::get().evmVersion(), _language);
bool success = false;
try
{
@@ -117,7 +117,7 @@ Error expectError(
void parsePrintCompare(string const& _source, bool _canWarn = false)
{
- AssemblyStack stack;
+ AssemblyStack stack(dev::test::Options::get().evmVersion());
BOOST_REQUIRE(stack.parseAndAnalyze("", _source));
if (_canWarn)
BOOST_REQUIRE(Error::containsOnlyWarnings(stack.errors()));
@@ -168,6 +168,11 @@ BOOST_AUTO_TEST_CASE(smoke_test)
BOOST_CHECK(successParse("{ }"));
}
+BOOST_AUTO_TEST_CASE(surplus_input)
+{
+ CHECK_PARSE_ERROR("{ } { }", ParserError, "Expected token EOS");
+}
+
BOOST_AUTO_TEST_CASE(simple_instructions)
{
BOOST_CHECK(successParse("{ dup1 dup1 mul dup1 sub pop }"));
@@ -385,6 +390,7 @@ BOOST_AUTO_TEST_CASE(number_literals)
CHECK_PARSE_ERROR("{ let x := .1 }", ParserError, "Invalid number literal.");
CHECK_PARSE_ERROR("{ let x := 1e5 }", ParserError, "Invalid number literal.");
CHECK_PARSE_ERROR("{ let x := 67.235 }", ParserError, "Invalid number literal.");
+ CHECK_STRICT_ERROR("{ let x := 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }", TypeError, "Number literal too large (> 256 bits)");
}
BOOST_AUTO_TEST_CASE(function_definitions)
@@ -561,7 +567,7 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode)
{
string source = "{ let x := \"\\u1bac\" }";
string parsed = "{\n let x := \"\\xe1\\xae\\xac\"\n}";
- AssemblyStack stack;
+ AssemblyStack stack(dev::test::Options::get().evmVersion());
BOOST_REQUIRE(stack.parseAndAnalyze("", source));
BOOST_REQUIRE(stack.errors().empty());
BOOST_CHECK_EQUAL(stack.print(), parsed);
@@ -768,6 +774,20 @@ BOOST_AUTO_TEST_CASE(create2)
BOOST_CHECK(successAssemble("{ pop(create2(10, 0x123, 32, 64)) }"));
}
+BOOST_AUTO_TEST_CASE(shift)
+{
+ BOOST_CHECK(successAssemble("{ pop(shl(10, 32)) }"));
+ BOOST_CHECK(successAssemble("{ pop(shr(10, 32)) }"));
+ BOOST_CHECK(successAssemble("{ pop(sar(10, 32)) }"));
+}
+
+BOOST_AUTO_TEST_CASE(shift_constantinople_warning)
+{
+ CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", Warning, "The \"shl\" instruction is only available for Constantinople-compatible VMs.");
+ CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", Warning, "The \"shr\" instruction is only available for Constantinople-compatible VMs.");
+ CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", Warning, "The \"sar\" instruction is only available for Constantinople-compatible VMs.");
+}
+
BOOST_AUTO_TEST_CASE(jump_warning)
{
CHECK_PARSE_WARNING("{ 1 jump }", Warning, "Jump instructions");
diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp
index 0c904c77..285c5604 100644
--- a/test/libsolidity/JSONCompiler.cpp
+++ b/test/libsolidity/JSONCompiler.cpp
@@ -44,7 +44,7 @@ Json::Value compileSingle(string const& _input)
{
string output(compileJSON(_input.c_str(), dev::test::Options::get().optimize));
Json::Value ret;
- BOOST_REQUIRE(Json::Reader().parse(output, ret, false));
+ BOOST_REQUIRE(jsonParseStrict(output, ret));
return ret;
}
@@ -56,7 +56,7 @@ Json::Value compileMulti(string const& _input, bool _callback)
compileJSONMulti(_input.c_str(), dev::test::Options::get().optimize)
);
Json::Value ret;
- BOOST_REQUIRE(Json::Reader().parse(output, ret, false));
+ BOOST_REQUIRE(jsonParseStrict(output, ret));
return ret;
}
@@ -64,7 +64,7 @@ Json::Value compile(string const& _input)
{
string output(compileStandard(_input.c_str(), NULL));
Json::Value ret;
- BOOST_REQUIRE(Json::Reader().parse(output, ret, false));
+ BOOST_REQUIRE(jsonParseStrict(output, ret));
return ret;
}
diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp
index efe8faff..f1edeeb7 100644
--- a/test/libsolidity/Metadata.cpp
+++ b/test/libsolidity/Metadata.cpp
@@ -23,6 +23,7 @@
#include "../TestHelper.h"
#include <libsolidity/interface/CompilerStack.h>
#include <libdevcore/SwarmHash.h>
+#include <libdevcore/JSON.h>
namespace dev
{
@@ -45,6 +46,7 @@ BOOST_AUTO_TEST_CASE(metadata_stamp)
)";
CompilerStack compilerStack;
compilerStack.addSource("", std::string(sourceCode));
+ compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
@@ -71,6 +73,7 @@ BOOST_AUTO_TEST_CASE(metadata_stamp_experimental)
)";
CompilerStack compilerStack;
compilerStack.addSource("", std::string(sourceCode));
+ compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
@@ -105,13 +108,14 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources)
}
)";
compilerStack.addSource("B", std::string(sourceCode));
+ compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
std::string const& serialisedMetadata = compilerStack.metadata("A");
BOOST_CHECK(dev::test::isValidMetadata(serialisedMetadata));
Json::Value metadata;
- BOOST_REQUIRE(Json::Reader().parse(serialisedMetadata, metadata, false));
+ BOOST_REQUIRE(jsonParseStrict(serialisedMetadata, metadata));
BOOST_CHECK_EQUAL(metadata["sources"].size(), 1);
BOOST_CHECK(metadata["sources"].isMember("A"));
@@ -143,13 +147,14 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources_imports)
}
)";
compilerStack.addSource("C", std::string(sourceCode));
+ compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
std::string const& serialisedMetadata = compilerStack.metadata("C");
BOOST_CHECK(dev::test::isValidMetadata(serialisedMetadata));
Json::Value metadata;
- BOOST_REQUIRE(Json::Reader().parse(serialisedMetadata, metadata, false));
+ BOOST_REQUIRE(jsonParseStrict(serialisedMetadata, metadata));
BOOST_CHECK_EQUAL(metadata["sources"].size(), 3);
BOOST_CHECK(metadata["sources"].isMember("A"));
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index 8c955292..12b5f439 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -35,12 +35,6 @@ namespace test
class SMTCheckerFramework: public AnalysisFramework
{
-public:
- SMTCheckerFramework()
- {
- m_warningsToFilter.push_back("Experimental features are turned on.");
- }
-
protected:
virtual std::pair<SourceUnit const*, ErrorList>
parseAnalyseAndReturnError(
@@ -103,6 +97,7 @@ BOOST_AUTO_TEST_CASE(warn_on_struct)
}
)";
CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
+ "Experimental feature",
"Assertion checker does not yet implement this expression.",
"Assertion checker does not yet support the type of this variable."
}));
@@ -471,7 +466,8 @@ BOOST_AUTO_TEST_CASE(for_loop)
text = R"(
contract C {
function f(uint x) public pure {
- for (uint y = 2; x < 10; ) {
+ uint y;
+ for (y = 2; x < 10; ) {
y = 3;
}
assert(y == 3);
@@ -482,7 +478,8 @@ BOOST_AUTO_TEST_CASE(for_loop)
text = R"(
contract C {
function f(uint x) public pure {
- for (uint y = 2; x < 10; ) {
+ uint y;
+ for (y = 2; x < 10; ) {
y = 3;
}
assert(y == 2);
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 26bfb6d0..0d471b32 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -26,7 +26,7 @@
#include <libdevcore/Exceptions.h>
#include <libdevcore/SwarmHash.h>
-#include <json/json.h>
+#include <libdevcore/JSON.h>
namespace dev
{
@@ -44,11 +44,13 @@ public:
{
m_compilerStack.reset(false);
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
+ m_compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
+ m_compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
Json::Value generatedInterface = m_compilerStack.contractABI(m_compilerStack.lastContractName());
Json::Value expectedInterface;
- BOOST_REQUIRE(m_reader.parse(_expectedInterfaceString, expectedInterface));
+ BOOST_REQUIRE(jsonParseStrict(_expectedInterfaceString, expectedInterface));
BOOST_CHECK_MESSAGE(
expectedInterface == generatedInterface,
"Expected:\n" << expectedInterface.toStyledString() <<
@@ -58,7 +60,6 @@ public:
protected:
CompilerStack m_compilerStack;
- Json::Reader m_reader;
};
BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, JSONInterfaceChecker)
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 0611e71d..33cd1419 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -21,13 +21,20 @@
* Unit tests for the solidity expression compiler, testing the behaviour of the code.
*/
+#include <test/libsolidity/SolidityExecutionFramework.h>
+
+#include <test/TestHelper.h>
+
+#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/interface/EVMVersion.h>
+
+#include <libevmasm/Assembly.h>
+
+#include <boost/test/unit_test.hpp>
+
#include <functional>
#include <string>
#include <tuple>
-#include <boost/test/unit_test.hpp>
-#include <libevmasm/Assembly.h>
-#include <libsolidity/interface/Exceptions.h>
-#include <test/libsolidity/SolidityExecutionFramework.h>
using namespace std;
using namespace std::placeholders;
@@ -284,6 +291,54 @@ BOOST_AUTO_TEST_CASE(conditional_expression_functions)
ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(u256(2)));
}
+BOOST_AUTO_TEST_CASE(C99_scoping_activation)
+{
+ char const* sourceCode = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public returns (uint) {
+ uint x = 7;
+ {
+ x = 3; // This should still assign to the outer variable
+ uint x;
+ x = 4; // This should assign to the new one
+ }
+ return x;
+ }
+ function g() pure public returns (uint x) {
+ x = 7;
+ {
+ x = 3;
+ uint x;
+ return x; // This returns the new variable, i.e. 0
+ }
+ }
+ function h() pure public returns (uint x, uint a, uint b) {
+ x = 7;
+ {
+ x = 3;
+ a = x; // This should read from the outer
+ uint x = 4;
+ b = x;
+ }
+ }
+ function i() pure public returns (uint x, uint a) {
+ x = 7;
+ {
+ x = 3;
+ uint x = x; // This should read from the outer and assign to the inner
+ a = x;
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(0));
+ ABI_CHECK(callContractFunction("h()"), encodeArgs(3, 3, 4));
+ ABI_CHECK(callContractFunction("i()"), encodeArgs(3, 3));
+}
+
BOOST_AUTO_TEST_CASE(recursive_calls)
{
char const* sourceCode = R"(
@@ -2967,6 +3022,29 @@ BOOST_AUTO_TEST_CASE(event)
}
}
+BOOST_AUTO_TEST_CASE(event_emit)
+{
+ char const* sourceCode = R"(
+ contract ClientReceipt {
+ event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
+ function deposit(bytes32 _id) payable {
+ emit Deposit(msg.sender, _id, msg.value);
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ u256 value(18);
+ u256 id(0x1234);
+ callContractFunctionWithValue("deposit(bytes32)", value, id);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
+ BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value)));
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3);
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256)")));
+ BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight));
+ BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id));
+}
+
BOOST_AUTO_TEST_CASE(event_no_arguments)
{
char const* sourceCode = R"(
@@ -3009,6 +3087,28 @@ BOOST_AUTO_TEST_CASE(event_access_through_base_name)
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("x()")));
}
+BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit)
+{
+ char const* sourceCode = R"(
+ contract A {
+ event x();
+ }
+ contract B is A {
+ function f() returns (uint) {
+ emit A.x();
+ return 1;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ callContractFunction("f()");
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
+ BOOST_CHECK(m_logs[0].data.empty());
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("x()")));
+}
+
BOOST_AUTO_TEST_CASE(events_with_same_name)
{
char const* sourceCode = R"(
@@ -3107,6 +3207,58 @@ BOOST_AUTO_TEST_CASE(events_with_same_name_inherited)
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,uint256)")));
}
+BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit)
+{
+ char const* sourceCode = R"(
+ contract A {
+ event Deposit();
+ }
+
+ contract B {
+ event Deposit(address _addr);
+ }
+
+ contract ClientReceipt is A, B {
+ event Deposit(address _addr, uint _amount);
+ function deposit() returns (uint) {
+ emit Deposit();
+ return 1;
+ }
+ function deposit(address _addr) returns (uint) {
+ emit Deposit(_addr);
+ return 1;
+ }
+ function deposit(address _addr, uint _amount) returns (uint) {
+ emit Deposit(_addr, _amount);
+ return 1;
+ }
+ }
+ )";
+ u160 const c_loggedAddress = m_contractAddress;
+
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
+ BOOST_CHECK(m_logs[0].data.empty());
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()")));
+
+ ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1)));
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
+ BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress));
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address)")));
+
+ ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1)));
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
+ BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress, 100));
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,uint256)")));
+}
+
BOOST_AUTO_TEST_CASE(event_anonymous)
{
char const* sourceCode = R"(
@@ -3565,8 +3717,8 @@ BOOST_AUTO_TEST_CASE(library_call_protection)
}
)";
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("np(Lib.S storage)", 0), encodeArgs());
+ ABI_CHECK(callContractFunction("v(Lib.S storage)", 0), 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));
@@ -5207,6 +5359,18 @@ BOOST_AUTO_TEST_CASE(super_overload)
ABI_CHECK(callContractFunction("h()"), encodeArgs(2));
}
+BOOST_AUTO_TEST_CASE(gasleft_shadow_resolution)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function gasleft() returns(uint256) { return 0; }
+ function f() returns(uint256) { return gasleft(); }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(0));
+}
+
BOOST_AUTO_TEST_CASE(bool_conversion)
{
char const* sourceCode = R"(
@@ -7459,6 +7623,33 @@ BOOST_AUTO_TEST_CASE(addmod_mulmod)
ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0)));
}
+BOOST_AUTO_TEST_CASE(addmod_mulmod_zero)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() pure returns (uint) {
+ addmod(1, 2, 0);
+ return 2;
+ }
+ function g() pure returns (uint) {
+ mulmod(1, 2, 0);
+ return 2;
+ }
+ function h() pure returns (uint) {
+ mulmod(0, 1, 2);
+ mulmod(1, 0, 2);
+ addmod(0, 1, 2);
+ addmod(1, 0, 2);
+ return 2;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f()"), encodeArgs());
+ ABI_CHECK(callContractFunction("g()"), encodeArgs());
+ ABI_CHECK(callContractFunction("h()"), encodeArgs(2));
+}
+
BOOST_AUTO_TEST_CASE(divisiod_by_zero)
{
char const* sourceCode = R"(
@@ -10594,6 +10785,51 @@ BOOST_AUTO_TEST_CASE(snark)
BOOST_CHECK(callContractFunction("verifyTx()") == encodeArgs(true));
}
+BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure)
+{
+ char const* sourceCode = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ uint x;
+ function f() public returns (uint) {
+ x = 3;
+ return 1;
+ }
+ }
+ interface CView {
+ function f() view external returns (uint);
+ }
+ interface CPure {
+ function f() pure external returns (uint);
+ }
+ contract D {
+ function f() public returns (uint) {
+ return (new C()).f();
+ }
+ function fview() public returns (uint) {
+ return (CView(new C())).f();
+ }
+ function fpure() public returns (uint) {
+ return (CPure(new C())).f();
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "D");
+ // This should work (called via CALL)
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(1));
+ if (dev::test::Options::get().evmVersion().hasStaticCall())
+ {
+ // These should throw (called via STATICCALL)
+ ABI_CHECK(callContractFunction("fview()"), encodeArgs());
+ ABI_CHECK(callContractFunction("fpure()"), encodeArgs());
+ }
+ else
+ {
+ ABI_CHECK(callContractFunction("fview()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("fpure()"), encodeArgs(1));
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h
index b0daaba9..12687dd1 100644
--- a/test/libsolidity/SolidityExecutionFramework.h
+++ b/test/libsolidity/SolidityExecutionFramework.h
@@ -52,27 +52,39 @@ public:
std::map<std::string, dev::test::Address> const& _libraryAddresses = std::map<std::string, dev::test::Address>()
) override
{
+ bytes bytecode = compileContract(_sourceCode, _contractName, _libraryAddresses);
+ sendMessage(bytecode + _arguments, true, _value);
+ return m_output;
+ }
+
+ bytes compileContract(
+ std::string const& _sourceCode,
+ std::string const& _contractName = "",
+ std::map<std::string, dev::test::Address> const& _libraryAddresses = std::map<std::string, dev::test::Address>()
+ )
+ {
// Silence compiler version warning
std::string sourceCode = "pragma solidity >=0.0;\n" + _sourceCode;
m_compiler.reset(false);
m_compiler.addSource("", sourceCode);
m_compiler.setLibraries(_libraryAddresses);
+ m_compiler.setEVMVersion(m_evmVersion);
m_compiler.setOptimiserSettings(m_optimize, m_optimizeRuns);
if (!m_compiler.compile())
{
+ auto scannerFromSourceName = [&](std::string const& _sourceName) -> solidity::Scanner const& { return m_compiler.scanner(_sourceName); };
+ SourceReferenceFormatter formatter(std::cerr, scannerFromSourceName);
+
for (auto const& error: m_compiler.errors())
- SourceReferenceFormatter::printExceptionInformation(
- std::cerr,
+ formatter.printExceptionInformation(
*error,
- (error->type() == Error::Type::Warning) ? "Warning" : "Error",
- [&](std::string const& _sourceName) -> solidity::Scanner const& { return m_compiler.scanner(_sourceName); }
+ (error->type() == Error::Type::Warning) ? "Warning" : "Error"
);
BOOST_ERROR("Compiling contract failed");
}
eth::LinkerObject obj = m_compiler.object(_contractName.empty() ? m_compiler.lastContractName() : _contractName);
BOOST_REQUIRE(obj.linkReferences.empty());
- sendMessage(obj.bytecode + _arguments, true, _value);
- return m_output;
+ return obj.bytecode;
}
protected:
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index 67747386..5f044b44 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -132,7 +132,7 @@ bytes compileFirstExpression(
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
ErrorReporter errorReporter(errors);
- TypeChecker typeChecker(errorReporter);
+ TypeChecker typeChecker(dev::test::Options::get().evmVersion(), errorReporter);
BOOST_REQUIRE(typeChecker.checkTypeRequirements(*contract));
}
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
@@ -141,7 +141,7 @@ bytes compileFirstExpression(
FirstExpressionExtractor extractor(*contract);
BOOST_REQUIRE(extractor.expression() != nullptr);
- CompilerContext context;
+ CompilerContext context(dev::test::Options::get().evmVersion());
context.resetVisitedNodes(contract);
context.setInheritanceHierarchy(inheritanceHierarchy);
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
@@ -322,10 +322,10 @@ BOOST_AUTO_TEST_CASE(arithmetics)
{
char const* sourceCode = R"(
contract test {
- function f(uint y) { var x = ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }
+ function f(uint y) { ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }
}
)";
- bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}});
+ bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
bytes expectation({byte(Instruction::PUSH1), 0x1,
byte(Instruction::PUSH1), 0x2,
byte(Instruction::PUSH1), 0x3,
@@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(Instruction::PUSH1), 0x6,
byte(Instruction::PUSH1), 0x7,
byte(Instruction::PUSH1), 0x8,
- byte(Instruction::DUP10),
+ byte(Instruction::DUP9),
byte(Instruction::XOR),
byte(Instruction::AND),
byte(Instruction::OR),
@@ -364,13 +364,13 @@ BOOST_AUTO_TEST_CASE(unary_operators)
{
char const* sourceCode = R"(
contract test {
- function f(int y) { var x = !(~+- y == 2); }
+ function f(int y) { !(~+- y == 2); }
}
)";
- bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}});
+ bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
bytes expectation({byte(Instruction::PUSH1), 0x2,
- byte(Instruction::DUP3),
+ byte(Instruction::DUP2),
byte(Instruction::PUSH1), 0x0,
byte(Instruction::SUB),
byte(Instruction::NOT),
@@ -383,7 +383,7 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec)
{
char const* sourceCode = R"(
contract test {
- function f(uint a) { var x = --a ^ (a-- ^ (++a ^ a++)); }
+ function f(uint a) returns (uint x) { x = --a ^ (a-- ^ (++a ^ a++)); }
}
)";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}});
@@ -426,7 +426,10 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec)
byte(Instruction::POP), // second ++
// Stack here: a x a^(a+2)^(a+2)
byte(Instruction::DUP3), // will change
- byte(Instruction::XOR)});
+ byte(Instruction::XOR),
+ byte(Instruction::SWAP1),
+ byte(Instruction::POP),
+ byte(Instruction::DUP1)});
// Stack here: a x a^(a+2)^(a+2)^a
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -512,6 +515,39 @@ BOOST_AUTO_TEST_CASE(blockhash)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
+BOOST_AUTO_TEST_CASE(gas_left)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f() returns (uint256 val) {
+ return msg.gas;
+ }
+ }
+ )";
+ bytes code = compileFirstExpression(
+ sourceCode, {}, {},
+ {make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message))}
+ );
+
+ bytes expectation({byte(Instruction::GAS)});
+ BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
+
+ sourceCode = R"(
+ contract test {
+ function f() returns (uint256 val) {
+ return gasleft();
+ }
+ }
+ )";
+ code = compileFirstExpression(
+ sourceCode, {}, {},
+ {make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))}
+ );
+
+ expectation = bytes({byte(Instruction::GAS)});
+ BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 315c7c5f..997b610e 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -22,6 +22,8 @@
#include <test/libsolidity/AnalysisFramework.h>
+#include <test/TestHelper.h>
+
#include <libsolidity/ast/AST.h>
#include <libdevcore/SHA3.h>
@@ -76,15 +78,233 @@ BOOST_AUTO_TEST_CASE(double_function_declaration)
BOOST_AUTO_TEST_CASE(double_variable_declaration)
{
- char const* text = R"(
+ string text = R"(
contract test {
- function f() public {
+ function f() pure public {
uint256 x;
if (true) { uint256 x; }
}
}
)";
- CHECK_ERROR(text, DeclarationError, "Identifier already declared.");
+ CHECK_ERROR(text, DeclarationError, "Identifier already declared");
+}
+
+BOOST_AUTO_TEST_CASE(double_variable_declaration_050)
+{
+ string text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ uint256 x;
+ if (true) { uint256 x; }
+ }
+ }
+ )";
+ CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
+ "This declaration shadows an existing declaration.",
+ "Unused local variable",
+ "Unused local variable"
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope)
+{
+ string text = R"(
+ contract test {
+ function f() pure public {
+ { uint x; }
+ { uint x; }
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Identifier already declared");
+}
+
+BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope_050)
+{
+ string text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ { uint x; }
+ { uint x; }
+ }
+ }
+ )";
+ CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
+ "Unused local variable",
+ "Unused local variable"
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope_activation)
+{
+ string text = R"(
+ contract test {
+ function f() pure public {
+ { uint x; }
+ uint x;
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Identifier already declared");
+}
+
+BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope_activation_050)
+{
+ string text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ { uint x; }
+ uint x;
+ }
+ }
+ )";
+ CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
+ "Unused local variable",
+ "Unused local variable"
+ }));
+}
+BOOST_AUTO_TEST_CASE(scoping_old)
+{
+ char const* text = R"(
+ contract test {
+ function f() pure public {
+ x = 4;
+ uint256 x = 2;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(scoping)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() public {
+ {
+ uint256 x;
+ }
+ x = 2;
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
+}
+
+BOOST_AUTO_TEST_CASE(scoping_activation_old)
+{
+ char const* text = R"(
+ contract test {
+ function f() pure public {
+ x = 3;
+ uint x;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(scoping_activation)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ x = 3;
+ uint x;
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
+}
+
+BOOST_AUTO_TEST_CASE(scoping_self_use)
+{
+ char const* text = R"(
+ contract test {
+ function f() pure public {
+ uint a = a;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(scoping_self_use_050)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ uint a = a;
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
+}
+
+BOOST_AUTO_TEST_CASE(scoping_for)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ for (uint x = 0; x < 10; x ++){
+ x = 2;
+ }
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(scoping_for2)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ for (uint x = 0; x < 10; x ++)
+ x = 2;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(scoping_for3)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ for (uint x = 0; x < 10; x ++){
+ x = 2;
+ }
+ x = 4;
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
+}
+
+BOOST_AUTO_TEST_CASE(scoping_for_decl_in_body)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ for (;; y++){
+ uint y = 3;
+ }
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
}
BOOST_AUTO_TEST_CASE(name_shadowing)
@@ -758,6 +978,62 @@ BOOST_AUTO_TEST_CASE(functions_with_stucts_of_non_external_types_in_interface_ne
CHECK_ERROR(text, TypeError, "Internal or recursive type is not allowed for public or external functions.");
}
+BOOST_AUTO_TEST_CASE(returning_multi_dimensional_arrays_new_abi)
+{
+ char const* text = R"(
+ pragma experimental ABIEncoderV2;
+
+ contract C {
+ function f() public pure returns (string[][]) {}
+ }
+ )";
+ CHECK_WARNING(text, "Experimental features");
+}
+
+BOOST_AUTO_TEST_CASE(returning_multi_dimensional_arrays)
+{
+ char const* text = R"(
+ contract C {
+ function f() public pure returns (string[][]) {}
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "only supported in the new experimental ABI encoder");
+}
+
+BOOST_AUTO_TEST_CASE(returning_multi_dimensional_static_arrays)
+{
+ char const* text = R"(
+ contract C {
+ function f() public pure returns (uint[][2]) {}
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "only supported in the new experimental ABI encoder");
+}
+
+BOOST_AUTO_TEST_CASE(returning_arrays_in_structs_new_abi)
+{
+ char const* text = R"(
+ pragma experimental ABIEncoderV2;
+
+ contract C {
+ struct S { string[] s; }
+ function f() public pure returns (S) {}
+ }
+ )";
+ CHECK_WARNING(text, "Experimental features");
+}
+
+BOOST_AUTO_TEST_CASE(returning_arrays_in_structs_arrays)
+{
+ char const* text = R"(
+ contract C {
+ struct S { string[] s; }
+ function f() public pure returns (S x) {}
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "only supported in the new experimental ABI encoder");
+}
+
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
{
char const* text = R"(
@@ -1004,7 +1280,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation)
{
char const* text = R"(
contract B {
- function f() mod1(2, true) mod2("0123456") public { }
+ function f() mod1(2, true) mod2("0123456") pure public { }
modifier mod1(uint a, bool b) { if (b) _; }
modifier mod2(bytes7 a) { while (a == "1234567") _; }
}
@@ -1039,11 +1315,23 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
{
char const* text = R"(
contract B {
- function f() mod(x) public { uint x = 7; }
+ function f() mod(x) pure public { uint x = 7; }
modifier mod(uint a) { if (a > 0) _; }
}
)";
- CHECK_SUCCESS(text);
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables050)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract B {
+ function f() mod(x) pure public { uint x = 7; }
+ modifier mod(uint a) { if (a > 0) _; }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Undeclared identifier.");
}
BOOST_AUTO_TEST_CASE(function_modifier_double_invocation)
@@ -2484,6 +2772,25 @@ BOOST_AUTO_TEST_CASE(explicit_conversion_from_decimal_to_bytesxx)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(combining_hex_and_denomination)
+{
+ char const* text = R"(
+ contract Foo {
+ uint constant x = 0x01 wei;
+ }
+ )";
+ CHECK_WARNING(text, "Hexadecimal numbers with unit denominations are deprecated.");
+
+ char const* textV050 = R"(
+ pragma experimental "v0.5.0";
+
+ contract Foo {
+ uint constant x = 0x01 wei;
+ }
+ )";
+ CHECK_ERROR(textV050, TypeError, "Hexadecimal numbers cannot be used with unit denominations.");
+}
+
BOOST_AUTO_TEST_CASE(assigning_value_to_const_variable)
{
char const* text = R"(
@@ -3021,6 +3328,20 @@ BOOST_AUTO_TEST_CASE(uninitialized_mapping_array_variable)
CHECK_WARNING(sourceCode, "Uninitialized storage pointer");
}
+BOOST_AUTO_TEST_CASE(uninitialized_mapping_array_variable_050)
+{
+ char const* sourceCode = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure public {
+ mapping(uint => uint)[] storage x;
+ x;
+ }
+ }
+ )";
+ CHECK_ERROR(sourceCode, DeclarationError, "Uninitialized storage pointer");
+}
+
BOOST_AUTO_TEST_CASE(no_delete_on_storage_pointers)
{
char const* sourceCode = R"(
@@ -3320,6 +3641,24 @@ BOOST_AUTO_TEST_CASE(non_initialized_references)
CHECK_WARNING(text, "Uninitialized storage pointer");
}
+BOOST_AUTO_TEST_CASE(non_initialized_references_050)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract c
+ {
+ struct s {
+ uint a;
+ }
+ function f() public {
+ s storage x;
+ }
+ }
+ )";
+
+ CHECK_ERROR(text, DeclarationError, "Uninitialized storage pointer");
+}
+
BOOST_AUTO_TEST_CASE(keccak256_with_large_integer_constant)
{
char const* text = R"(
@@ -5607,10 +5946,11 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_negative_stack)
BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_two_stack_load)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract c {
uint8 x;
function f() public {
- assembly { x pop }
+ assembly { pop(x) }
}
}
)";
@@ -5620,6 +5960,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_two_stack_load)
BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
modifier m {
uint a = 1;
@@ -5628,7 +5969,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
}
_;
}
- function f() m {
+ function f() public m {
}
}
)";
@@ -5638,6 +5979,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
BOOST_AUTO_TEST_CASE(inline_assembly_storage)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
uint x = 1;
function f() public {
@@ -5653,6 +5995,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage)
BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
uint x = 1;
modifier m {
@@ -5661,7 +6004,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers)
}
_;
}
- function f() m {
+ function f() public m {
}
}
)";
@@ -5671,6 +6014,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers)
BOOST_AUTO_TEST_CASE(inline_assembly_constant_assign)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
uint constant x = 1;
function f() public {
@@ -5686,6 +6030,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_constant_assign)
BOOST_AUTO_TEST_CASE(inline_assembly_constant_access)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
uint constant x = 1;
function f() public {
@@ -5701,6 +6046,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_constant_access)
BOOST_AUTO_TEST_CASE(inline_assembly_local_variable_access_out_of_functions)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
function f() public {
uint a;
@@ -5716,6 +6062,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_local_variable_access_out_of_functions)
BOOST_AUTO_TEST_CASE(inline_assembly_local_variable_access_out_of_functions_storage_ptr)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
uint[] r;
function f() public {
@@ -5732,6 +6079,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_local_variable_access_out_of_functions_stor
BOOST_AUTO_TEST_CASE(inline_assembly_storage_variable_access_out_of_functions)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
uint a;
function f() pure public {
@@ -5744,9 +6092,25 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_variable_access_out_of_functions)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(inline_assembly_constant_variable_via_offset)
+{
+ char const* text = R"(
+ contract test {
+ uint constant x = 2;
+ function f() pure public {
+ assembly {
+ let r := x_offset
+ }
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Constant variables not supported by inline assembly.");
+}
+
BOOST_AUTO_TEST_CASE(inline_assembly_calldata_variables)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract C {
function f(bytes bytesAsCalldata) external {
assembly {
@@ -5758,6 +6122,182 @@ BOOST_AUTO_TEST_CASE(inline_assembly_calldata_variables)
CHECK_ERROR(text, TypeError, "Call data elements cannot be accessed directly.");
}
+BOOST_AUTO_TEST_CASE(inline_assembly_050_literals_on_stack)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure public {
+ assembly {
+ 1
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::SyntaxError, "are not supposed to return"},
+ {Error::Type::DeclarationError, "Unbalanced stack"},
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_literals_on_stack)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure public {
+ assembly {
+ 1
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "are not supposed to return"},
+ {Error::Type::DeclarationError, "Unbalanced stack"},
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_050_bare_instructions)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() view public {
+ assembly {
+ address
+ pop
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::SyntaxError, "The use of non-functional"},
+ {Error::Type::SyntaxError, "The use of non-functional"}
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_bare_instructions)
+{
+ char const* text = R"(
+ contract C {
+ function f() view public {
+ assembly {
+ address
+ pop
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "The use of non-functional"},
+ {Error::Type::Warning, "The use of non-functional"}
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_050_labels)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure public {
+ assembly {
+ label:
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::SyntaxError, "Jump instructions and labels are low-level"},
+ {Error::Type::SyntaxError, "The use of labels is deprecated"}
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_labels)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure public {
+ assembly {
+ label:
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Jump instructions and labels are low-level"},
+ {Error::Type::Warning, "The use of labels is deprecated"}
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_050_jump)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure public {
+ assembly {
+ jump(2)
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::SyntaxError, "Jump instructions and labels are low-level"}
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_jump)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure public {
+ assembly {
+ jump(2)
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::TypeError, "Function declared as pure"},
+ {Error::Type::Warning, "Jump instructions and labels are low-level"}
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_050_leave_items_on_stack)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure public {
+ assembly {
+ mload(0)
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::SyntaxError, "are not supposed to return"},
+ {Error::Type::DeclarationError, "Unbalanced stack"},
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_leave_items_on_stack)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure public {
+ assembly {
+ mload(0)
+ }
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "are not supposed to return"},
+ {Error::Type::DeclarationError, "Unbalanced stack"},
+ }));
+}
+
BOOST_AUTO_TEST_CASE(invalid_mobile_type)
{
char const* text = R"(
@@ -6285,7 +6825,16 @@ BOOST_AUTO_TEST_CASE(warn_about_throw)
}
}
)";
- CHECK_WARNING(text, "\"throw\" is deprecated");
+ CHECK_WARNING(text, "\"throw\" is deprecated in favour of \"revert()\", \"require()\" and \"assert()\"");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure public {
+ throw;
+ }
+ }
+ )";
+ CHECK_ERROR(text, SyntaxError, "\"throw\" is deprecated in favour of \"revert()\", \"require()\" and \"assert()\"");
}
BOOST_AUTO_TEST_CASE(bare_revert)
@@ -6701,6 +7250,8 @@ BOOST_AUTO_TEST_CASE(callable_crash)
BOOST_AUTO_TEST_CASE(error_transfer_non_payable_fallback)
{
+ // This used to be a test for a.transfer to generate a warning
+ // because A's fallback function is not payable.
char const* text = R"(
contract A {
function() public {}
@@ -6714,12 +7265,17 @@ BOOST_AUTO_TEST_CASE(error_transfer_non_payable_fallback)
}
}
)";
- CHECK_ERROR(text, TypeError, "Value transfer to a contract without a payable fallback function.");
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"transfer\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
}
BOOST_AUTO_TEST_CASE(error_transfer_no_fallback)
{
- char const* text = R"(
+ // This used to be a test for a.transfer to generate a warning
+ // because A does not have a payable fallback function.
+ std::string text = R"(
contract A {}
contract B {
@@ -6730,12 +7286,17 @@ BOOST_AUTO_TEST_CASE(error_transfer_no_fallback)
}
}
)";
- CHECK_ERROR(text, TypeError, "Value transfer to a contract without a payable fallback function.");
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"transfer\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
}
BOOST_AUTO_TEST_CASE(error_send_non_payable_fallback)
{
- char const* text = R"(
+ // This used to be a test for a.send to generate a warning
+ // because A does not have a payable fallback function.
+ std::string text = R"(
contract A {
function() public {}
}
@@ -6748,11 +7309,16 @@ BOOST_AUTO_TEST_CASE(error_send_non_payable_fallback)
}
}
)";
- CHECK_ERROR(text, TypeError, "Value transfer to a contract without a payable fallback function.");
+ CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"send\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
}
BOOST_AUTO_TEST_CASE(does_not_error_transfer_payable_fallback)
{
+ // This used to be a test for a.transfer to generate a warning
+ // because A does not have a payable fallback function.
char const* text = R"(
contract A {
function() payable public {}
@@ -6766,7 +7332,7 @@ BOOST_AUTO_TEST_CASE(does_not_error_transfer_payable_fallback)
}
}
)";
- CHECK_SUCCESS_NO_WARNINGS(text);
+ CHECK_WARNING(text, "Using contract member \"transfer\" inherited from the address type is deprecated.");
}
BOOST_AUTO_TEST_CASE(does_not_error_transfer_regular_function)
@@ -6792,11 +7358,14 @@ BOOST_AUTO_TEST_CASE(returndatacopy_as_variable)
char const* text = R"(
contract c { function f() public { uint returndatasize; assembly { returndatasize }}}
)";
- CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
+ vector<pair<Error::Type, std::string>> expectations(vector<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"}
- }));
+ {Error::Type::Warning, "The use of non-functional instructions is deprecated."},
+ {Error::Type::DeclarationError, "Unbalanced stack"}
+ });
+ if (!dev::test::Options::get().evmVersion().supportsReturndata())
+ expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible")));
+ CHECK_ALLOW_MULTI(text, expectations);
}
BOOST_AUTO_TEST_CASE(create2_as_variable)
@@ -6806,8 +7375,9 @@ BOOST_AUTO_TEST_CASE(create2_as_variable)
)";
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"}
+ {Error::Type::Warning, "The \"create2\" instruction is not supported by the VM version"},
+ {Error::Type::DeclarationError, "Unbalanced stack"},
+ {Error::Type::Warning, "not supposed to return values"}
}));
}
@@ -7101,6 +7671,50 @@ BOOST_AUTO_TEST_CASE(builtin_reject_gas)
CHECK_ERROR(text, TypeError, "Member \"gas\" not found or not visible after argument-dependent lookup");
}
+BOOST_AUTO_TEST_CASE(gasleft)
+{
+ char const* text = R"(
+ contract C {
+ function f() public view returns (uint256 val) { return msg.gas; }
+ }
+ )";
+ CHECK_WARNING(text, "\"msg.gas\" has been deprecated in favor of \"gasleft()\"");
+
+ text = R"(
+ contract C {
+ function f() public view returns (uint256 val) { return gasleft(); }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() public returns (uint256 val) { return msg.gas; }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "\"msg.gas\" has been deprecated in favor of \"gasleft()\"");
+}
+
+BOOST_AUTO_TEST_CASE(gasleft_shadowing)
+{
+ char const* text = R"(
+ contract C {
+ function gasleft() public pure returns (bytes32 val) { return "abc"; }
+ function f() public pure returns (bytes32 val) { return gasleft(); }
+ }
+ )";
+ CHECK_WARNING(text, "This declaration shadows a builtin symbol.");
+
+ text = R"(
+ contract C {
+ uint gasleft;
+ function f() public { gasleft = 42; }
+ }
+ )";
+ CHECK_WARNING(text, "This declaration shadows a builtin symbol.");
+}
+
BOOST_AUTO_TEST_CASE(builtin_reject_value)
{
char const* text = R"(
@@ -7362,7 +7976,7 @@ BOOST_AUTO_TEST_CASE(non_external_fallback)
function () external { }
}
)";
- CHECK_WARNING(text, "Experimental features are turned on.");
+ CHECK_SUCCESS_NO_WARNINGS(text);
text = R"(
pragma experimental "v0.5.0";
contract C {
@@ -7680,12 +8294,140 @@ BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
CHECK_ERROR(text, TypeError, "Operator / not compatible with types int_const 3 and int_const 0");
}
+BOOST_AUTO_TEST_CASE(warn_about_address_members_on_contract)
+{
+ std::string text = R"(
+ contract C {
+ function f() view public {
+ this.balance;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Using contract member \"balance\" inherited from the address type is deprecated.");
+ text = R"(
+ contract C {
+ function f() view public {
+ this.transfer;
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"transfer\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
+ text = R"(
+ contract C {
+ function f() view public {
+ this.send;
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"send\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
+ text = R"(
+ contract C {
+ function f() view public {
+ this.call;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Using contract member \"call\" inherited from the address type is deprecated.");
+ text = R"(
+ contract C {
+ function f() view public {
+ this.callcode;
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"callcode\" inherited from the address type is deprecated"},
+ {Error::Type::Warning, "\"callcode\" has been deprecated in favour of \"delegatecall\""}
+ }));
+ text = R"(
+ contract C {
+ function f() view public {
+ this.delegatecall;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Using contract member \"delegatecall\" inherited from the address type is deprecated.");
+}
+
+BOOST_AUTO_TEST_CASE(warn_about_address_members_on_non_this_contract)
+{
+ std::string text = R"(
+ contract C {
+ function f() view public {
+ C c;
+ c.balance;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Using contract member \"balance\" inherited from the address type is deprecated");
+ text = R"(
+ contract C {
+ function f() view public {
+ C c;
+ c.transfer;
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"transfer\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
+ text = R"(
+ contract C {
+ function f() view public {
+ C c;
+ c.send;
+ }
+ }
+ )";
+ CHECK_ALLOW_MULTI(text, (vector<pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Using contract member \"send\" inherited from the address type is deprecated"},
+ {Error::Type::TypeError, "Value transfer to a contract without a payable fallback function"}
+ }));
+ text = R"(
+ contract C {
+ function f() pure public {
+ C c;
+ c.call;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Using contract member \"call\" inherited from the address type is deprecated");
+ text = R"(
+ contract C {
+ function f() pure public {
+ C c;
+ c.callcode;
+ }
+ }
+ )";
+ CHECK_WARNING_ALLOW_MULTI(text, (std::vector<std::string>{
+ "Using contract member \"callcode\" inherited from the address type is deprecated",
+ "\"callcode\" has been deprecated in favour of \"delegatecall\""
+ }));
+ text = R"(
+ contract C {
+ function f() pure public {
+ C c;
+ c.delegatecall;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Using contract member \"delegatecall\" inherited from the address type is deprecated");
+}
+
BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
{
char const* text = R"(
pragma experimental "v0.5.0";
contract C {
- function f() {
+ function f() public {
this.balance;
}
}
@@ -7694,7 +8436,7 @@ BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
text = R"(
pragma experimental "v0.5.0";
contract C {
- function f() {
+ function f() public {
this.transfer;
}
}
@@ -7703,7 +8445,7 @@ BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
text = R"(
pragma experimental "v0.5.0";
contract C {
- function f() {
+ function f() public {
this.send;
}
}
@@ -7712,7 +8454,7 @@ BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
text = R"(
pragma experimental "v0.5.0";
contract C {
- function f() {
+ function f() public {
this.call;
}
}
@@ -7721,7 +8463,7 @@ BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
text = R"(
pragma experimental "v0.5.0";
contract C {
- function f() {
+ function f() public {
this.callcode;
}
}
@@ -7730,7 +8472,7 @@ BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
text = R"(
pragma experimental "v0.5.0";
contract C {
- function f() {
+ function f() public {
this.delegatecall;
}
}
@@ -7738,6 +8480,113 @@ BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
CHECK_ERROR(text, TypeError, "Member \"delegatecall\" not found or not visible after argument-dependent lookup in contract");
}
+BOOST_AUTO_TEST_CASE(no_warning_for_using_members_that_look_like_address_members)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function transfer(uint) public;
+ function f() public {
+ this.transfer(10);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(emit_events)
+{
+ char const* text = R"(
+ contract C {
+ event e();
+ function f() public {
+ emit e();
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ event e(uint a, string b);
+ function f() public {
+ emit e(2, "abc");
+ emit e({b: "abc", a: 8});
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract A { event e(uint a, string b); }
+ contract C is A {
+ function f() public {
+ emit A.e(2, "abc");
+ emit A.e({b: "abc", a: 8});
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(old_style_events_050)
+{
+ char const* text = R"(
+ contract C {
+ event e();
+ function f() public {
+ e();
+ }
+ }
+ )";
+ CHECK_WARNING(text, "without \"emit\" prefix");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ event e();
+ function f() public {
+ e();
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "have to be prefixed");
+}
+
+BOOST_AUTO_TEST_CASE(getter_is_memory_type)
+{
+ char const* text = R"(
+ contract C {
+ struct S { string m; }
+ string[] public x;
+ S[] public y;
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Check that the getters return a memory strings, not a storage strings.
+ ContractDefinition const& c = dynamic_cast<ContractDefinition const&>(*m_compiler.ast("").nodes().at(1));
+ BOOST_CHECK(c.interfaceFunctions().size() == 2);
+ for (auto const& f: c.interfaceFunctions())
+ {
+ auto const& retType = f.second->returnParameterTypes().at(0);
+ BOOST_CHECK(retType->dataStoredIn(DataLocation::Memory));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(require_visibility_specifiers)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure { }
+ }
+ )";
+ CHECK_WARNING(text, "No visibility specified. Defaulting to");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() pure { }
+ }
+ )";
+ CHECK_ERROR(text, SyntaxError, "No visibility specified.");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp
index fb09451f..49a725e0 100644
--- a/test/libsolidity/SolidityNatspecJSON.cpp
+++ b/test/libsolidity/SolidityNatspecJSON.cpp
@@ -22,7 +22,7 @@
#include "../TestHelper.h"
#include <string>
-#include <json/json.h>
+#include <libdevcore/JSON.h>
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/Exceptions.h>
#include <libdevcore/Exceptions.h>
@@ -47,6 +47,7 @@ public:
{
m_compilerStack.reset(false);
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
+ m_compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
Json::Value generatedDocumentation;
@@ -55,7 +56,7 @@ public:
else
generatedDocumentation = m_compilerStack.natspecDev(m_compilerStack.lastContractName());
Json::Value expectedDocumentation;
- m_reader.parse(_expectedDocumentationString, expectedDocumentation);
+ jsonParseStrict(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(
expectedDocumentation == generatedDocumentation,
"Expected:\n" << expectedDocumentation.toStyledString() <<
@@ -67,13 +68,13 @@ public:
{
m_compilerStack.reset(false);
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
+ m_compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!m_compilerStack.parseAndAnalyze());
BOOST_REQUIRE(Error::containsErrorOfType(m_compilerStack.errors(), Error::Type::DocstringParsingError));
}
private:
CompilerStack m_compilerStack;
- Json::Reader m_reader;
};
BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker)
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index bd635c33..33039ca9 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(constant_folding_both_sides)
}
})";
compileBothVersions(sourceCode);
- compareVersions("f(uint256)");
+ compareVersions("f(uint256)", 7);
}
BOOST_AUTO_TEST_CASE(storage_access)
@@ -190,7 +190,7 @@ BOOST_AUTO_TEST_CASE(storage_access)
}
)";
compileBothVersions(sourceCode);
- compareVersions("f(uint256)");
+ compareVersions("f(uint256)", 7);
}
BOOST_AUTO_TEST_CASE(array_copy)
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 861e6408..f03b30e1 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -1164,6 +1164,36 @@ BOOST_AUTO_TEST_CASE(constant_is_keyword)
CHECK_PARSE_ERROR(text, "Expected identifier");
}
+BOOST_AUTO_TEST_CASE(keyword_is_reserved)
+{
+ auto keywords = {
+ "abstract",
+ "after",
+ "case",
+ "catch",
+ "default",
+ "final",
+ "in",
+ "inline",
+ "let",
+ "match",
+ "null",
+ "of",
+ "relocatable",
+ "static",
+ "switch",
+ "try",
+ "type",
+ "typeof"
+ };
+
+ for (const auto& keyword: keywords)
+ {
+ auto text = std::string("contract ") + keyword + " {}";
+ CHECK_PARSE_ERROR(text.c_str(), "Expected identifier");
+ }
+}
+
BOOST_AUTO_TEST_CASE(var_array)
{
char const* text = R"(
@@ -1708,6 +1738,19 @@ BOOST_AUTO_TEST_CASE(newInvalidTypeName)
CHECK_PARSE_ERROR(text, "Expected explicit type name");
}
+BOOST_AUTO_TEST_CASE(emitWithoutEvent)
+{
+ char const* text = R"(
+ contract C {
+ event A();
+ function f() {
+ emit A;
+ }
+ }
+ )";
+ CHECK_PARSE_ERROR(text, "Expected token LParen got 'Semicolon'");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp
index 9f385a04..bc9f2fe1 100644
--- a/test/libsolidity/SolidityTypes.cpp
+++ b/test/libsolidity/SolidityTypes.cpp
@@ -88,6 +88,21 @@ BOOST_AUTO_TEST_CASE(storage_layout_arrays)
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(32), 9).storageSize() == 9);
}
+BOOST_AUTO_TEST_CASE(type_escaping)
+{
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier("("), "$_");
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier(")"), "_$");
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier(","), "_$_");
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier("$"), "$$$");
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier("()"), "$__$");
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier("(,)"), "$__$__$");
+ BOOST_CHECK_EQUAL(Type::escapeIdentifier("(,$,)"), "$__$_$$$_$__$");
+ BOOST_CHECK_EQUAL(
+ Type::escapeIdentifier("((__(_$_$$,__($$,,,$$),$,,,)))$$,$$"),
+ "$_$___$__$$$_$$$$$$_$___$_$$$$$$_$__$__$_$$$$$$_$_$_$$$_$__$__$__$_$_$$$$$$$_$_$$$$$$"
+ );
+}
+
BOOST_AUTO_TEST_CASE(type_identifiers)
{
ASTNode::resetID();
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index e48624e5..4c8918be 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -89,7 +89,7 @@ Json::Value compile(string const& _input)
StandardCompiler compiler;
string output = compiler.compile(_input);
Json::Value ret;
- BOOST_REQUIRE(Json::Reader().parse(output, ret, false));
+ BOOST_REQUIRE(jsonParseStrict(output, ret));
return ret;
}
@@ -110,11 +110,11 @@ BOOST_AUTO_TEST_CASE(assume_object_input)
/// Use the string interface of StandardCompiler to trigger these
result = compile("");
- BOOST_CHECK(containsError(result, "JSONError", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n"));
+ BOOST_CHECK(containsError(result, "JSONError", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n* Line 1, Column 1\n A valid JSON document must be either an array or an object value.\n"));
result = compile("invalid");
- BOOST_CHECK(containsError(result, "JSONError", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n"));
+ BOOST_CHECK(containsError(result, "JSONError", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n* Line 1, Column 2\n Extra non-whitespace after JSON value.\n"));
result = compile("\"invalid\"");
- BOOST_CHECK(containsError(result, "JSONError", "Input is not a JSON object."));
+ BOOST_CHECK(containsError(result, "JSONError", "* Line 1, Column 1\n A valid JSON document must be either an array or an object value.\n"));
BOOST_CHECK(!containsError(result, "JSONError", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n"));
result = compile("{}");
BOOST_CHECK(!containsError(result, "JSONError", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n"));
@@ -154,6 +154,61 @@ BOOST_AUTO_TEST_CASE(no_sources)
BOOST_CHECK(containsError(result, "JSONError", "No input sources specified."));
}
+BOOST_AUTO_TEST_CASE(no_sources_empty_object)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "sources": {}
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "No input sources specified."));
+}
+
+BOOST_AUTO_TEST_CASE(no_sources_empty_array)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "sources": []
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "\"sources\" is not a JSON object."));
+}
+
+BOOST_AUTO_TEST_CASE(sources_is_array)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "sources": ["aa", "bb"]
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "\"sources\" is not a JSON object."));
+}
+
+BOOST_AUTO_TEST_CASE(unexpected_trailing_test)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "sources": {
+ "A": {
+ "content": "contract A { function f() {} }"
+ }
+ }
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "* Line 10, Column 2\n Extra non-whitespace after JSON value.\n"));
+}
+
+
BOOST_AUTO_TEST_CASE(smoke_test)
{
char const* input = R"(
@@ -515,6 +570,196 @@ BOOST_AUTO_TEST_CASE(library_filename_with_colon)
BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"][0].isObject());
}
+BOOST_AUTO_TEST_CASE(libraries_invalid_top_level)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "libraries": "42"
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "\"libraries\" is not a JSON object."));
+}
+
+BOOST_AUTO_TEST_CASE(libraries_invalid_entry)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "libraries": {
+ "L": "42"
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "library entry is not a JSON object."));
+}
+
+BOOST_AUTO_TEST_CASE(libraries_invalid_hex)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "libraries": {
+ "library.sol": {
+ "L": "0x4200000000000000000000000000000000000xx1"
+ }
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "Invalid library address (\"0x4200000000000000000000000000000000000xx1\") supplied."));
+}
+
+BOOST_AUTO_TEST_CASE(libraries_invalid_length)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "libraries": {
+ "library.sol": {
+ "L1": "0x42",
+ "L2": "0x4200000000000000000000000000000000000001ff"
+ }
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "Library address is of invalid length."));
+}
+
+BOOST_AUTO_TEST_CASE(libraries_missing_hex_prefix)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "libraries": {
+ "library.sol": {
+ "L": "4200000000000000000000000000000000000001"
+ }
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "Library address is not prefixed with \"0x\"."));
+}
+
+BOOST_AUTO_TEST_CASE(library_linking)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "libraries": {
+ "library.sol": {
+ "L": "0x4200000000000000000000000000000000000001"
+ }
+ },
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "evm.bytecode"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "import \"library.sol\"; import \"library2.sol\"; contract A { function f() returns (uint) { L2.g(); return L.g(); } }"
+ },
+ "library.sol": {
+ "content": "library L { function g() returns (uint) { return 1; } }"
+ },
+ "library2.sol": {
+ "content": "library L2 { function g() { } }"
+ }
+ }
+ }
+ )";
+ 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"]["library.sol"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"].isArray());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"][0].isObject());
+}
+
+BOOST_AUTO_TEST_CASE(evm_version)
+{
+ auto inputForVersion = [](string const& _version)
+ {
+ return R"(
+ {
+ "language": "Solidity",
+ "sources": { "fileA": { "content": "contract A { }" } },
+ "settings": {
+ )" + _version + R"(
+ "outputSelection": {
+ "fileA": {
+ "A": [ "metadata" ]
+ }
+ }
+ }
+ }
+ )";
+ };
+ Json::Value result;
+ result = compile(inputForVersion("\"evmVersion\": \"homestead\","));
+ BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"homestead\"") != string::npos);
+ result = compile(inputForVersion("\"evmVersion\": \"tangerineWhistle\","));
+ BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"tangerineWhistle\"") != string::npos);
+ result = compile(inputForVersion("\"evmVersion\": \"spuriousDragon\","));
+ BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"spuriousDragon\"") != string::npos);
+ result = compile(inputForVersion("\"evmVersion\": \"byzantium\","));
+ BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"byzantium\"") != string::npos);
+ // test default
+ result = compile(inputForVersion(""));
+ BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"byzantium\"") != string::npos);
+ // test invalid
+ result = compile(inputForVersion("\"evmVersion\": \"invalid\","));
+ BOOST_CHECK(result["errors"][0]["message"].asString() == "Invalid EVM version requested.");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
index 3a03c877..26ff461c 100644
--- a/test/libsolidity/ViewPureChecker.cpp
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -20,6 +20,8 @@
#include <test/libsolidity/AnalysisFramework.h>
+#include <test/TestHelper.h>
+
#include <boost/test/unit_test.hpp>
#include <string>
@@ -109,6 +111,7 @@ BOOST_AUTO_TEST_CASE(environment_access)
"block.difficulty",
"block.number",
"block.gaslimit",
+ "gasleft()",
"msg.gas",
"msg.value",
"msg.sender",
@@ -148,7 +151,7 @@ BOOST_AUTO_TEST_CASE(environment_access)
BOOST_AUTO_TEST_CASE(view_error_for_050)
{
CHECK_ERROR(
- "pragma experimental \"v0.5.0\"; contract C { uint x; function f() view { x = 2; } }",
+ "pragma experimental \"v0.5.0\"; contract C { uint x; function f() view public { x = 2; } }",
TypeError,
"Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable."
);
@@ -277,11 +280,11 @@ BOOST_AUTO_TEST_CASE(builtin_functions)
string text = R"(
contract C {
function f() public {
- this.transfer(1);
- require(this.send(2));
- selfdestruct(this);
- require(this.delegatecall());
- require(this.call());
+ address(this).transfer(1);
+ require(address(this).send(2));
+ selfdestruct(address(this));
+ require(address(this).delegatecall());
+ require(address(this).call());
}
function g() pure public {
bytes32 x = keccak256("abc");
@@ -423,7 +426,10 @@ BOOST_AUTO_TEST_CASE(assembly_staticcall)
}
}
)";
- CHECK_WARNING(text, "only available after the Metropolis");
+ if (!dev::test::Options::get().evmVersion().hasStaticCall())
+ CHECK_WARNING(text, "\"staticcall\" instruction is only available for Byzantium-compatible");
+ else
+ CHECK_SUCCESS_NO_WARNINGS(text);
}
BOOST_AUTO_TEST_CASE(assembly_jump)