aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/interface
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/interface')
-rw-r--r--libsolidity/interface/CompilerStack.cpp118
-rw-r--r--libsolidity/interface/CompilerStack.h9
-rw-r--r--libsolidity/interface/InterfaceHandler.cpp48
-rw-r--r--libsolidity/interface/InterfaceHandler.h10
-rw-r--r--libsolidity/interface/Version.cpp4
-rw-r--r--libsolidity/interface/Version.h1
6 files changed, 122 insertions, 68 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index a31df584..3335c40e 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>
@@ -111,6 +112,7 @@ bool CompilerStack::parse()
{
//reset
m_errors.clear();
+ ASTNode::resetID();
m_parseSuccessful = false;
if (SemVerVersion{string(VersionString)}.isPrerelease())
@@ -180,11 +182,15 @@ 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;
- m_contracts[contract->name()].contract = contract;
- }
- if (!checkLibraryNameClashes())
- noErrors = false;
+ // Note that we now reference contracts by their fully qualified names, and
+ // thus contracts can only conflict if declared in the same source file. This
+ // already causes a double-declaration error elsewhere, so we do not report
+ // an error here and instead silently drop any additional contracts we find.
+
+ if (m_contracts.find(contract->fullyQualifiedName()) == m_contracts.end())
+ m_contracts[contract->fullyQualifiedName()].contract = contract;
+ }
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
@@ -201,7 +207,13 @@ bool CompilerStack::parse()
else
noErrors = false;
- m_contracts[contract->name()].contract = contract;
+ // Note that we now reference contracts by their fully qualified names, and
+ // thus contracts can only conflict if declared in the same source file. This
+ // already causes a double-declaration error elsewhere, so we do not report
+ // an error here and instead silently drop any additional contracts we find.
+
+ if (m_contracts.find(contract->fullyQualifiedName()) == m_contracts.end())
+ m_contracts[contract->fullyQualifiedName()].contract = contract;
}
if (noErrors)
@@ -315,6 +327,27 @@ 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
+ return matchContract.contract->name();
+}
+
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
{
return contract(_contractName).object;
@@ -569,37 +602,6 @@ void CompilerStack::resolveImports()
swap(m_sourceOrder, sourceOrder);
}
-bool CompilerStack::checkLibraryNameClashes()
-{
- bool clashFound = false;
- map<string, SourceLocation> libraries;
- for (Source const* source: m_sourceOrder)
- for (ASTPointer<ASTNode> const& node: source->ast->nodes())
- if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
- if (contract->isLibrary())
- {
- if (libraries.count(contract->name()))
- {
- auto err = make_shared<Error>(Error::Type::DeclarationError);
- *err <<
- errinfo_sourceLocation(contract->location()) <<
- errinfo_comment(
- "Library \"" + contract->name() + "\" declared twice "
- "(will create ambiguities during linking)."
- ) <<
- errinfo_secondarySourceLocation(SecondarySourceLocation().append(
- "The other declaration is here:", libraries[contract->name()]
- ));
-
- m_errors.push_back(err);
- clashFound = true;
- }
- else
- libraries[contract->name()] = contract->location();
- }
- return !clashFound;
-}
-
string CompilerStack::absolutePath(string const& _path, string const& _reference) const
{
using path = boost::filesystem::path;
@@ -622,13 +624,17 @@ void CompilerStack::compileContract(
map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
)
{
- if (_compiledContracts.count(&_contract) || !_contract.annotation().isFullyImplemented)
+ if (
+ _compiledContracts.count(&_contract) ||
+ !_contract.annotation().isFullyImplemented ||
+ !_contract.annotation().hasPublicConstructor
+ )
return;
for (auto const* dependency: _contract.annotation().contractDependencies)
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)}
@@ -674,10 +680,27 @@ 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())
+ // 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)
+ {
+ for (auto const& contractEntry: m_contracts)
+ {
+ stringstream ss;
+ ss.str(contractEntry.first);
+ // All entries are <source>:<contract>
+ string source;
+ string foundName;
+ getline(ss, source, ':');
+ getline(ss, foundName, ':');
+ 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;
}
@@ -695,7 +718,7 @@ string CompilerStack::createOnChainMetadata(Contract const& _contract) const
Json::Value meta;
meta["version"] = 1;
meta["language"] = "Solidity";
- meta["compiler"]["version"] = VersionString;
+ meta["compiler"]["version"] = VersionStringStrict;
meta["sources"] = Json::objectValue;
for (auto const& s: m_sources)
@@ -703,10 +726,15 @@ string CompilerStack::createOnChainMetadata(Contract const& _contract) const
solAssert(s.second.scanner, "Scanner not available");
meta["sources"][s.first]["keccak256"] =
"0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes());
- meta["sources"][s.first]["urls"] = Json::arrayValue;
- meta["sources"][s.first]["urls"].append(
- "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes())
- );
+ if (m_metadataLiteralSources)
+ meta["sources"][s.first]["content"] = s.second.scanner->source();
+ else
+ {
+ meta["sources"][s.first]["urls"] = Json::arrayValue;
+ meta["sources"][s.first]["urls"].append(
+ "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes())
+ );
+ }
}
meta["settings"]["optimizer"]["enabled"] = m_optimize;
meta["settings"]["optimizer"]["runs"] = m_optimizeRuns;
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index d49a8df1..9ee70215 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.
@@ -173,6 +177,7 @@ public:
/// Can be one of 4 types defined at @c DocumentationType
Json::Value const& metadata(std::string const& _contractName, DocumentationType _type) const;
std::string const& onChainMetadata(std::string const& _contractName) const;
+ void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; }
/// @returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& scanner(std::string const& _sourceName = "") const;
@@ -230,9 +235,6 @@ private:
StringMap loadMissingSources(SourceUnit const& _ast, std::string const& _path);
std::string applyRemapping(std::string const& _path, std::string const& _context);
void resolveImports();
- /// Checks whether there are libraries with the same name, reports that as an error and
- /// @returns false in this case.
- bool checkLibraryNameClashes();
/// @returns the absolute path corresponding to @a _path relative to @a _reference.
std::string absolutePath(std::string const& _path, std::string const& _reference) const;
/// Helper function to return path converted strings.
@@ -273,6 +275,7 @@ private:
std::map<std::string const, Contract> m_contracts;
std::string m_formalTranslation;
ErrorList m_errors;
+ bool m_metadataLiteralSources = false;
};
}
diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp
index 9944bb22..6c1bb0c4 100644
--- a/libsolidity/interface/InterfaceHandler.cpp
+++ b/libsolidity/interface/InterfaceHandler.cpp
@@ -30,20 +30,6 @@ Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDe
{
Json::Value abi(Json::arrayValue);
- auto populateParameters = [](vector<string> const& _paramNames, vector<string> const& _paramTypes)
- {
- Json::Value params(Json::arrayValue);
- solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match");
- for (unsigned i = 0; i < _paramNames.size(); ++i)
- {
- Json::Value param;
- param["name"] = _paramNames[i];
- param["type"] = _paramTypes[i];
- params.append(param);
- }
- return params;
- };
-
for (auto it: _contractDef.interfaceFunctions())
{
auto externalFunctionType = it.second->interfaceFunctionType();
@@ -52,13 +38,15 @@ Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDe
method["name"] = it.second->declaration().name();
method["constant"] = it.second->isConstant();
method["payable"] = it.second->isPayable();
- method["inputs"] = populateParameters(
+ method["inputs"] = formatTypeList(
externalFunctionType->parameterNames(),
- externalFunctionType->parameterTypeNames(_contractDef.isLibrary())
+ externalFunctionType->parameterTypes(),
+ _contractDef.isLibrary()
);
- method["outputs"] = populateParameters(
+ method["outputs"] = formatTypeList(
externalFunctionType->returnParameterNames(),
- externalFunctionType->returnParameterTypeNames(_contractDef.isLibrary())
+ externalFunctionType->returnParameterTypes(),
+ _contractDef.isLibrary()
);
abi.append(method);
}
@@ -69,9 +57,10 @@ Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDe
auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType();
solAssert(!!externalFunction, "");
method["payable"] = externalFunction->isPayable();
- method["inputs"] = populateParameters(
+ method["inputs"] = formatTypeList(
externalFunction->parameterNames(),
- externalFunction->parameterTypeNames(_contractDef.isLibrary())
+ externalFunction->parameterTypes(),
+ _contractDef.isLibrary()
);
abi.append(method);
}
@@ -179,6 +168,25 @@ Json::Value InterfaceHandler::devDocumentation(ContractDefinition const& _contra
return doc;
}
+Json::Value InterfaceHandler::formatTypeList(
+ vector<string> const& _names,
+ vector<TypePointer> const& _types,
+ bool _forLibrary
+)
+{
+ Json::Value params(Json::arrayValue);
+ solAssert(_names.size() == _types.size(), "Names and types vector size does not match");
+ for (unsigned i = 0; i < _names.size(); ++i)
+ {
+ solAssert(_types[i], "");
+ Json::Value param;
+ param["name"] = _names[i];
+ param["type"] = _types[i]->canonicalName(_forLibrary);
+ params.append(param);
+ }
+ return params;
+}
+
string InterfaceHandler::extractDoc(multimap<string, DocTag> const& _tags, string const& _name)
{
string value;
diff --git a/libsolidity/interface/InterfaceHandler.h b/libsolidity/interface/InterfaceHandler.h
index b7e1bb00..56927d44 100644
--- a/libsolidity/interface/InterfaceHandler.h
+++ b/libsolidity/interface/InterfaceHandler.h
@@ -37,6 +37,8 @@ namespace solidity
// Forward declarations
class ContractDefinition;
+class Type;
+using TypePointer = std::shared_ptr<Type const>;
struct DocTag;
enum class DocumentationType: uint8_t;
@@ -84,6 +86,14 @@ public:
static Json::Value devDocumentation(ContractDefinition const& _contractDef);
private:
+ /// @returns a json value suitable for a list of types in function input or output
+ /// parameters or other places. If @a _forLibrary is true, complex types are referenced
+ /// by name, otherwise they are anonymously expanded.
+ static Json::Value formatTypeList(
+ std::vector<std::string> const& _names,
+ std::vector<TypePointer> const& _types,
+ bool _forLibrary
+ );
/// @returns concatenation of all content under the given tag name.
static std::string extractDoc(std::multimap<std::string, DocTag> const& _tags, std::string const& _name);
};
diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp
index ff66f039..0d23f9c3 100644
--- a/libsolidity/interface/Version.cpp
+++ b/libsolidity/interface/Version.cpp
@@ -38,6 +38,10 @@ string const dev::solidity::VersionString =
(string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
(string(SOL_VERSION_BUILDINFO).empty() ? "" : "+" + string(SOL_VERSION_BUILDINFO));
+string const dev::solidity::VersionStringStrict =
+ string(dev::solidity::VersionNumber) +
+ (string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
+ (string(SOL_VERSION_COMMIT).empty() ? "" : "+" + string(SOL_VERSION_COMMIT));
bytes dev::solidity::binaryVersion()
{
diff --git a/libsolidity/interface/Version.h b/libsolidity/interface/Version.h
index 5b07b3f4..24c3555d 100644
--- a/libsolidity/interface/Version.h
+++ b/libsolidity/interface/Version.h
@@ -32,6 +32,7 @@ namespace solidity
extern char const* VersionNumber;
extern std::string const VersionString;
+extern std::string const VersionStringStrict;
/// @returns a binary form of the version string, where A.B.C-HASH is encoded such that
/// the first byte is zero, the following three bytes encode A B and C (interpreted as decimals)