mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2901 from ethereum/compiler-names
Provide optional list of contract names to CompilerStack.compile
This commit is contained in:
commit
54cf15ac4f
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user