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
|
vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
|
||||||
{
|
{
|
||||||
if (!m_inheritableMembers)
|
if (!m_inheritableMembers)
|
||||||
|
@ -358,6 +358,8 @@ public:
|
|||||||
Json::Value const& devDocumentation() const;
|
Json::Value const& devDocumentation() const;
|
||||||
void setDevDocumentation(Json::Value const& _devDocumentation);
|
void setDevDocumentation(Json::Value const& _devDocumentation);
|
||||||
|
|
||||||
|
std::string fullyQualifiedName() const;
|
||||||
|
|
||||||
virtual TypePointer type() const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual ContractDefinitionAnnotation& annotation() const override;
|
virtual ContractDefinitionAnnotation& annotation() const override;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
* Full-stack compiler that converts a source code string to bytecode.
|
* Full-stack compiler that converts a source code string to bytecode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <libsolidity/interface/CompilerStack.h>
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
|
|
||||||
#include <libsolidity/interface/Version.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->currentThis())) return false;
|
||||||
if (!resolver.updateDeclaration(*m_globalContext->currentSuper())) return false;
|
if (!resolver.updateDeclaration(*m_globalContext->currentSuper())) return false;
|
||||||
if (!resolver.resolveNamesAndTypes(*contract)) 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)
|
if (contract != existingContract)
|
||||||
BOOST_THROW_EXCEPTION(DeclarationError() <<
|
BOOST_THROW_EXCEPTION(CompilerError() <<
|
||||||
errinfo_sourceLocation(contract->location()) <<
|
errinfo_sourceLocation(contract->location()) <<
|
||||||
errinfo_comment(contract->name() + " is already defined.") <<
|
errinfo_comment(contract->name() + " is already defined.") <<
|
||||||
errinfo_secondarySourceLocation(
|
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())
|
if (!checkLibraryNameClashes())
|
||||||
@ -211,9 +213,9 @@ bool CompilerStack::parse()
|
|||||||
else
|
else
|
||||||
noErrors = false;
|
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)
|
if (contract != existingContract)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() <<
|
BOOST_THROW_EXCEPTION(CompilerError() <<
|
||||||
errinfo_sourceLocation(contract->location()) <<
|
errinfo_sourceLocation(contract->location()) <<
|
||||||
@ -221,7 +223,7 @@ bool CompilerStack::parse()
|
|||||||
+ *(existingContract->location().sourceName)));
|
+ *(existingContract->location().sourceName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_contracts[contract->name()].contract = contract;
|
m_contracts[contract->fullyQualifiedName()].contract = contract;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noErrors)
|
if (noErrors)
|
||||||
@ -335,6 +337,28 @@ string const* CompilerStack::runtimeSourceMapping(string const& _contractName) c
|
|||||||
return c.runtimeSourceMapping.get();
|
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
|
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
|
||||||
{
|
{
|
||||||
return contract(_contractName).object;
|
return contract(_contractName).object;
|
||||||
@ -598,7 +622,7 @@ bool CompilerStack::checkLibraryNameClashes()
|
|||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
if (contract->isLibrary())
|
if (contract->isLibrary())
|
||||||
{
|
{
|
||||||
if (libraries.count(contract->name()))
|
if (libraries.count(contract->fullyQualifiedName()))
|
||||||
{
|
{
|
||||||
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
||||||
*err <<
|
*err <<
|
||||||
@ -615,7 +639,7 @@ bool CompilerStack::checkLibraryNameClashes()
|
|||||||
clashFound = true;
|
clashFound = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
libraries[contract->name()] = contract->location();
|
libraries[contract->fullyQualifiedName()] = contract->location();
|
||||||
}
|
}
|
||||||
return !clashFound;
|
return !clashFound;
|
||||||
}
|
}
|
||||||
@ -648,7 +672,7 @@ void CompilerStack::compileContract(
|
|||||||
compileContract(*dependency, _compiledContracts);
|
compileContract(*dependency, _compiledContracts);
|
||||||
|
|
||||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
|
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);
|
string onChainMetadata = createOnChainMetadata(compiledContract);
|
||||||
bytes cborEncodedMetadata =
|
bytes cborEncodedMetadata =
|
||||||
// CBOR-encoding of {"bzzr0": dev::swarmHash(onChainMetadata)}
|
// 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 (auto const& it: m_sources)
|
||||||
for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
|
for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
|
||||||
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
|
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
|
||||||
contractName = contract->name();
|
contractName = contract->fullyQualifiedName();
|
||||||
auto it = m_contracts.find(contractName);
|
auto it = m_contracts.find(contractName);
|
||||||
if (it == m_contracts.end())
|
if (it == m_contracts.end())
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
|
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.
|
/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
|
||||||
/// if the contract does not (yet) have bytecode.
|
/// 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;
|
||||||
|
|
||||||
|
/// @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
|
/// @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
|
/// returned by the constructor or the zero-h256 if the contract still needs to be linked or
|
||||||
/// does not have runtime code.
|
/// 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_argBinary))
|
||||||
{
|
{
|
||||||
if (m_args.count(g_argOutputDir))
|
if (m_args.count("output-dir"))
|
||||||
createFile(_contract + ".bin", m_compiler->object(_contract).toHex());
|
{
|
||||||
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", m_compiler->object(_contract).toHex());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cout << "Binary: " << endl;
|
cout << "Binary: " << endl;
|
||||||
|
Loading…
Reference in New Issue
Block a user