aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRhett Aultman <roadriverrail@gmail.com>2016-12-12 06:17:38 +0800
committerRhett Aultman <rhett.aultman@meraki.net>2017-01-17 01:32:57 +0800
commit071b936b371cd5287717d0ac27b80b837836809a (patch)
treeb4aa6fc05ef1ee3ebec47d7c4ada0c2c0a14a10e
parent9e88f1eebe27c780c80be06d702eac30e2fc5fa3 (diff)
downloaddexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.tar
dexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.tar.gz
dexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.tar.bz2
dexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.tar.lz
dexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.tar.xz
dexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.tar.zst
dexon-solidity-071b936b371cd5287717d0ac27b80b837836809a.zip
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.
-rw-r--r--libsolidity/ast/AST.cpp6
-rw-r--r--libsolidity/ast/AST.h2
-rw-r--r--libsolidity/interface/CompilerStack.cpp48
-rw-r--r--libsolidity/interface/CompilerStack.h4
-rw-r--r--solc/CommandLineInterface.cpp6
5 files changed, 52 insertions, 14 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 6f7a64dc..480fce44 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -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)
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 2d092408..060cf973 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -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;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 9c4618e7..13cf7d6c 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -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."));
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index d49a8df1..9436bd83 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -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.
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index e322455b..cebc9a07 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -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;