Skip to content

Commit

Permalink
Merge pull request ethereum#3101 from ethereum/compilerstack-header
Browse files Browse the repository at this point in the history
Remove the reliance on empty contract name equals "last contract" in CompilerStack
  • Loading branch information
chriseth authored Oct 19, 2017
2 parents b966021 + 8d3cfa8 commit 4e7d144
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 41 deletions.
37 changes: 24 additions & 13 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,22 +747,32 @@ void CompilerStack::compileContract(
}
}

string const CompilerStack::lastContractName() const
{
if (m_contracts.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
// try to find some user-supplied contract
string contractName;
for (auto const& it: m_sources)
for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
contractName = contract->fullyQualifiedName();
return contractName;
}

CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
{
if (m_contracts.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
string contractName = _contractName;
if (_contractName.empty())
// try to find some user-supplied contract
for (auto const& it: m_sources)
for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
contractName = contract->fullyQualifiedName();
auto it = m_contracts.find(contractName);

auto it = m_contracts.find(_contractName);
if (it != m_contracts.end())
return it->second;

// To provide a measure of backward-compatibility, if a contract is not located by its
// fully-qualified name, a lookup will be attempted purely on the contract's name to see
// if anything will satisfy.
if (it == m_contracts.end() && contractName.find(":") == string::npos)
if (_contractName.find(":") == string::npos)
{
for (auto const& contractEntry: m_contracts)
{
Expand All @@ -773,12 +783,13 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa
string foundName;
getline(ss, source, ':');
getline(ss, foundName, ':');
if (foundName == contractName) return contractEntry.second;
if (foundName == _contractName)
return contractEntry.second;
}
// If we get here, both lookup methods failed.
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
}
return it->second;

// If we get here, both lookup methods failed.
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract \"" + _contractName + "\" not found."));
}

CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const
Expand Down
31 changes: 17 additions & 14 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ class CompilerStack: boost::noncopyable
std::map<std::string, unsigned> sourceIndices() const;

/// @returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& scanner(std::string const& _sourceName = "") const;
Scanner const& scanner(std::string const& _sourceName) const;

/// @returns the parsed source unit with the supplied name.
SourceUnit const& ast(std::string const& _sourceName = "") const;
SourceUnit const& ast(std::string const& _sourceName) const;

/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
/// line and columns are numbered starting from 1 with following order:
Expand All @@ -168,48 +168,51 @@ class CompilerStack: boost::noncopyable
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;

/// @returns the name of the last contract.
std::string const lastContractName() const;

/// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
std::string const filesystemFriendlyName(std::string const& _contractName) const;

/// @returns the assembled object for a contract.
eth::LinkerObject const& object(std::string const& _contractName = "") const;
eth::LinkerObject const& object(std::string const& _contractName) const;

/// @returns the runtime object for the contract.
eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const;
eth::LinkerObject const& runtimeObject(std::string const& _contractName) const;

/// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL.
/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
/// substituted by the actual address. Note that this sequence starts end ends in three X
/// characters but can contain anything in between.
eth::LinkerObject const& cloneObject(std::string const& _contractName = "") const;
eth::LinkerObject const& cloneObject(std::string const& _contractName) const;

/// @returns normal contract assembly items
eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
eth::AssemblyItems const* assemblyItems(std::string const& _contractName) const;

/// @returns runtime contract assembly items
eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName) const;

/// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr
/// if the contract does not (yet) have bytecode.
std::string const* sourceMapping(std::string const& _contractName = "") const;
std::string const* sourceMapping(std::string const& _contractName) const;

/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
/// if the contract does not (yet) have bytecode.
std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
std::string const* runtimeSourceMapping(std::string const& _contractName) const;

/// @return a verbose text representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
std::string assemblyString(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
std::string assemblyString(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;

/// @returns a JSON representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
Json::Value assemblyJSON(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
Json::Value assemblyJSON(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;

/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.
Json::Value const& contractABI(std::string const& _contractName = "") const;
Json::Value const& contractABI(std::string const& _contractName) const;

/// @returns a JSON representing the contract's user documentation.
/// Prerequisite: Successful call to parse or compile.
Expand Down Expand Up @@ -276,8 +279,8 @@ class CompilerStack: boost::noncopyable
);
void link();

Contract const& contract(std::string const& _contractName = "") const;
Source const& source(std::string const& _sourceName = "") const;
Contract const& contract(std::string const& _contractName) const;
Source const& source(std::string const& _sourceName) const;

/// @returns the parsed contract with the supplied name. Throws an exception if the contract
/// does not exist.
Expand Down
5 changes: 3 additions & 2 deletions solc/CommandLineInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,9 +938,10 @@ void CommandLineInterface::handleAst(string const& _argStr)
for (auto const& sourceCode: m_sourceCodes)
asts.push_back(&m_compiler->ast(sourceCode.first));
map<ASTNode const*, eth::GasMeter::GasConsumption> gasCosts;
if (m_compiler->runtimeAssemblyItems())
// FIXME: shouldn't this be done for every contract?
if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
gasCosts = GasEstimator::breakToStatementLevel(
GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(), asts),
GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
asts
);

Expand Down
2 changes: 1 addition & 1 deletion test/libsolidity/AnalysisFramework.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
}
}

return make_pair(&m_compiler.ast(), firstError);
return make_pair(&m_compiler.ast(""), firstError);
}

SourceUnit const* AnalysisFramework::parseAndAnalyse(string const& _source)
Expand Down
14 changes: 7 additions & 7 deletions test/libsolidity/GasMeter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class GasMeterTestFramework: public SolidityExecutionFramework
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");

AssemblyItems const* items = m_compiler.runtimeAssemblyItems("");
ASTNode const& sourceUnit = m_compiler.ast();
AssemblyItems const* items = m_compiler.runtimeAssemblyItems(m_compiler.lastContractName());
ASTNode const& sourceUnit = m_compiler.ast("");
BOOST_REQUIRE(items != nullptr);
m_gasCosts = GasEstimator::breakToStatementLevel(
GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
Expand All @@ -64,13 +64,13 @@ class GasMeterTestFramework: public SolidityExecutionFramework
{
compileAndRun(_sourceCode);
auto state = make_shared<KnownState>();
PathGasMeter meter(*m_compiler.assemblyItems());
PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName()));
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
// costs for deployment
gas += bytecodeSize * GasCosts::createDataGas;
// costs for transaction
gas += gasForTransaction(m_compiler.object().bytecode, true);
gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);

BOOST_REQUIRE(!gas.isInfinite);
BOOST_CHECK(gas.value == m_gasUsed);
Expand All @@ -91,7 +91,7 @@ class GasMeterTestFramework: public SolidityExecutionFramework
}

gas += GasEstimator::functionalEstimation(
*m_compiler.runtimeAssemblyItems(),
*m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()),
_sig
);
BOOST_REQUIRE(!gas.isInfinite);
Expand Down Expand Up @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
if (first->first->location().intersects(second->first->location()))
{
BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
auto scannerFromSource = [&](string const&) -> Scanner const& { return m_compiler.scanner(); };
auto scannerFromSource = [&](string const& _sourceName) -> Scanner const& { return m_compiler.scanner(_sourceName); };
SourceReferenceFormatter::printSourceLocation(cout, &first->first->location(), scannerFromSource);
SourceReferenceFormatter::printSourceLocation(cout, &second->first->location(), scannerFromSource);
}
Expand Down
2 changes: 1 addition & 1 deletion test/libsolidity/SolidityABIJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class JSONInterfaceChecker
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");

Json::Value generatedInterface = m_compilerStack.contractABI("");
Json::Value generatedInterface = m_compilerStack.contractABI(m_compilerStack.lastContractName());
Json::Value expectedInterface;
BOOST_REQUIRE(m_reader.parse(_expectedInterfaceString, expectedInterface));
BOOST_CHECK_MESSAGE(
Expand Down
2 changes: 1 addition & 1 deletion test/libsolidity/SolidityExecutionFramework.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class SolidityExecutionFramework: public dev::test::ExecutionFramework
);
BOOST_ERROR("Compiling contract failed");
}
eth::LinkerObject obj = m_compiler.object(_contractName);
eth::LinkerObject obj = m_compiler.object(_contractName.empty() ? m_compiler.lastContractName() : _contractName);
BOOST_REQUIRE(obj.linkReferences.empty());
sendMessage(obj.bytecode + _arguments, true, _value);
return m_output;
Expand Down
4 changes: 2 additions & 2 deletions test/libsolidity/SolidityNatspecJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ class DocumentationChecker

Json::Value generatedDocumentation;
if (_userDocumentation)
generatedDocumentation = m_compilerStack.natspecUser("");
generatedDocumentation = m_compilerStack.natspecUser(m_compilerStack.lastContractName());
else
generatedDocumentation = m_compilerStack.natspecDev("");
generatedDocumentation = m_compilerStack.natspecDev(m_compilerStack.lastContractName());
Json::Value expectedDocumentation;
m_reader.parse(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(
Expand Down

0 comments on commit 4e7d144

Please sign in to comment.