mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Only avoid collision if it's the same file
@chriseth had suggested that it would be better if contracts were referenced in a file:contract notation, and that we output .bin files that prepend original path names if necessary to avoid a collision. This commit is mostly a draft; it still needs to be run through the test suite.
This commit is contained in:
parent
9e88f1eebe
commit
071b936b37
@ -190,6 +190,12 @@ void ContractDefinition::setUserDocumentation(Json::Value const& _userDocumentat
|
||||
}
|
||||
|
||||
|
||||
std::string ContractDefinition::fullyQualifiedName() const
|
||||
{
|
||||
std::string qualifiedName = *(location().sourceName) + ":" + name();
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
|
||||
{
|
||||
if (!m_inheritableMembers)
|
||||
|
@ -358,6 +358,8 @@ public:
|
||||
Json::Value const& devDocumentation() const;
|
||||
void setDevDocumentation(Json::Value const& _devDocumentation);
|
||||
|
||||
std::string fullyQualifiedName() const;
|
||||
|
||||
virtual TypePointer type() const override;
|
||||
|
||||
virtual ContractDefinitionAnnotation& annotation() const override;
|
||||
|
@ -21,6 +21,7 @@
|
||||
* Full-stack compiler that converts a source code string to bytecode.
|
||||
*/
|
||||
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
|
||||
#include <libsolidity/interface/Version.h>
|
||||
@ -180,17 +181,18 @@ bool CompilerStack::parse()
|
||||
if (!resolver.updateDeclaration(*m_globalContext->currentThis())) return false;
|
||||
if (!resolver.updateDeclaration(*m_globalContext->currentSuper())) return false;
|
||||
if (!resolver.resolveNamesAndTypes(*contract)) return false;
|
||||
if (m_contracts.find(contract->name()) != m_contracts.end())
|
||||
|
||||
if (m_contracts.find(contract->fullyQualifiedName()) != m_contracts.end())
|
||||
{
|
||||
const ContractDefinition* existingContract = m_contracts.find(contract->name())->second.contract;
|
||||
const ContractDefinition* existingContract = m_contracts.find(contract->fullyQualifiedName())->second.contract;
|
||||
if (contract != existingContract)
|
||||
BOOST_THROW_EXCEPTION(DeclarationError() <<
|
||||
BOOST_THROW_EXCEPTION(CompilerError() <<
|
||||
errinfo_sourceLocation(contract->location()) <<
|
||||
errinfo_comment(contract->name() + " is already defined.") <<
|
||||
errinfo_secondarySourceLocation(
|
||||
SecondarySourceLocation().append(existingContract->location()), "Previous definition is here:"));
|
||||
SecondarySourceLocation().append("Previous definition is here:", existingContract->location())));
|
||||
}
|
||||
m_contracts[contract->name()].contract = contract;
|
||||
m_contracts[contract->fullyQualifiedName()].contract = contract;
|
||||
}
|
||||
|
||||
if (!checkLibraryNameClashes())
|
||||
@ -211,9 +213,9 @@ bool CompilerStack::parse()
|
||||
else
|
||||
noErrors = false;
|
||||
|
||||
if (m_contracts.find(contract->name()) != m_contracts.end())
|
||||
if (m_contracts.find(contract->fullyQualifiedName()) != m_contracts.end())
|
||||
{
|
||||
const ContractDefinition* existingContract = m_contracts.find(contract->name())->second.contract;
|
||||
const ContractDefinition* existingContract = m_contracts.find(contract->fullyQualifiedName())->second.contract;
|
||||
if (contract != existingContract)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() <<
|
||||
errinfo_sourceLocation(contract->location()) <<
|
||||
@ -221,7 +223,7 @@ bool CompilerStack::parse()
|
||||
+ *(existingContract->location().sourceName)));
|
||||
}
|
||||
|
||||
m_contracts[contract->name()].contract = contract;
|
||||
m_contracts[contract->fullyQualifiedName()].contract = contract;
|
||||
}
|
||||
|
||||
if (noErrors)
|
||||
@ -335,6 +337,28 @@ string const* CompilerStack::runtimeSourceMapping(string const& _contractName) c
|
||||
return c.runtimeSourceMapping.get();
|
||||
}
|
||||
|
||||
std::string const CompilerStack::filesystemFriendlyName(string const& _contractName) const
|
||||
{
|
||||
// Look up the contract (by its fully-qualified name)
|
||||
Contract const& matchContract = m_contracts.at(_contractName);
|
||||
// Check to see if it could collide on name
|
||||
for (auto const& contract: m_contracts)
|
||||
{
|
||||
if (contract.second.contract->name() == matchContract.contract->name() &&
|
||||
contract.second.contract != matchContract.contract)
|
||||
{
|
||||
// If it does, then return its fully-qualified name, made fs-friendly
|
||||
std::string friendlyName = boost::algorithm::replace_all_copy(_contractName, "/", "_");
|
||||
boost::algorithm::replace_all(friendlyName, ":", "_");
|
||||
boost::algorithm::replace_all(friendlyName, ".", "_");
|
||||
return friendlyName;
|
||||
}
|
||||
}
|
||||
// If no collision, return the contract's name
|
||||
// String is copied to ensure that the contract's name can't be messed with
|
||||
return std::string(matchContract.contract->name());
|
||||
}
|
||||
|
||||
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
|
||||
{
|
||||
return contract(_contractName).object;
|
||||
@ -598,7 +622,7 @@ bool CompilerStack::checkLibraryNameClashes()
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
if (contract->isLibrary())
|
||||
{
|
||||
if (libraries.count(contract->name()))
|
||||
if (libraries.count(contract->fullyQualifiedName()))
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
||||
*err <<
|
||||
@ -615,7 +639,7 @@ bool CompilerStack::checkLibraryNameClashes()
|
||||
clashFound = true;
|
||||
}
|
||||
else
|
||||
libraries[contract->name()] = contract->location();
|
||||
libraries[contract->fullyQualifiedName()] = contract->location();
|
||||
}
|
||||
return !clashFound;
|
||||
}
|
||||
@ -648,7 +672,7 @@ void CompilerStack::compileContract(
|
||||
compileContract(*dependency, _compiledContracts);
|
||||
|
||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
|
||||
Contract& compiledContract = m_contracts.at(_contract.name());
|
||||
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
||||
string onChainMetadata = createOnChainMetadata(compiledContract);
|
||||
bytes cborEncodedMetadata =
|
||||
// CBOR-encoding of {"bzzr0": dev::swarmHash(onChainMetadata)}
|
||||
@ -694,7 +718,7 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa
|
||||
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->name();
|
||||
contractName = contract->fullyQualifiedName();
|
||||
auto it = m_contracts.find(contractName);
|
||||
if (it == m_contracts.end())
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
|
||||
|
@ -148,6 +148,10 @@ public:
|
||||
/// @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;
|
||||
|
||||
/// @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 hash of the runtime bytecode for the contract, i.e. the code that is
|
||||
/// returned by the constructor or the zero-h256 if the contract still needs to be linked or
|
||||
/// does not have runtime code.
|
||||
|
@ -185,8 +185,10 @@ void CommandLineInterface::handleBinary(string const& _contract)
|
||||
{
|
||||
if (m_args.count(g_argBinary))
|
||||
{
|
||||
if (m_args.count(g_argOutputDir))
|
||||
createFile(_contract + ".bin", m_compiler->object(_contract).toHex());
|
||||
if (m_args.count("output-dir"))
|
||||
{
|
||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", m_compiler->object(_contract).toHex());
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Binary: " << endl;
|
||||
|
Loading…
Reference in New Issue
Block a user