aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-12-20 00:02:28 +0800
committerGitHub <noreply@github.com>2018-12-20 00:02:28 +0800
commitae08d7c375482cef29567e15468e8867380c9cc6 (patch)
treefd162c6117bece7ea548d8d9474f9e217fbb96a6 /libsolidity
parentef59f35a14c6eea65b15ac78db06befb182907c1 (diff)
parent900d100700d6b7ba347bae9779aa7f540387fee8 (diff)
downloaddexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.tar
dexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.tar.gz
dexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.tar.bz2
dexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.tar.lz
dexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.tar.xz
dexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.tar.zst
dexon-solidity-ae08d7c375482cef29567e15468e8867380c9cc6.zip
Merge pull request #5681 from ethereum/limitOutput
Do not compile unless requested.
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/interface/CompilerStack.cpp55
-rw-r--r--libsolidity/interface/StandardCompiler.cpp65
2 files changed, 100 insertions, 20 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index adfb94bd..f9d889e7 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -389,18 +389,27 @@ string const CompilerStack::lastContractName() const
eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
return currentContract.compiler ? &contract(_contractName).compiler->assemblyItems() : nullptr;
}
eth::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr;
}
string const* CompilerStack::sourceMapping(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& c = contract(_contractName);
if (!c.sourceMapping)
{
@@ -412,6 +421,9 @@ string const* CompilerStack::sourceMapping(string const& _contractName) const
string const* CompilerStack::runtimeSourceMapping(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& c = contract(_contractName);
if (!c.runtimeSourceMapping)
{
@@ -447,17 +459,26 @@ std::string const CompilerStack::filesystemFriendlyName(string const& _contractN
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
return contract(_contractName).object;
}
eth::LinkerObject const& CompilerStack::runtimeObject(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
return contract(_contractName).runtimeObject;
}
/// FIXME: cache this string
string CompilerStack::assemblyString(string const& _contractName, StringMap _sourceCodes) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
if (currentContract.compiler)
return currentContract.compiler->assemblyString(_sourceCodes);
@@ -468,6 +489,9 @@ string CompilerStack::assemblyString(string const& _contractName, StringMap _sou
/// FIXME: cache the JSON
Json::Value CompilerStack::assemblyJSON(string const& _contractName, StringMap _sourceCodes) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
if (currentContract.compiler)
return currentContract.compiler->assemblyJSON(_sourceCodes);
@@ -494,13 +518,16 @@ map<string, unsigned> CompilerStack::sourceIndices() const
Json::Value const& CompilerStack::contractABI(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
return contractABI(contract(_contractName));
}
Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
{
if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(_contract.contract, "");
@@ -513,13 +540,16 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
Json::Value const& CompilerStack::natspecUser(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
return natspecUser(contract(_contractName));
}
Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
{
if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(_contract.contract, "");
@@ -532,13 +562,16 @@ Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
Json::Value const& CompilerStack::natspecDev(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
return natspecDev(contract(_contractName));
}
Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
{
if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(_contract.contract, "");
@@ -551,6 +584,9 @@ Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
Json::Value methodIdentifiers(Json::objectValue);
for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
methodIdentifiers[it.second->externalSignature()] = it.first.hex();
@@ -583,8 +619,8 @@ SourceUnit const& CompilerStack::ast(string const& _sourceName) const
ContractDefinition const& CompilerStack::contractDefinition(string const& _contractName) const
{
- if (m_stackState != CompilationSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
return *contract(_contractName).contract;
}
@@ -594,6 +630,9 @@ size_t CompilerStack::functionEntryPoint(
FunctionDefinition const& _function
) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
shared_ptr<Compiler> const& compiler = contract(_contractName).compiler;
if (!compiler)
return 0;
@@ -936,6 +975,9 @@ bytes CompilerStack::createCBORMetadata(string const& _metadata, bool _experimen
string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
string ret;
map<string, unsigned> sourceIndicesMap = sourceIndices();
int prevStart = -1;
@@ -1022,6 +1064,9 @@ Json::Value gasToJson(GasEstimator::GasConsumption const& _gas)
Json::Value CompilerStack::gasEstimates(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName))
return Json::Value();
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index e99b1324..137a4439 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -28,6 +28,7 @@
#include <libdevcore/JSON.h>
#include <libdevcore/Keccak256.h>
+#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <algorithm>
@@ -191,6 +192,31 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil
return false;
}
+/// @returns true if any binary was requested, i.e. we actually have to perform compilation.
+bool isBinaryRequested(Json::Value const& _outputSelection)
+{
+ if (!_outputSelection.isObject())
+ return false;
+
+ // This does not inculde "evm.methodIdentifiers" on purpose!
+ static vector<string> const outputsThatRequireBinaries{
+ "*",
+ "metadata", // This is only generated at the end of compilation, but could be generated earlier.
+ "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes",
+ "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences",
+ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap",
+ "evm.bytecode.linkReferences",
+ "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly"
+ };
+
+ for (auto const& fileRequests: _outputSelection)
+ for (auto const& requests: fileRequests)
+ for (auto const& output: outputsThatRequireBinaries)
+ if (isArtifactRequested(requests, output))
+ return true;
+ return false;
+}
+
Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkReferences)
{
Json::Value ret(Json::objectValue);
@@ -564,9 +590,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection));
+ bool const binariesRequested = isBinaryRequested(outputSelection);
+
try
{
- m_compilerStack.compile();
+ if (binariesRequested)
+ m_compilerStack.compile();
+ else
+ m_compilerStack.parseAndAnalyze();
for (auto const& error: m_compilerStack.errors())
{
@@ -655,7 +686,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
bool const compilationSuccess = m_compilerStack.state() == CompilerStack::State::CompilationSuccessful;
/// Inconsistent state - stop here to receive error reports from users
- if (!compilationSuccess && errors.empty())
+ if (((binariesRequested && !compilationSuccess) || !analysisSuccess) && errors.empty())
return formatFatalError("InternalCompilerError", "No error reported, but compilation failed.");
Json::Value output = Json::objectValue;
@@ -681,7 +712,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
}
Json::Value contractsOutput = Json::objectValue;
- for (string const& contractName: compilationSuccess ? m_compilerStack.contractNames() : vector<string>())
+ for (string const& contractName: analysisSuccess ? m_compilerStack.contractNames() : vector<string>())
{
size_t colon = contractName.rfind(':');
solAssert(colon != string::npos, "");
@@ -692,7 +723,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
Json::Value contractData(Json::objectValue);
if (isArtifactRequested(outputSelection, file, name, "abi"))
contractData["abi"] = m_compilerStack.contractABI(contractName);
- if (isArtifactRequested(outputSelection, file, name, "metadata"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "metadata"))
contractData["metadata"] = m_compilerStack.metadata(contractName);
if (isArtifactRequested(outputSelection, file, name, "userdoc"))
contractData["userdoc"] = m_compilerStack.natspecUser(contractName);
@@ -702,16 +733,16 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
// EVM
Json::Value evmData(Json::objectValue);
// @TODO: add ir
- if (isArtifactRequested(outputSelection, file, name, "evm.assembly"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.assembly"))
evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input));
- if (isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly"))
evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input));
if (isArtifactRequested(outputSelection, file, name, "evm.methodIdentifiers"))
evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName);
- if (isArtifactRequested(outputSelection, file, name, "evm.gasEstimates"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.gasEstimates"))
evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName);
- if (isArtifactRequested(
+ if (compilationSuccess && isArtifactRequested(
outputSelection,
file,
name,
@@ -722,7 +753,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.sourceMapping(contractName)
);
- if (isArtifactRequested(
+ if (compilationSuccess && isArtifactRequested(
outputSelection,
file,
name,
@@ -733,14 +764,18 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.runtimeSourceMapping(contractName)
);
- contractData["evm"] = evmData;
+ if (!evmData.empty())
+ contractData["evm"] = evmData;
- if (!contractsOutput.isMember(file))
- contractsOutput[file] = Json::objectValue;
-
- contractsOutput[file][name] = contractData;
+ if (!contractData.empty())
+ {
+ if (!contractsOutput.isMember(file))
+ contractsOutput[file] = Json::objectValue;
+ contractsOutput[file][name] = contractData;
+ }
}
- output["contracts"] = contractsOutput;
+ if (!contractsOutput.empty())
+ output["contracts"] = contractsOutput;
return output;
}