aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md2
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp6
-rw-r--r--libsolidity/codegen/ArrayUtils.cpp3
-rw-r--r--libsolidity/interface/CompilerStack.cpp11
-rw-r--r--libsolidity/interface/CompilerStack.h11
-rw-r--r--libsolidity/interface/StandardCompiler.cpp19
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp11
-rw-r--r--test/libsolidity/StandardCompiler.cpp177
8 files changed, 237 insertions, 3 deletions
diff --git a/Changelog.md b/Changelog.md
index c78a26e0..8f97b0e8 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,7 @@
Features:
* Parser: Better error message for unexpected trailing comma in parameter lists.
+ * Standard JSON: Support the ``outputSelection`` field for selective compilation of supplied sources.
* Syntax Checker: Unary ``+`` is now a syntax error as experimental 0.5.0 feature.
* Type Checker: Disallow non-pure constant state variables as experimental 0.5.0 feature.
* Code Generator: Always use all available gas for calls as experimental 0.5.0 feature
@@ -14,6 +15,7 @@ Bugfixes:
* Type Checker: Properly support overwriting members inherited from ``address`` in a contract
(such as ``balance``, ``transfer``, etc.)
* Type Checker: Prevent duplicate event declarations.
+ * Type Checker: Do not mark event parameters as shadowing state variables.
### 0.4.17 (2017-09-21)
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index 523e7176..5d010693 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -647,10 +647,12 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
bool warnAboutShadowing = true;
// Do not warn about shadowing for structs and enums because their members are
- // not accessible without prefixes.
+ // not accessible without prefixes. Also do not warn about event parameters
+ // because they don't participate in any proper scope.
if (
dynamic_cast<StructDefinition const*>(m_currentScope) ||
- dynamic_cast<EnumDefinition const*>(m_currentScope)
+ dynamic_cast<EnumDefinition const*>(m_currentScope) ||
+ dynamic_cast<EventDefinition const*>(m_currentScope)
)
warnAboutShadowing = false;
// Do not warn about the constructor shadowing the contract.
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp
index e17188c2..ce8cbb5f 100644
--- a/libsolidity/codegen/ArrayUtils.cpp
+++ b/libsolidity/codegen/ArrayUtils.cpp
@@ -291,8 +291,11 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
CompilerUtils utils(m_context);
unsigned baseSize = 1;
if (!_sourceType.isByteArray())
+ {
// We always pad the elements, regardless of _padToWordBoundaries.
baseSize = _sourceType.baseType()->calldataEncodedSize();
+ solAssert(baseSize >= 0x20, "");
+ }
if (_sourceType.location() == DataLocation::CallData)
{
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 51544f8a..b99fe4ee 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -252,6 +252,14 @@ bool CompilerStack::parseAndAnalyze()
return parse() && analyze();
}
+bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) const
+{
+ return
+ m_requestedContractNames.empty() ||
+ m_requestedContractNames.count(_contract.fullyQualifiedName()) ||
+ m_requestedContractNames.count(_contract.name());
+}
+
bool CompilerStack::compile()
{
if (m_stackState < AnalysisSuccessful)
@@ -262,7 +270,8 @@ bool CompilerStack::compile()
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
- compileContract(*contract, compiledContracts);
+ if (isRequestedContract(*contract))
+ compileContract(*contract, compiledContracts);
this->link();
m_stackState = CompilationSuccessful;
return true;
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index f1bbae47..c567ac2c 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -116,6 +116,13 @@ public:
m_optimizeRuns = _runs;
}
+ /// Sets the list of requested contract names. If empty, no filtering is performed and every contract
+ /// found in the supplied sources is compiled. Names are cleared iff @a _contractNames is missing.
+ void setRequestedContractNames(std::set<std::string> const& _contractNames = std::set<std::string>{})
+ {
+ m_requestedContractNames = _contractNames;
+ }
+
/// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata.
void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; }
@@ -259,6 +266,9 @@ private:
/// Helper function to return path converted strings.
std::string sanitizePath(std::string const& _path) const { return boost::filesystem::path(_path).generic_string(); }
+ /// @returns true if the contract is requested to be compiled.
+ bool isRequestedContract(ContractDefinition const& _contract) const;
+
/// Compile a single contract and put the result in @a _compiledContracts.
void compileContract(
ContractDefinition const& _contract,
@@ -297,6 +307,7 @@ private:
ReadCallback::Callback m_smtQuery;
bool m_optimize = false;
unsigned m_optimizeRuns = 200;
+ std::set<std::string> m_requestedContractNames;
std::map<std::string, h160> m_libraries;
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
/// "context:prefix=target"
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index b4fbbef9..430739ac 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -92,6 +92,22 @@ Json::Value formatErrorWithException(
return formatError(_warning, _type, _component, message, formattedMessage, location);
}
+set<string> requestedContractNames(Json::Value const& _outputSelection)
+{
+ set<string> names;
+ for (auto const& sourceName: _outputSelection.getMemberNames())
+ {
+ for (auto const& contractName: _outputSelection[sourceName].getMemberNames())
+ {
+ /// Consider the "all sources" shortcuts as requesting everything.
+ if (contractName == "*" || contractName == "")
+ return set<string>();
+ names.insert((sourceName == "*" ? "" : sourceName) + ":" + contractName);
+ }
+ }
+ return names;
+}
+
/// Returns true iff @a _hash (hex with 0x prefix) is the Keccak256 hash of the binary data in @a _content.
bool hashMatchesContent(string const& _hash, string const& _content)
{
@@ -265,6 +281,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
Json::Value metadataSettings = settings.get("metadata", Json::Value());
m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool());
+ Json::Value outputSelection = settings.get("outputSelection", Json::Value());
+ m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection));
+
auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compilerStack.scanner(_sourceName); };
try
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index ed223678..350d41f1 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -6371,6 +6371,17 @@ BOOST_AUTO_TEST_CASE(function_override_is_not_shadowing)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(event_parameter_cannot_shadow_state_variable)
+{
+ char const* text = R"(
+ contract C {
+ address a;
+ event E(address a);
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(callable_crash)
{
char const* text = R"(
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 24f915c0..4504946b 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -226,6 +226,183 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
);
}
+BOOST_AUTO_TEST_CASE(output_selection_explicit)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_all_contracts)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "*": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_all_files_single_contract)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_all_files_all_contracts)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "*": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_dependent_contract)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract B { } contract A { function f() { new B(); } }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[{\"constant\":false,\"inputs\":[],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_dependent_contract_with_import)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "import \"fileB\"; contract A { function f() { new B(); } }"
+ },
+ "fileB": {
+ "content": "contract B { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[{\"constant\":false,\"inputs\":[],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}