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: | Features: | ||||||
|  * Parser: Better error message for unexpected trailing comma in parameter lists. |  * 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. |  * 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. |  * Type Checker: Disallow non-pure constant state variables as experimental 0.5.0 feature. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -252,6 +252,14 @@ bool CompilerStack::parseAndAnalyze() | |||||||
| 	return parse() && analyze(); | 	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() | bool CompilerStack::compile() | ||||||
| { | { | ||||||
| 	if (m_stackState < AnalysisSuccessful) | 	if (m_stackState < AnalysisSuccessful) | ||||||
| @ -262,6 +270,7 @@ bool CompilerStack::compile() | |||||||
| 	for (Source const* source: m_sourceOrder) | 	for (Source const* source: m_sourceOrder) | ||||||
| 		for (ASTPointer<ASTNode> const& node: source->ast->nodes()) | 		for (ASTPointer<ASTNode> const& node: source->ast->nodes()) | ||||||
| 			if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) | 			if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) | ||||||
|  | 				if (isRequestedContract(*contract)) | ||||||
| 					compileContract(*contract, compiledContracts); | 					compileContract(*contract, compiledContracts); | ||||||
| 	this->link(); | 	this->link(); | ||||||
| 	m_stackState = CompilationSuccessful; | 	m_stackState = CompilationSuccessful; | ||||||
|  | |||||||
| @ -116,6 +116,13 @@ public: | |||||||
| 		m_optimizeRuns = _runs; | 		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.
 | 	/// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata.
 | ||||||
| 	void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; } | 	void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; } | ||||||
| 
 | 
 | ||||||
| @ -259,6 +266,9 @@ private: | |||||||
| 	/// Helper function to return path converted strings.
 | 	/// Helper function to return path converted strings.
 | ||||||
| 	std::string sanitizePath(std::string const& _path) const { return boost::filesystem::path(_path).generic_string(); } | 	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.
 | 	/// Compile a single contract and put the result in @a _compiledContracts.
 | ||||||
| 	void compileContract( | 	void compileContract( | ||||||
| 		ContractDefinition const& _contract, | 		ContractDefinition const& _contract, | ||||||
| @ -297,6 +307,7 @@ private: | |||||||
| 	ReadCallback::Callback m_smtQuery; | 	ReadCallback::Callback m_smtQuery; | ||||||
| 	bool m_optimize = false; | 	bool m_optimize = false; | ||||||
| 	unsigned m_optimizeRuns = 200; | 	unsigned m_optimizeRuns = 200; | ||||||
|  | 	std::set<std::string> m_requestedContractNames; | ||||||
| 	std::map<std::string, h160> m_libraries; | 	std::map<std::string, h160> m_libraries; | ||||||
| 	/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
 | 	/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
 | ||||||
| 	/// "context:prefix=target"
 | 	/// "context:prefix=target"
 | ||||||
|  | |||||||
| @ -92,6 +92,22 @@ Json::Value formatErrorWithException( | |||||||
| 	return formatError(_warning, _type, _component, message, formattedMessage, location); | 	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.
 | /// 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) | 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()); | 	Json::Value metadataSettings = settings.get("metadata", Json::Value()); | ||||||
| 	m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool()); | 	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); }; | 	auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compilerStack.scanner(_sourceName); }; | ||||||
| 
 | 
 | ||||||
| 	try | 	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() | BOOST_AUTO_TEST_SUITE_END() | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user