Merge pull request #7278 from ethereum/develop

Merge develop into develop_060
This commit is contained in:
Mathias L. Baumann
2019-08-26 10:26:48 +02:00
committed by GitHub
66 changed files with 985 additions and 493 deletions
@@ -0,0 +1,233 @@
{
"absolutePath" : "a",
"exportedSymbols" :
{
"A" :
[
1
],
"B" :
[
4
],
"C" :
[
7
],
"D" :
[
10
],
"E" :
[
13
]
},
"id" : 14,
"nodeType" : "SourceUnit",
"nodes" :
[
{
"baseContracts" : [],
"contractDependencies" : [],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 1,
"linearizedBaseContracts" :
[
1
],
"name" : "A",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "0:14:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 2,
"name" : "A",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 1,
"src" : "29:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_A_$1",
"typeString" : "contract A"
}
},
"id" : 3,
"nodeType" : "InheritanceSpecifier",
"src" : "29:1:1"
}
],
"contractDependencies" :
[
1
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 4,
"linearizedBaseContracts" :
[
4,
1
],
"name" : "B",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "15:19:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 5,
"name" : "B",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 4,
"src" : "49:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_B_$4",
"typeString" : "contract B"
}
},
"id" : 6,
"nodeType" : "InheritanceSpecifier",
"src" : "49:1:1"
}
],
"contractDependencies" :
[
1,
4
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 7,
"linearizedBaseContracts" :
[
7,
4,
1
],
"name" : "C",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "35:19:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 8,
"name" : "C",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 7,
"src" : "69:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_C_$7",
"typeString" : "contract C"
}
},
"id" : 9,
"nodeType" : "InheritanceSpecifier",
"src" : "69:1:1"
}
],
"contractDependencies" :
[
1,
4,
7
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 10,
"linearizedBaseContracts" :
[
10,
7,
4,
1
],
"name" : "D",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "55:19:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 11,
"name" : "D",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 10,
"src" : "89:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_D_$10",
"typeString" : "contract D"
}
},
"id" : 12,
"nodeType" : "InheritanceSpecifier",
"src" : "89:1:1"
}
],
"contractDependencies" :
[
1,
4,
7,
10
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 13,
"linearizedBaseContracts" :
[
13,
10,
7,
4,
1
],
"name" : "E",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "75:19:1"
}
],
"src" : "0:95:1"
}
@@ -0,0 +1,7 @@
contract A { }
contract B is A { }
contract C is B { }
contract D is C { }
contract E is D { }
// ----
@@ -0,0 +1,288 @@
{
"attributes" :
{
"absolutePath" : "a",
"exportedSymbols" :
{
"A" :
[
1
],
"B" :
[
4
],
"C" :
[
7
],
"D" :
[
10
],
"E" :
[
13
]
}
},
"children" :
[
{
"attributes" :
{
"baseContracts" :
[
null
],
"contractDependencies" :
[
null
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
1
],
"name" : "A",
"nodes" :
[
null
],
"scope" : 14
},
"id" : 1,
"name" : "ContractDefinition",
"src" : "0:14:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
4,
1
],
"name" : "B",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "A",
"referencedDeclaration" : 1,
"type" : "contract A"
},
"id" : 2,
"name" : "UserDefinedTypeName",
"src" : "29:1:1"
}
],
"id" : 3,
"name" : "InheritanceSpecifier",
"src" : "29:1:1"
}
],
"id" : 4,
"name" : "ContractDefinition",
"src" : "15:19:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1,
4
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
7,
4,
1
],
"name" : "C",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "B",
"referencedDeclaration" : 4,
"type" : "contract B"
},
"id" : 5,
"name" : "UserDefinedTypeName",
"src" : "49:1:1"
}
],
"id" : 6,
"name" : "InheritanceSpecifier",
"src" : "49:1:1"
}
],
"id" : 7,
"name" : "ContractDefinition",
"src" : "35:19:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1,
4,
7
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
10,
7,
4,
1
],
"name" : "D",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "C",
"referencedDeclaration" : 7,
"type" : "contract C"
},
"id" : 8,
"name" : "UserDefinedTypeName",
"src" : "69:1:1"
}
],
"id" : 9,
"name" : "InheritanceSpecifier",
"src" : "69:1:1"
}
],
"id" : 10,
"name" : "ContractDefinition",
"src" : "55:19:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1,
4,
7,
10
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
13,
10,
7,
4,
1
],
"name" : "E",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "D",
"referencedDeclaration" : 10,
"type" : "contract D"
},
"id" : 11,
"name" : "UserDefinedTypeName",
"src" : "89:1:1"
}
],
"id" : 12,
"name" : "InheritanceSpecifier",
"src" : "89:1:1"
}
],
"id" : 13,
"name" : "ContractDefinition",
"src" : "75:19:1"
}
],
"id" : 14,
"name" : "SourceUnit",
"src" : "0:95:1"
}
@@ -1 +1,3 @@
contract C1 {} contract C2 is C1 {}
// ----
-427
View File
@@ -41,183 +41,6 @@ namespace test
BOOST_AUTO_TEST_SUITE(SolidityImports)
BOOST_AUTO_TEST_CASE(smoke_test)
{
CompilerStack c;
c.setSources({{"a", "contract C {} pragma solidity >=0.0;"}});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(regular_import)
{
CompilerStack c;
c.setSources({
{"a", "contract C {} pragma solidity >=0.0;"},
{"b", "import \"a\"; contract D is C {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(import_does_not_clutter_importee)
{
CompilerStack c;
c.setSources({
{"a", "contract C { D d; } pragma solidity >=0.0;"},
{"b", "import \"a\"; contract D is C {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(import_is_transitive)
{
CompilerStack c;
c.setSources({
{"a", "contract C { } pragma solidity >=0.0;"},
{"b", "import \"a\"; pragma solidity >=0.0;"},
{"c", "import \"b\"; contract D is C {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(circular_import)
{
CompilerStack c;
c.setSources({
{"a", "import \"b\"; contract C { D d; } pragma solidity >=0.0;"},
{"b", "import \"a\"; contract D { C c; } pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(relative_import)
{
CompilerStack c;
c.setSources({
{"a", "import \"./dir/b\"; contract A is B {} pragma solidity >=0.0;"},
{"dir/b", "contract B {} pragma solidity >=0.0;"},
{"dir/c", "import \"../a\"; contract C is A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(relative_import_multiplex)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"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());
}
BOOST_AUTO_TEST_CASE(simple_alias)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"dir/a/b/c", "import \"../../.././a\" as x; contract B is x.A { function() external { x.A r = x.A(20); } } pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(library_name_clash)
{
CompilerStack c;
c.setSources({
{"a", "library A {} pragma solidity >=0.0;"},
{"b", "library A {} pragma solidity >=0.0;"},
{"c", "import {A} from \"./a\"; import {A} from \"./b\";"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(library_name_clash_with_contract)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "library A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(complex_import)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} contract B {} contract C { struct S { uint a; } } pragma solidity >=0.0;"},
{"b", "import \"a\" as x; import {B as b, C as c, C} from \"a\"; "
"contract D is b { function f(c.S memory var1, x.C.S memory var2, C.S memory var3) internal {} } pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_1)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import \"a\"; contract A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_2)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import \"a\" as A; contract A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_3)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import {A as b} from \"a\"; contract b {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_4)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import {A} from \"a\"; contract A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_5)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import {A} from \"a\"; contract B {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(remappings)
{
CompilerStack c;
@@ -246,17 +69,6 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings)
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(filename_with_period)
{
CompilerStack c;
c.setSources({
{"a/a.sol", "import \".b.sol\"; contract A is B {} pragma solidity >=0.0;"},
{"a/.b.sol", "contract B {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_preserved)
{
CompilerStack c;
@@ -303,245 +115,6 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent_2)
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(shadowing_via_import)
{
CompilerStack c;
c.setSources({
{"a", "library A {} pragma solidity >=0.0;"},
{"b", "library A {} pragma solidity >=0.0;"},
{"c", "import {A} from \"./a\"; import {A} from \"./b\";"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_imports)
{
CompilerStack c;
c.setSources({
{"B.sol", "contract X {} pragma solidity >=0.0;"},
{"b", R"(
pragma solidity >=0.0;
import * as msg from "B.sol";
contract C {
})"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
size_t errorCount = 0;
for (auto const& e: c.errors())
{
string const* msg = e->comment();
BOOST_REQUIRE(msg);
if (msg->find("pre-release") != string::npos)
continue;
BOOST_CHECK(
msg->find("shadows a builtin symbol") != string::npos
);
errorCount++;
}
BOOST_CHECK_EQUAL(errorCount, 1);
}
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_multiple_imports)
{
CompilerStack c;
c.setSources({
{"B.sol", "contract msg {} contract block{} pragma solidity >=0.0;"},
{"b", R"(
pragma solidity >=0.0;
import {msg, block} from "B.sol";
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.
BOOST_CHECK(4 <= numErrors && numErrors <= 5);
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_CASE(shadowing_builtins_with_alias)
{
CompilerStack c;
c.setSources({
{"B.sol", "contract C {} pragma solidity >=0.0;"},
{"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_CASE(inheritance_abi_encoder_mismatch_1)
{
CompilerStack c;
c.setSources({
{"A.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) returns (S memory,S memory) { }
}
)"},
{"B.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
)"},
{"C.sol", R"(
pragma solidity >=0.0;
import "./B.sol";
contract C is B { }
)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
int typeErrors = 0;
// Sometimes we get the prerelease warning, sometimes not.
for (auto const& e: c.errors())
{
if (e->type() != langutil::Error::Type::TypeError)
continue;
typeErrors++;
string const* msg = e->comment();
BOOST_REQUIRE(msg);
BOOST_CHECK_EQUAL(*msg, std::string("Contract \"C\" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use \"pragma experimental ABIEncoderV2;\" for the inheriting contract as well to enable the feature."));
}
BOOST_CHECK_EQUAL(typeErrors, 1);
}
BOOST_AUTO_TEST_CASE(inheritance_abi_encoder_mismatch_2)
{
CompilerStack c;
c.setSources({
{"A.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) returns (S memory,S memory) { }
}
)"},
{"B.sol", R"(
pragma solidity >=0.0;
import "./A.sol";
contract B is A { }
)"},
{"C.sol", R"(
pragma solidity >=0.0;
import "./B.sol";
contract C is B { }
)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
int typeErrors = 0;
// Sometimes we get the prerelease warning, sometimes not.
for (auto const& e: c.errors())
{
if (e->type() != langutil::Error::Type::TypeError)
continue;
typeErrors++;
string const* msg = e->comment();
BOOST_REQUIRE(msg);
BOOST_CHECK_EQUAL(*msg, std::string("Contract \"B\" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use \"pragma experimental ABIEncoderV2;\" for the inheriting contract as well to enable the feature."));
}
BOOST_CHECK_EQUAL(typeErrors, 1);
}
BOOST_AUTO_TEST_CASE(inheritance_abi_encoder_match)
{
CompilerStack c;
c.setSources({
{"A.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
)"},
{"B.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
)"},
{"C.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
import "./B.sol";
contract C is B { }
)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
int typeErrors = 0;
// Sometimes we get the prerelease warning, sometimes not.
for (auto const& e: c.errors())
{
if (e->type() != langutil::Error::Type::TypeError)
continue;
typeErrors++;
}
BOOST_CHECK_EQUAL(typeErrors, 0);
}
BOOST_AUTO_TEST_SUITE_END()
}
+3 -1
View File
@@ -116,13 +116,15 @@ BOOST_AUTO_TEST_CASE(division)
if (a == 0) {
return 0;
}
// TODO remove when SMTChecker sees that this code is the `else` of the `return`.
require(a != 0);
uint256 c = a * b;
require(c / a == b);
return c;
}
}
)";
CHECK_WARNING(text, "Division by zero");
CHECK_SUCCESS_OR_WARNING(text, "might happen");
text = R"(
contract C {
function div(uint256 a, uint256 b) internal pure returns (uint256) {
+16 -5
View File
@@ -108,6 +108,9 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr
BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end."));
int start = location["start"].asInt();
int end = location["end"].asInt();
std::string sourceName;
if (location.isMember("source") && location["source"].isString())
sourceName = location["source"].asString();
if (start >= static_cast<int>(versionPragma.size()))
start -= versionPragma.size();
if (end >= static_cast<int>(versionPragma.size()))
@@ -115,6 +118,7 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr
m_errorList.emplace_back(SyntaxTestError{
error["type"].asString(),
error["message"].asString(),
sourceName,
start,
end
});
@@ -141,13 +145,20 @@ vector<string> SMTCheckerTest::hashesFromJson(Json::Value const& _jsonObj, strin
Json::Value SMTCheckerTest::buildJson(string const& _extra)
{
string language = "\"language\": \"Solidity\"";
string sourceName = "\"A\"";
string sourceContent = "\"" + _extra + m_source + "\"";
string sourceObj = "{ \"content\": " + sourceContent + "}";
string sources = " \"sources\": { " + sourceName + ": " + sourceObj + "}";
string sources = " \"sources\": { ";
bool first = true;
for (auto [sourceName, sourceContent]: m_sources)
{
string sourceObj = "{ \"content\": \"" + _extra + sourceContent + "\"}";
if (!first)
sources += ", ";
sources += "\"" + sourceName + "\": " + sourceObj;
first = false;
}
sources += "}";
string input = "{" + language + ", " + sources + "}";
Json::Value source;
if (!jsonParse(input, source))
BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string."));
BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string: " + input));
return source;
}
+90 -41
View File
@@ -59,7 +59,8 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
file.exceptions(ios::badbit);
m_source = parseSourceAndSettings(file);
m_sources = parseSourcesAndSettings(file);
if (m_settings.count("optimize-yul"))
{
m_optimiseYul = true;
@@ -74,7 +75,10 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
{
string const versionPragma = "pragma solidity >=0.0;\n";
compiler().reset();
compiler().setSources({{"", versionPragma + m_source}});
auto sourcesWithPragma = m_sources;
for (auto& source: sourcesWithPragma)
source.second = versionPragma + source.second;
compiler().setSources(sourcesWithPragma);
compiler().setEVMVersion(m_evmVersion);
compiler().setParserErrorRecovery(m_parserErrorRecovery);
compiler().setOptimiserSettings(
@@ -83,11 +87,27 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
OptimiserSettings::minimal()
);
if (compiler().parse())
compiler().analyze();
if (compiler().analyze())
try
{
if (!compiler().compile())
BOOST_THROW_EXCEPTION(runtime_error("Compilation failed even though analysis was successful."));
}
catch (UnimplementedFeatureError const& _e)
{
m_errorList.emplace_back(SyntaxTestError{
"UnimplementedFeatureError",
errorMessage(_e),
"",
-1,
-1
});
}
for (auto const& currentError: filterErrors(compiler().errors(), true))
{
int locationStart = -1, locationEnd = -1;
string sourceName;
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
{
// ignore the version pragma inserted by the testing tool when calculating locations.
@@ -95,10 +115,13 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
locationStart = location->start - versionPragma.size();
if (location->end >= static_cast<int>(versionPragma.size()))
locationEnd = location->end - versionPragma.size();
if (location->source)
sourceName = location->source->name();
}
m_errorList.emplace_back(SyntaxTestError{
currentError->typeName(),
errorMessage(*currentError),
sourceName,
locationStart,
locationEnd
});
@@ -123,51 +146,65 @@ bool SyntaxTest::printExpectationAndError(ostream& _stream, string const& _lineP
void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const
{
if (m_sources.empty())
return;
bool outputSourceNames = true;
if (m_sources.size() == 1 && m_sources.begin()->first.empty())
outputSourceNames = false;
if (_formatted)
{
if (m_source.empty())
return;
vector<char const*> sourceFormatting(m_source.length(), formatting::RESET);
for (auto const& error: m_errorList)
if (error.locationStart >= 0 && error.locationEnd >= 0)
{
assert(static_cast<size_t>(error.locationStart) <= m_source.length());
assert(static_cast<size_t>(error.locationEnd) <= m_source.length());
bool isWarning = error.type == "Warning";
for (int i = error.locationStart; i < error.locationEnd; i++)
if (isWarning)
{
if (sourceFormatting[i] == formatting::RESET)
sourceFormatting[i] = formatting::ORANGE_BACKGROUND_256;
}
else
sourceFormatting[i] = formatting::RED_BACKGROUND;
}
_stream << _linePrefix << sourceFormatting.front() << m_source.front();
for (size_t i = 1; i < m_source.length(); i++)
for (auto const& [name, source]: m_sources)
{
if (sourceFormatting[i] != sourceFormatting[i - 1])
_stream << sourceFormatting[i];
if (m_source[i] != '\n')
_stream << m_source[i];
else
if (outputSourceNames)
_stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl;
vector<char const*> sourceFormatting(source.length(), formatting::RESET);
for (auto const& error: m_errorList)
if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0)
{
assert(static_cast<size_t>(error.locationStart) <= source.length());
assert(static_cast<size_t>(error.locationEnd) <= source.length());
bool isWarning = error.type == "Warning";
for (int i = error.locationStart; i < error.locationEnd; i++)
if (isWarning)
{
if (sourceFormatting[i] == formatting::RESET)
sourceFormatting[i] = formatting::ORANGE_BACKGROUND_256;
}
else
sourceFormatting[i] = formatting::RED_BACKGROUND;
}
_stream << _linePrefix << sourceFormatting.front() << source.front();
for (size_t i = 1; i < source.length(); i++)
{
_stream << formatting::RESET << endl;
if (i + 1 < m_source.length())
_stream << _linePrefix << sourceFormatting[i];
if (sourceFormatting[i] != sourceFormatting[i - 1])
_stream << sourceFormatting[i];
if (source[i] != '\n')
_stream << source[i];
else
{
_stream << formatting::RESET << endl;
if (i + 1 < source.length())
_stream << _linePrefix << sourceFormatting[i];
}
}
_stream << formatting::RESET;
}
_stream << formatting::RESET;
}
else
{
stringstream stream(m_source);
string line;
while (getline(stream, line))
_stream << _linePrefix << line << endl;
}
for (auto const& [name, source]: m_sources)
{
if (outputSourceNames)
_stream << _linePrefix << "==== Source: " + name << " ====" << endl;
stringstream stream(source);
string line;
while (getline(stream, line))
_stream << _linePrefix << line << endl;
}
}
void SyntaxTest::printErrorList(
@@ -187,9 +224,11 @@ void SyntaxTest::printErrorList(
_stream << _linePrefix;
_stream << error.type << ": ";
}
if (error.locationStart >= 0 || error.locationEnd >= 0)
if (!error.sourceName.empty() || error.locationStart >= 0 || error.locationEnd >= 0)
{
_stream << "(";
if (!error.sourceName.empty())
_stream << error.sourceName << ":";
if (error.locationStart >= 0)
_stream << error.locationStart;
_stream << "-";
@@ -234,10 +273,19 @@ vector<SyntaxTestError> SyntaxTest::parseExpectations(istream& _stream)
int locationStart = -1;
int locationEnd = -1;
std::string sourceName;
if (it != line.end() && *it == '(')
{
++it;
if (it != line.end() && !isdigit(*it))
{
auto sourceNameStart = it;
while (it != line.end() && *it != ':')
++it;
sourceName = std::string(sourceNameStart, it);
expect(it, line.end(), ':');
}
locationStart = parseUnsignedInteger(it, line.end());
expect(it, line.end(), '-');
locationEnd = parseUnsignedInteger(it, line.end());
@@ -251,6 +299,7 @@ vector<SyntaxTestError> SyntaxTest::parseExpectations(istream& _stream)
expectations.emplace_back(SyntaxTestError{
move(errorType),
move(errorMessage),
move(sourceName),
locationStart,
locationEnd
});
+3 -1
View File
@@ -38,12 +38,14 @@ struct SyntaxTestError
{
std::string type;
std::string message;
std::string sourceName;
int locationStart;
int locationEnd;
bool operator==(SyntaxTestError const& _rhs) const
{
return type == _rhs.type &&
message == _rhs.message &&
sourceName == _rhs.sourceName &&
locationStart == _rhs.locationStart &&
locationEnd == _rhs.locationEnd;
}
@@ -85,7 +87,7 @@ protected:
static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream);
std::string m_source;
std::map<std::string, std::string> m_sources;
std::vector<SyntaxTestError> m_expectations;
std::vector<SyntaxTestError> m_errorList;
bool m_optimiseYul = false;
@@ -1,3 +1,4 @@
==== Source: A ====
pragma experimental SMTChecker;
contract C
@@ -1,3 +1,4 @@
==== Source: A ====
pragma experimental SMTChecker;
contract C
@@ -4,3 +4,5 @@ contract C {
fixed a3 = 0 / 0.123;
fixed a4 = 0 / -0.123;
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -0,0 +1,4 @@
==== Source: a ====
import "b"; contract C { D d; }
==== Source: b ====
import "a"; contract D { C c; }
@@ -0,0 +1,5 @@
==== Source: a ====
contract A {} contract B {} contract C { struct S { uint a; } }
==== Source: b ====
import "a" as x; import {B as b, C as c, C} from "a";
contract D is b { function f(c.S memory var1, x.C.S memory var2, C.S memory var3) internal {} }
@@ -0,0 +1,6 @@
==== Source: a/.b.sol ====
contract B {}
==== Source: a/a.sol ====
import ".b.sol"; contract A is B {}
// ----
// ParserError: (a/a.sol:0-16): Source ".b.sol" not found: File not supplied initially.
@@ -0,0 +1,6 @@
==== Source: a ====
contract C { D d; }
==== Source: b ====
import "a"; contract D is C {}
// ----
// DeclarationError: (a:13-14): Identifier not found or not unique.
@@ -0,0 +1,7 @@
==== Source: a ====
contract C { }
==== Source: b ====
import "a";
==== Source: c ====
import "b";
contract D is C {}
@@ -0,0 +1,23 @@
==== Source: A.sol ====
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
==== Source: B.sol ====
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
==== Source: C.sol ====
pragma experimental ABIEncoderV2;
import "./B.sol";
contract C is B { }
// ----
// Warning: (A.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (B.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (C.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
@@ -0,0 +1,21 @@
==== Source: A.sol ====
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
==== Source: B.sol ====
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
==== Source: C.sol ====
import "./B.sol";
contract C is B { }
// ----
// Warning: (A.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (B.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (C.sol:18-37): Contract "C" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.
@@ -0,0 +1,18 @@
==== Source: A.sol ====
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
==== Source: B.sol ====
import "./A.sol";
contract B is A { }
==== Source: C.sol ====
import "./B.sol";
contract C is B { }
// ----
// Warning: (A.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (B.sol:18-37): Contract "B" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.
@@ -0,0 +1,8 @@
==== Source: a ====
library A {}
==== Source: b ====
library A {}
==== Source: c ====
import {A} from "./a"; import {A} from "./b";
// ----
// DeclarationError: (c:23-45): Identifier already declared.
@@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: b ====
library A {}
@@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import "a"; contract A {}
// ----
// DeclarationError: (b:12-25): Identifier already declared.
@@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import "a" as A; contract A {}
// ----
// DeclarationError: (b:17-30): Identifier already declared.
@@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import {A as b} from "a"; contract b {}
// ----
// DeclarationError: (b:26-39): Identifier already declared.
@@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import {A} from "a"; contract A {}
// ----
// DeclarationError: (b:21-34): Identifier already declared.
@@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: b ====
import {A} from "a"; contract B {}
@@ -0,0 +1,4 @@
==== Source: a ====
contract C {}
==== Source: b ====
import "a"; contract D is C {}
@@ -0,0 +1,6 @@
==== Source: a ====
import "./dir/b"; contract A is B {}
==== Source: dir/b ====
contract B {}
==== Source: dir/c ====
import "../a"; contract C is A {}
@@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: dir/a/b/c ====
import "../../.././a"; contract B is A {}
@@ -0,0 +1,6 @@
==== Source: B.sol ====
contract C {}
==== Source: b ====
import {C as msg} from "B.sol";
// ----
// Warning: (B.sol:0-13): This declaration shadows a builtin symbol.
@@ -0,0 +1,8 @@
==== Source: B.sol ====
contract X {}
==== Source: b ====
import * as msg from "B.sol";
contract C {
}
// ----
// Warning: (b:0-29): This declaration shadows a builtin symbol.
@@ -0,0 +1,11 @@
==== Source: B.sol ====
contract msg {} contract block{}
==== Source: b ====
import {msg, block} from "B.sol";
contract C {
}
// ----
// Warning: (B.sol:0-15): This declaration shadows a builtin symbol.
// Warning: (B.sol:16-32): This declaration shadows a builtin symbol.
// Warning: (B.sol:0-15): This declaration shadows a builtin symbol.
// Warning: (B.sol:16-32): This declaration shadows a builtin symbol.
@@ -0,0 +1,8 @@
==== Source: a ====
library A {}
==== Source: b ====
library A {}
==== Source: c ====
import {A} from "./a"; import {A} from "./b";
// ----
// DeclarationError: (c:23-45): Identifier already declared.
@@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: dir/a/b/c ====
import "../../.././a" as x; contract B is x.A { function() external { x.A r = x.A(20); r; } }
@@ -0,0 +1,2 @@
==== Source: a ====
contract C {}
@@ -4,5 +4,6 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (50-67): Unused local variable.
// Warning: (20-119): Function state mutability can be restricted to pure
@@ -4,5 +4,6 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (50-73): Unused local variable.
// Warning: (20-118): Function state mutability can be restricted to pure
@@ -0,0 +1,10 @@
==== Source: A ====
contract A {
function g() public { x; }
}
==== Source: B ====
contract B {
function f() public { }
}
// ----
// DeclarationError: (A:36-37): Undeclared identifier.
@@ -0,0 +1,12 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x; }
}
==== Source: B ====
import "A";
contract B is A {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// Warning: (A:14-78): Function state mutability can be restricted to pure
// Warning: (B:31-95): Function state mutability can be restricted to pure
@@ -0,0 +1,5 @@
==== Source: a ====
import "b";
contract C {}
// ----
// ParserError: (a:0-11): Source "b" not found: File not supplied initially.
@@ -0,0 +1,10 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x; }
}
==== Source: B ====
contract B is A {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// DeclarationError: (B:14-15): Identifier not found or not unique.
@@ -0,0 +1,7 @@
==== Source: SourceName ====
contract A {
uint256 x;
function f() public pure { x = 42; }
}
// ----
// TypeError: (SourceName:53-54): Function declared as pure, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
@@ -0,0 +1,11 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x; }
}
==== Source: B ====
contract B {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// Warning: (A:14-78): Function state mutability can be restricted to pure
// Warning: (B:14-78): Function state mutability can be restricted to pure
@@ -8,4 +8,5 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-147): Function state mutability can be restricted to pure
@@ -6,4 +6,5 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-104): Function state mutability can be restricted to pure
@@ -6,4 +6,5 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-108): Function state mutability can be restricted to pure
@@ -5,3 +5,5 @@ contract test {
a; b;
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -7,3 +7,5 @@ contract A {
a; b; c; d;
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -5,4 +5,5 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-104): Function state mutability can be restricted to pure
@@ -6,4 +6,5 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-182): Function state mutability can be restricted to pure
@@ -4,3 +4,5 @@ contract test {
fixedString[0.5] = "Half";
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -5,3 +5,5 @@ contract test {
}
myStruct a = myStruct(3.125, 3);
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -11,5 +11,6 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (238-252): This declaration shadows an existing declaration.
// Warning: (20-339): Function state mutability can be restricted to pure
@@ -4,5 +4,6 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (50-58): Unused local variable.
// Warning: (20-89): Function state mutability can be restricted to pure
@@ -6,6 +6,7 @@ contract A {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (52-60): Unused function parameter. Remove or comment out the variable name to silence this warning.
// Warning: (62-74): Unused function parameter. Remove or comment out the variable name to silence this warning.
// Warning: (93-104): Unused local variable.
@@ -7,3 +7,4 @@ contract C {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -6,3 +6,5 @@ contract test {
a; b; c;
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
@@ -13,3 +13,4 @@ contract C {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.