aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'test/libsolidity')
-rw-r--r--test/libsolidity/ASTJSON.cpp21
-rw-r--r--test/libsolidity/AnalysisFramework.cpp3
-rw-r--r--test/libsolidity/Assembly.cpp17
-rw-r--r--test/libsolidity/GasMeter.cpp11
-rw-r--r--test/libsolidity/Imports.cpp27
-rw-r--r--test/libsolidity/InlineAssembly.cpp14
-rw-r--r--test/libsolidity/JSONCompiler.cpp4
-rw-r--r--test/libsolidity/Metadata.cpp8
-rw-r--r--test/libsolidity/SMTChecker.cpp144
-rw-r--r--test/libsolidity/SemVerMatcher.cpp2
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp4
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp204
-rw-r--r--test/libsolidity/SolidityExecutionFramework.h15
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp58
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp749
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp4
-rw-r--r--test/libsolidity/SolidityParser.cpp34
-rw-r--r--test/libsolidity/StandardCompiler.cpp192
-rw-r--r--test/libsolidity/SyntaxTest.cpp209
-rw-r--r--test/libsolidity/SyntaxTest.h77
-rw-r--r--test/libsolidity/ViewPureChecker.cpp20
-rw-r--r--test/libsolidity/syntaxTests/docstring_empty_description.sol6
-rw-r--r--test/libsolidity/syntaxTests/double_stateVariable_declaration.sol6
-rw-r--r--test/libsolidity/syntaxTests/double_variable_declaration.sol8
-rw-r--r--test/libsolidity/syntaxTests/double_variable_declaration_050.sol11
-rw-r--r--test/libsolidity/syntaxTests/smoke_test.sol6
-rw-r--r--test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol14
-rw-r--r--test/libsolidity/syntaxTests/visibility/external_library_function.sol14
28 files changed, 1785 insertions, 97 deletions
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp
index a165f7a9..b44dd331 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/Options.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;
@@ -244,6 +260,7 @@ BOOST_AUTO_TEST_CASE(documentation)
" /** Some comment on fn.*/ function fn() public {}"
"}"
);
+ c.setEVMVersion(dev::test::Options::get().evmVersion());
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 0;
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index a27e3222..4538757d 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -20,6 +20,8 @@
#include <test/libsolidity/AnalysisFramework.h>
+#include <test/Options.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..5519ae0d 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/Options.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 9d3409dd..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)
diff --git a/test/libsolidity/Imports.cpp b/test/libsolidity/Imports.cpp
index dc1174f4..1b5dd4a5 100644
--- a/test/libsolidity/Imports.cpp
+++ b/test/libsolidity/Imports.cpp
@@ -21,6 +21,7 @@
*/
#include <test/libsolidity/ErrorCheck.h>
+#include <test/Options.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.
@@ -274,6 +300,7 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_alias)
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.
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index ea120657..34ca33e3 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -20,7 +20,7 @@
* Unit tests for inline assembly.
*/
-#include "../TestHelper.h"
+#include <test/Options.h>
#include <libsolidity/interface/AssemblyStack.h>
#include <libsolidity/parsing/Scanner.h>
@@ -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()));
@@ -567,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);
@@ -783,9 +783,9 @@ BOOST_AUTO_TEST_CASE(shift)
BOOST_AUTO_TEST_CASE(shift_constantinople_warning)
{
- CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", Warning, "The \"shl\" instruction is only available after the Constantinople hard fork");
- CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", Warning, "The \"shr\" instruction is only available after the Constantinople hard fork");
- CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", Warning, "The \"sar\" instruction is only available after the Constantinople hard fork");
+ 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)
diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp
index 285c5604..aed0a370 100644
--- a/test/libsolidity/JSONCompiler.cpp
+++ b/test/libsolidity/JSONCompiler.cpp
@@ -25,8 +25,8 @@
#include <libsolidity/interface/Version.h>
#include <libsolc/libsolc.h>
-#include "../Metadata.h"
-#include "../TestHelper.h"
+#include <test/Metadata.h>
+#include <test/Options.h>
using namespace std;
diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp
index 47cf1d3d..808bd1e1 100644
--- a/test/libsolidity/Metadata.cpp
+++ b/test/libsolidity/Metadata.cpp
@@ -19,8 +19,8 @@
* Unit tests for the metadata output.
*/
-#include "../Metadata.h"
-#include "../TestHelper.h"
+#include <test/Metadata.h>
+#include <test/Options.h>
#include <libsolidity/interface/CompilerStack.h>
#include <libdevcore/SwarmHash.h>
#include <libdevcore/JSON.h>
@@ -46,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;
@@ -72,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;
@@ -106,6 +108,7 @@ 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");
@@ -144,6 +147,7 @@ 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");
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index 5088ab94..beb933a4 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -329,6 +329,144 @@ BOOST_AUTO_TEST_CASE(ways_to_merge_variables)
CHECK_WARNING(text, "Assertion violation happens here");
}
+BOOST_AUTO_TEST_CASE(bool_simple)
+{
+ string text = R"(
+ contract C {
+ function f(bool x) public pure {
+ assert(x);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Assertion violation happens here");
+ text = R"(
+ contract C {
+ function f(bool x, bool y) public pure {
+ assert(x == y);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Assertion violation happens here");
+ text = R"(
+ contract C {
+ function f(bool x, bool y) public pure {
+ bool z = x || y;
+ assert(!(x && y) || z);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x) public pure {
+ if(x) {
+ assert(x);
+ } else {
+ assert(!x);
+ }
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x) public pure {
+ bool y = x;
+ assert(x == y);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x) public pure {
+ require(x);
+ bool y;
+ y = false;
+ assert(x || y);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x) public pure {
+ bool y;
+ assert(x <= y);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Assertion violation happens here");
+ text = R"(
+ contract C {
+ function f(bool x) public pure {
+ bool y;
+ assert(x >= y);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x) public pure {
+ require(x);
+ bool y;
+ assert(x > y);
+ assert(y < x);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(bool_int_mixed)
+{
+ string text = R"(
+ contract C {
+ function f(bool x) public pure {
+ uint a;
+ if(x)
+ a = 1;
+ assert(!x || a > 0);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x, uint a) public pure {
+ require(!x || a > 0);
+ uint b = a;
+ assert(!x || b > 0);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(bool x, bool y) public pure {
+ uint a;
+ if (x) {
+ if (y) {
+ a = 0;
+ } else {
+ a = 1;
+ }
+ } else {
+ if (y) {
+ a = 1;
+ } else {
+ a = 0;
+ }
+ }
+ bool xor_x_y = (x && !y) || (!x && y);
+ assert(!xor_x_y || a > 0);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(while_loop_simple)
{
// Check that variables are cleared
@@ -466,7 +604,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);
@@ -477,7 +616,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/SemVerMatcher.cpp b/test/libsolidity/SemVerMatcher.cpp
index 08ef5277..07f8fba6 100644
--- a/test/libsolidity/SemVerMatcher.cpp
+++ b/test/libsolidity/SemVerMatcher.cpp
@@ -25,7 +25,7 @@
#include <tuple>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/analysis/SemVerHandler.h>
-#include "../TestHelper.h"
+#include <test/Options.h>
using namespace std;
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index e242508a..107abc26 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output.
*/
-#include "../TestHelper.h"
+#include <test/Options.h>
#include <libsolidity/interface/CompilerStack.h>
#include <libdevcore/Exceptions.h>
@@ -44,6 +44,8 @@ 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());
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 3882e4ea..44dc40f7 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/Options.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"(
@@ -1733,6 +1788,23 @@ BOOST_AUTO_TEST_CASE(transfer_ether)
ABI_CHECK(callContractFunction("b(address,uint256)", oogRecipient, 10), encodeArgs());
}
+BOOST_AUTO_TEST_CASE(uncalled_blockhash)
+{
+ char const* code = R"(
+ contract C {
+ function f() public view returns (bytes32)
+ {
+ var x = block.blockhash;
+ return x(block.number - 1);
+ }
+ }
+ )";
+ compileAndRun(code, 0, "C");
+ bytes result = callContractFunction("f()");
+ BOOST_REQUIRE_EQUAL(result.size(), 32);
+ BOOST_CHECK(result[0] != 0 || result[1] != 0 || result[2] != 0);
+}
+
BOOST_AUTO_TEST_CASE(log0)
{
char const* sourceCode = R"(
@@ -2824,6 +2896,58 @@ BOOST_AUTO_TEST_CASE(function_modifier_multiple_times_local_vars)
ABI_CHECK(callContractFunction("a()"), encodeArgs(0));
}
+BOOST_AUTO_TEST_CASE(function_modifier_library)
+{
+ char const* sourceCode = R"(
+ library L {
+ struct S { uint v; }
+ modifier mod(S storage s) { s.v++; _; }
+ function libFun(S storage s) mod(s) internal { s.v += 0x100; }
+ }
+
+ contract Test {
+ using L for *;
+ L.S s;
+
+ function f() public returns (uint) {
+ s.libFun();
+ L.libFun(s);
+ return s.v;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202));
+}
+
+BOOST_AUTO_TEST_CASE(function_modifier_library_inheritance)
+{
+ // Tests that virtual lookup for modifiers in libraries does not consider
+ // the current inheritance hierarchy.
+
+ char const* sourceCode = R"(
+ library L {
+ struct S { uint v; }
+ modifier mod(S storage s) { s.v++; _; }
+ function libFun(S storage s) mod(s) internal { s.v += 0x100; }
+ }
+
+ contract Test {
+ using L for *;
+ L.S s;
+ modifier mod(L.S storage) { revert(); _; }
+
+ function f() public returns (uint) {
+ s.libFun();
+ L.libFun(s);
+ return s.v;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202));
+}
+
BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack)
{
char const* sourceCode = R"(
@@ -5304,6 +5428,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"(
@@ -6888,6 +7024,21 @@ BOOST_AUTO_TEST_CASE(library_call)
ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(33) * 9));
}
+BOOST_AUTO_TEST_CASE(library_function_external)
+{
+ char const* sourceCode = R"(
+ library Lib { function m(bytes b) external pure returns (byte) { return b[2]; } }
+ contract Test {
+ function f(bytes b) public pure returns (byte) {
+ return Lib.m(b);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "Lib");
+ compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
+ ABI_CHECK(callContractFunction("f(bytes)", u256(0x20), u256(5), "abcde"), encodeArgs("c"));
+}
+
BOOST_AUTO_TEST_CASE(library_stray_values)
{
char const* sourceCode = R"(
@@ -10718,6 +10869,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 b853d558..12687dd1 100644
--- a/test/libsolidity/SolidityExecutionFramework.h
+++ b/test/libsolidity/SolidityExecutionFramework.h
@@ -52,11 +52,23 @@ 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())
{
@@ -72,8 +84,7 @@ public:
}
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..c8adfc6e 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -30,7 +30,7 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/interface/ErrorReporter.h>
-#include "../TestHelper.h"
+#include <test/Options.h>
using namespace std;
@@ -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 be147e48..c757037c 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -22,6 +22,8 @@
#include <test/libsolidity/AnalysisFramework.h>
+#include <test/Options.h>
+
#include <libsolidity/ast/AST.h>
#include <libdevcore/SHA3.h>
@@ -41,50 +43,216 @@ namespace test
BOOST_FIXTURE_TEST_SUITE(SolidityNameAndTypeResolution, AnalysisFramework)
-BOOST_AUTO_TEST_CASE(smoke_test)
+
+BOOST_AUTO_TEST_CASE(double_function_declaration)
{
char const* text = R"(
contract test {
- uint256 stateVariable1;
- function fun(uint256 arg1) public { uint256 y; y = arg1; }
+ function fun() public { }
+ function fun() public { }
}
)";
- CHECK_SUCCESS(text);
+ CHECK_ERROR(text, DeclarationError, "Function with same name and arguments defined twice.");
}
-BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
+BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope)
{
- char const* text = R"(
+ string text = R"(
contract test {
- uint256 variable;
- uint128 variable;
+ function f() pure public {
+ { uint x; }
+ { uint x; }
+ }
}
)";
- CHECK_ERROR(text, DeclarationError, "Identifier already declared.");
+ CHECK_ERROR(text, DeclarationError, "Identifier already declared");
}
-BOOST_AUTO_TEST_CASE(double_function_declaration)
+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 fun() public { }
- function fun() public { }
+ function f() pure public {
+ x = 4;
+ uint256 x = 2;
+ }
}
)";
- CHECK_ERROR(text, DeclarationError, "Function with same name and arguments defined twice.");
+ CHECK_SUCCESS_NO_WARNINGS(text);
}
-BOOST_AUTO_TEST_CASE(double_variable_declaration)
+BOOST_AUTO_TEST_CASE(scoping)
{
char const* text = R"(
+ pragma experimental "v0.5.0";
contract test {
function f() public {
- uint256 x;
- if (true) { uint256 x; }
+ {
+ uint256 x;
+ }
+ x = 2;
}
}
)";
- CHECK_ERROR(text, DeclarationError, "Identifier already declared.");
+ 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 +926,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 +1228,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 +1263,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 +2720,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"(
@@ -5639,10 +5894,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) }
}
}
)";
@@ -5652,6 +5908,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;
@@ -5660,7 +5917,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
}
_;
}
- function f() m {
+ function f() public m {
}
}
)";
@@ -5670,6 +5927,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 {
@@ -5685,6 +5943,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 {
@@ -5693,7 +5952,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers)
}
_;
}
- function f() m {
+ function f() public m {
}
}
)";
@@ -5703,6 +5962,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 {
@@ -5718,6 +5978,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 {
@@ -5733,6 +5994,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;
@@ -5748,6 +6010,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 {
@@ -5764,6 +6027,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 {
@@ -5794,6 +6058,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_constant_variable_via_offset)
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 {
@@ -5805,6 +6070,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"(
@@ -6757,6 +7198,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 {}
@@ -6770,12 +7213,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 {
@@ -6786,12 +7234,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 {}
}
@@ -6804,11 +7257,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 {}
@@ -6822,7 +7280,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)
@@ -6848,11 +7306,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)
@@ -6862,8 +7323,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"}
}));
}
@@ -7157,6 +7619,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"(
@@ -7418,7 +7924,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 {
@@ -7736,12 +8242,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;
}
}
@@ -7750,7 +8384,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;
}
}
@@ -7759,7 +8393,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;
}
}
@@ -7768,7 +8402,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;
}
}
@@ -7777,7 +8411,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;
}
}
@@ -7786,7 +8420,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;
}
}
@@ -7794,6 +8428,20 @@ 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"(
@@ -7870,6 +8518,23 @@ BOOST_AUTO_TEST_CASE(getter_is_memory_type)
}
}
+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 e8906bb9..eeebeb74 100644
--- a/test/libsolidity/SolidityNatspecJSON.cpp
+++ b/test/libsolidity/SolidityNatspecJSON.cpp
@@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output.
*/
-#include "../TestHelper.h"
+#include <test/Options.h>
#include <string>
#include <libdevcore/JSON.h>
#include <libsolidity/interface/CompilerStack.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;
@@ -67,6 +68,7 @@ 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));
}
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index b7097d0f..4e862f60 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -25,8 +25,8 @@
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h>
#include <libsolidity/interface/ErrorReporter.h>
-#include "../TestHelper.h"
-#include "ErrorCheck.h"
+#include <test/Options.h>
+#include <test/libsolidity/ErrorCheck.h>
using namespace std;
@@ -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"(
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 404f709d..dd6eb7c4 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -570,6 +570,198 @@ 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);
+ result = compile(inputForVersion("\"evmVersion\": \"constantinople\","));
+ BOOST_CHECK(result["contracts"]["fileA"]["A"]["metadata"].asString().find("\"evmVersion\":\"constantinople\"") != 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/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp
new file mode 100644
index 00000000..45a851b6
--- /dev/null
+++ b/test/libsolidity/SyntaxTest.cpp
@@ -0,0 +1,209 @@
+/*
+ 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/>.
+*/
+
+#include <test/libsolidity/SyntaxTest.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/throw_exception.hpp>
+#include <cctype>
+#include <fstream>
+#include <memory>
+#include <stdexcept>
+
+using namespace dev;
+using namespace solidity;
+using namespace dev::solidity::test;
+using namespace std;
+namespace fs = boost::filesystem;
+using namespace boost::unit_test;
+
+template<typename IteratorType>
+void skipWhitespace(IteratorType& it, IteratorType end)
+{
+ while (it != end && isspace(*it))
+ ++it;
+}
+
+template<typename IteratorType>
+void skipSlashes(IteratorType& it, IteratorType end)
+{
+ while (it != end && *it == '/')
+ ++it;
+}
+
+SyntaxTest::SyntaxTest(string const& _filename)
+{
+ ifstream file(_filename);
+ if (!file)
+ BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
+ file.exceptions(ios::badbit);
+
+ m_source = parseSource(file);
+ m_expectations = parseExpectations(file);
+}
+
+bool SyntaxTest::run(ostream& _stream, string const& _indent)
+{
+ m_errorList = parseAnalyseAndReturnError(m_source, true, true, true).second;
+ if (!matchesExpectations(m_errorList))
+ {
+ std::string nextIndentLevel = _indent + "\t";
+ _stream << _indent << "Expected result:" << endl;
+ printExpected(_stream, nextIndentLevel);
+ _stream << _indent << "Obtained result:\n";
+ printErrorList(_stream, m_errorList, nextIndentLevel);
+ return false;
+ }
+ return true;
+}
+
+void SyntaxTest::printExpected(ostream& _stream, string const& _indent) const
+{
+ if (m_expectations.empty())
+ _stream << _indent << "Success" << endl;
+ else
+ for (auto const& expectation: m_expectations)
+ _stream << _indent << expectation.type << ": " << expectation.message << endl;
+}
+
+void SyntaxTest::printErrorList(
+ ostream& _stream,
+ ErrorList const& _errorList,
+ string const& _indent
+) const
+{
+ if (_errorList.empty())
+ _stream << _indent << "Success" << endl;
+ else
+ for (auto const& error: _errorList)
+ _stream << _indent << error->typeName() << ": " << errorMessage(*error) << endl;
+}
+
+bool SyntaxTest::matchesExpectations(ErrorList const& _errorList) const
+{
+ if (_errorList.size() != m_expectations.size())
+ return false;
+ else
+ for (size_t i = 0; i < _errorList.size(); i++)
+ if (
+ (_errorList[i]->typeName() != m_expectations[i].type) ||
+ (errorMessage(*_errorList[i]) != m_expectations[i].message)
+ )
+ return false;
+ return true;
+}
+
+string SyntaxTest::errorMessage(Error const& _e)
+{
+ if (_e.comment())
+ return boost::replace_all_copy(*_e.comment(), "\n", "\\n");
+ else
+ return "NONE";
+}
+
+string SyntaxTest::parseSource(istream& _stream)
+{
+ string source;
+ string line;
+ string const delimiter("// ----");
+ while (getline(_stream, line))
+ if (boost::algorithm::starts_with(line, delimiter))
+ break;
+ else
+ source += line + "\n";
+ return source;
+}
+
+vector<SyntaxTestExpectation> SyntaxTest::parseExpectations(istream& _stream)
+{
+ vector<SyntaxTestExpectation> expectations;
+ string line;
+ while (getline(_stream, line))
+ {
+ auto it = line.begin();
+
+ skipSlashes(it, line.end());
+ skipWhitespace(it, line.end());
+
+ if (it == line.end()) continue;
+
+ auto typeBegin = it;
+ while (it != line.end() && *it != ':')
+ ++it;
+ string errorType(typeBegin, it);
+
+ // skip colon
+ if (it != line.end()) it++;
+
+ skipWhitespace(it, line.end());
+
+ string errorMessage(it, line.end());
+ expectations.emplace_back(SyntaxTestExpectation{move(errorType), move(errorMessage)});
+ }
+ return expectations;
+}
+
+#if BOOST_VERSION < 105900
+test_case *make_test_case(
+ function<void()> const& _fn,
+ string const& _name,
+ string const& /* _filename */,
+ size_t /* _line */
+)
+{
+ return make_test_case(_fn, _name);
+}
+#endif
+
+int SyntaxTest::registerTests(
+ boost::unit_test::test_suite& _suite,
+ boost::filesystem::path const& _basepath,
+ boost::filesystem::path const& _path
+)
+{
+ int numTestsAdded = 0;
+ fs::path fullpath = _basepath / _path;
+ if (fs::is_directory(fullpath))
+ {
+ test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string());
+ for (auto const& entry: boost::iterator_range<fs::directory_iterator>(
+ fs::directory_iterator(fullpath),
+ fs::directory_iterator()
+ ))
+ numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename());
+ _suite.add(sub_suite);
+ }
+ else
+ {
+ static vector<unique_ptr<string>> filenames;
+
+ filenames.emplace_back(new string(_path.string()));
+ _suite.add(make_test_case(
+ [fullpath]
+ {
+ std::stringstream errorStream;
+ if (!SyntaxTest(fullpath.string()).run(errorStream, ""))
+ BOOST_ERROR("Test expectation mismatch.\n" + errorStream.str());
+ },
+ _path.stem().string(),
+ *filenames.back(),
+ 0
+ ));
+ numTestsAdded = 1;
+ }
+ return numTestsAdded;
+}
diff --git a/test/libsolidity/SyntaxTest.h b/test/libsolidity/SyntaxTest.h
new file mode 100644
index 00000000..4379c77b
--- /dev/null
+++ b/test/libsolidity/SyntaxTest.h
@@ -0,0 +1,77 @@
+/*
+ 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/>.
+*/
+
+#pragma once
+
+#include <test/libsolidity/AnalysisFramework.h>
+#include <libsolidity/interface/Exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <utility>
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+struct SyntaxTestExpectation
+{
+ std::string type;
+ std::string message;
+};
+
+
+class SyntaxTest: AnalysisFramework
+{
+public:
+ SyntaxTest(std::string const& _filename);
+
+ bool run(std::ostream& _stream, std::string const& _indent);
+
+ void printExpected(std::ostream& _stream, std::string const& _indent) const;
+ void printErrorList(
+ std::ostream& _stream,
+ ErrorList const& _errors,
+ std::string const& _indent
+ ) const;
+
+ static int registerTests(
+ boost::unit_test::test_suite& _suite,
+ boost::filesystem::path const& _basepath,
+ boost::filesystem::path const& _path
+ );
+private:
+ bool matchesExpectations(ErrorList const& _errors) const;
+ static std::string errorMessage(Error const& _e);
+ static std::string parseSource(std::istream& _stream);
+ static std::vector<SyntaxTestExpectation> parseExpectations(std::istream& _stream);
+
+ std::string m_source;
+ std::vector<SyntaxTestExpectation> m_expectations;
+ ErrorList m_errorList;
+};
+
+}
+}
+}
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
index 3a03c877..a6ce6d91 100644
--- a/test/libsolidity/ViewPureChecker.cpp
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -20,6 +20,8 @@
#include <test/libsolidity/AnalysisFramework.h>
+#include <test/Options.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)
diff --git a/test/libsolidity/syntaxTests/docstring_empty_description.sol b/test/libsolidity/syntaxTests/docstring_empty_description.sol
new file mode 100644
index 00000000..0caa1b23
--- /dev/null
+++ b/test/libsolidity/syntaxTests/docstring_empty_description.sol
@@ -0,0 +1,6 @@
+contract C {
+ /// @param id
+ function vote(uint id) public;
+}
+// ----
+// DocstringParsingError: No description given for param id
diff --git a/test/libsolidity/syntaxTests/double_stateVariable_declaration.sol b/test/libsolidity/syntaxTests/double_stateVariable_declaration.sol
new file mode 100644
index 00000000..c5507b64
--- /dev/null
+++ b/test/libsolidity/syntaxTests/double_stateVariable_declaration.sol
@@ -0,0 +1,6 @@
+contract test {
+ uint256 variable;
+ uint128 variable;
+}
+// ----
+// DeclarationError: Identifier already declared.
diff --git a/test/libsolidity/syntaxTests/double_variable_declaration.sol b/test/libsolidity/syntaxTests/double_variable_declaration.sol
new file mode 100644
index 00000000..3349cfec
--- /dev/null
+++ b/test/libsolidity/syntaxTests/double_variable_declaration.sol
@@ -0,0 +1,8 @@
+contract test {
+ function f() pure public {
+ uint256 x;
+ if (true) { uint256 x; }
+ }
+}
+// ----
+// DeclarationError: Identifier already declared.
diff --git a/test/libsolidity/syntaxTests/double_variable_declaration_050.sol b/test/libsolidity/syntaxTests/double_variable_declaration_050.sol
new file mode 100644
index 00000000..9c2d40d5
--- /dev/null
+++ b/test/libsolidity/syntaxTests/double_variable_declaration_050.sol
@@ -0,0 +1,11 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ uint256 x;
+ if (true) { uint256 x; }
+ }
+}
+// ----
+// Warning: This declaration shadows an existing declaration.
+// Warning: Unused local variable.
+// Warning: Unused local variable.
diff --git a/test/libsolidity/syntaxTests/smoke_test.sol b/test/libsolidity/syntaxTests/smoke_test.sol
new file mode 100644
index 00000000..2d48098a
--- /dev/null
+++ b/test/libsolidity/syntaxTests/smoke_test.sol
@@ -0,0 +1,6 @@
+contract test {
+ uint256 stateVariable1;
+ function fun(uint256 arg1) public { uint256 y; y = arg1; }
+}
+// ----
+// Warning: Function state mutability can be restricted to pure
diff --git a/test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol b/test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol
new file mode 100644
index 00000000..b033fd0c
--- /dev/null
+++ b/test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol
@@ -0,0 +1,14 @@
+library WithModifier {
+ modifier mod() { require(msg.value > 10 ether); _; }
+ function withMod(uint self) mod() internal view { require(self > 0); }
+}
+
+contract Test {
+ using WithModifier for *;
+
+ function f(uint _value) public payable {
+ _value.withMod();
+ WithModifier.withMod(_value);
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/visibility/external_library_function.sol b/test/libsolidity/syntaxTests/visibility/external_library_function.sol
new file mode 100644
index 00000000..110e74db
--- /dev/null
+++ b/test/libsolidity/syntaxTests/visibility/external_library_function.sol
@@ -0,0 +1,14 @@
+library L {
+ function f(uint) pure external {}
+}
+
+contract C {
+ using L for *;
+
+ function f() public pure {
+ L.f(2);
+ uint x;
+ x.f();
+ }
+}
+// ----