From a0394a1bfadb93b1f697b43bf52750bbff02af37 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 29 Sep 2017 19:05:39 +0100 Subject: [PATCH] Restrict contracts compiled via outputSelection (but not the individual output details) --- Changelog.md | 1 + libsolidity/interface/StandardCompiler.cpp | 19 ++++ test/libsolidity/StandardCompiler.cpp | 116 +++++++++++++++++++++ 3 files changed, 136 insertions(+) diff --git a/Changelog.md b/Changelog.md index 8ebc30d05..6f2f40fbc 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. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index b4fbbef9b..430739acc 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 requestedContractNames(Json::Value const& _outputSelection) +{ + set 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(); + 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/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 24f915c07..03d7f85af 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -226,6 +226,122 @@ 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_SUITE_END() }