aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--docs/layout-of-source-files.rst78
-rw-r--r--docs/style-guide.rst97
-rw-r--r--libsolidity/analysis/DeclarationContainer.cpp11
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp57
-rw-r--r--libsolidity/analysis/TypeChecker.cpp16
-rw-r--r--libsolidity/ast/AST.h4
-rw-r--r--libsolidity/ast/Types.cpp4
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp2
-rw-r--r--libsolidity/interface/CompilerStack.cpp125
-rw-r--r--libsolidity/interface/CompilerStack.h19
-rw-r--r--libsolidity/parsing/Parser.cpp2
-rw-r--r--solc/CommandLineInterface.cpp13
-rw-r--r--test/libsolidity/Imports.cpp41
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp11
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp21
16 files changed, 432 insertions, 70 deletions
diff --git a/.gitignore b/.gitignore
index ebd0881e..18cdd96f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,7 @@
# Build directory
build/
+docs/_build
# vim stuff
*.swp
diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst
index 445162f5..1128685d 100644
--- a/docs/layout-of-source-files.rst
+++ b/docs/layout-of-source-files.rst
@@ -9,24 +9,78 @@ Source files can contain an arbitrary number of contract definitions and include
Importing other Source Files
============================
+Syntax and Semantics
+--------------------
-Other source files can be referenced using `import "filename";` and the symbols
-defined there will also be available in the current source file.
+Solidity supports import statements that are very similar to those available in JavaScript
+(from ES6 on), although Solidity does not know the concept of a "default export".
-.. warning::
+At a global level, you can use import statements of the following form:
- Import will not work automatically for the commandline-compiler.
- Furthermore, this system of importing other files is not completely fleshed out
- yet, so please expect changes.
+`import "filename";` will import all global symbols from "filename" (and symbols imported there) into the current global scope (different than in ES6 but backwards-compatible for Solidity).
+
+`import * as symbolName from "filename";` creates a new global symbol `symbolName` whose members are all the global symbols from `"filename"`.
+
+`import {symbol1 as alias, symbol2} from "filename";` creates new global symbols `alias` and `symbol2` which reference `symbol1` and `symbal2` from `"filename"`, respectively.
+
+Another syntax is not part of ES6, but probably convenient:
+
+`import "filename" as symbolName;` is equivalent to `import * as symbolName from "filename";`.
+
+Paths
+-----
+
+In the above, `filename` is always treated as a path with `/` as directory separator,
+`.` as the current and `..` as the parent directory. Path names that do not start
+with `.` are treated as absolute paths.
+
+To import a file `x` from the same directory as the current file, use `import "./x" as x;`.
+If you use `import "x" as x;` instead, a different file could be referenced
+(in a global "include directory").
+
+It depends on the compiler (see below) how to actually resolve the paths.
+In general, the directory hierarchy does not need to strictly map onto your local
+filesystem, it can also map to resources discovered via e.g. ipfs, http or git.
+
+Use in actual Compilers
+-----------------------
+
+When the compiler is invoked, it is not only possible to specify how to
+discover the first element of a path, but it is possible to specify path prefix
+remappings so that e.g. `github.com/ethereum/dapp-bin/library` is remapped to
+`/usr/local/dapp-bin/library` and the compiler will read the files from there. If
+remapping keys are prefixes of each other, the longest is tried first. This
+allows for a "fallback-remapping" with e.g. `""` maps to
+`"/usr/local/include/solidity"`.
+
+**solc**:
+
+For solc (the commandline compiler), these remappings are provided as `key=value`
+arguments, where the `=value` part is optional (and defaults to key in that
+case). All remapping values that are regular files are compiled (including
+their dependencies). This mechanism is completely backwards-compatible (as long
+as no filename contains a =) and thus not a breaking change.
+
+So as an example, if you clone
+`github.com/ethereum/dapp-bin/` locally to `/usr/local/dapp-bin`, you can use
+the following in your source file:
+
+`import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;`
+
+and then run the compiler as
+
+`solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol`
+
+**browser-solidity**:
The `browser-based compiler <https://chriseth.github.io/browser-solidity>`_
-has quite advanced support for multiple files and can even import files
-directly from github, by using e.g.
-```import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol";```
+provides an automatic remapping for github and will also automatically retrieve
+the file over the network:
+You can import the iterable mapping by e.g.
+`import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;`.
+
+Other source code providers may be added in the future.
-If you want to use multiple source files with the (commandline compiler)[../commandline-compiler/] solc,
-you have to specify all files you will use as arguments to solc,
-the compiler will not yet search your filesystem on its own.
.. index:: ! comment, natspec
diff --git a/docs/style-guide.rst b/docs/style-guide.rst
index cd901e63..0e782e23 100644
--- a/docs/style-guide.rst
+++ b/docs/style-guide.rst
@@ -529,10 +529,105 @@ No::
x = y+z;
x +=1;
+
+******************
Naming Conventions
+******************
+
+Naming conventions are powerful when adopted and used broadly. The use of
+different conventions can convey significant *meta* information that would
+otherwise not be immediately available.
+
+The naming recommendations given here are intended to improve the readability,
+and thus they are not rules, but rather guidelines to try and help convey the
+most information through the names of things.
+
+Lastly, consistency within a codebase should always supercede any conventions
+outlined in this document.
+
+
+Naming Styles
+=============
+
+To avoid confusion, the following names will be used to refer to different
+naming styles.
+
+* ``b`` (single lowercase letter)
+* ``B`` (single uppercase letter)
+* ``lowercase``
+* ``lower_case_with_underscores``
+* ``UPPERCASE``
+* ``UPPER_CASE_WITH_UNDERSCORES``
+* ``CapitalizedWords`` (or CapWords)
+* ``mixedCase`` (differs from CapitalizedWords by initial lowercase character!)
+* ``Capitalized_Words_With_Underscores``
+
+.. note:: When using abbreviations in CapWords, capitalize all the letters of the abbreviation. Thus HTTPServerError is better than HttpServerError.
+
+
+Names to Avoid
+==============
+
+* ``l`` - Lowercase letter el
+* ``O`` - Uppercase letter oh
+* ``I`` - Uppercase letter eye
+
+Never use any of these for single letter variable names. They are often
+indistinguishable from the numerals one and zero.
+
+
+Contract and Library Names
+==========================
+
+Contracts should be named using the CapWords style.
+
+
+Events
+======
+
+Events should be named using the CapWords style.
+
+
+Function Names
+==============
+
+Functions should use mixedCase.
+
+
+Function Arguments
==================
-TODO
+When writing library functions that operate on a custom struct, the struct
+should be the first argument and should always be named ``self``.
+
+
+Local and State Variables
+=========================
+
+Use mixedCase.
+
+
+Constants
+=========
+
+Constants should be named with all capital letters with underscores separating
+words. (for example:``MAX_BLOCKS``)
+
+
+Modifiers
+=========
+
+Function modifiers should use lowercase words separated by underscores.
+
+
+Avoiding Collisions
+===================
+
+* ``single_trailing_underscore_``
+
+This convention is suggested when the desired name collides with that of a
+built-in or otherwise reserved name.
+
General Recommendations
=======================
diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp
index ac56562e..042b7a6a 100644
--- a/libsolidity/analysis/DeclarationContainer.cpp
+++ b/libsolidity/analysis/DeclarationContainer.cpp
@@ -49,6 +49,8 @@ Declaration const* DeclarationContainer::conflictingDeclaration(
if (!dynamic_cast<FunctionDefinition const*>(declaration))
return declaration;
}
+ else if (declarations.size() == 1 && declarations.front() == &_declaration)
+ return nullptr;
else if (!declarations.empty())
return declarations.front();
@@ -73,13 +75,12 @@ bool DeclarationContainer::registerDeclaration(
m_declarations.erase(*_name);
m_invisibleDeclarations.erase(*_name);
}
- else if (conflictingDeclaration(_declaration))
+ else if (conflictingDeclaration(_declaration, _name))
return false;
- if (_invisible)
- m_invisibleDeclarations[*_name].push_back(&_declaration);
- else
- m_declarations[*_name].push_back(&_declaration);
+ vector<Declaration const*>& decls = _invisible ? m_invisibleDeclarations[*_name] : m_declarations[*_name];
+ if (!contains(decls, &_declaration))
+ decls.push_back(&_declaration);
return true;
}
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index 96ffdd6e..5e407383 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -76,23 +76,58 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
string const& path = imp->annotation().absolutePath;
if (!_sourceUnits.count(path))
{
- reportDeclarationError( node->location(),
- "Import \"" +
- path +
- "\" (referenced as \"" +
- imp->path() +
- "\") not found."
+ reportDeclarationError(
+ imp->location(),
+ "Import \"" + path + "\" (referenced as \"" + imp->path() + "\") not found."
);
error = true;
+ continue;
}
+ auto scope = m_scopes.find(_sourceUnits.at(path));
+ solAssert(scope != end(m_scopes), "");
+ if (!imp->symbolAliases().empty())
+ for (auto const& alias: imp->symbolAliases())
+ {
+ auto declarations = scope->second->resolveName(alias.first->name(), false);
+ if (declarations.empty())
+ {
+ reportDeclarationError(
+ imp->location(),
+ "Declaration \"" +
+ alias.first->name() +
+ "\" not found in \"" +
+ path +
+ "\" (referenced as \"" +
+ imp->path() +
+ "\")."
+ );
+ error = true;
+ }
+ else
+ for (Declaration const* declaration: declarations)
+ {
+ ASTString const* name = alias.second ? alias.second.get() : &declaration->name();
+ if (!target.registerDeclaration(*declaration, name))
+ {
+ reportDeclarationError(
+ imp->location(),
+ "Identifier \"" + *name + "\" already declared."
+ );
+ error = true;
+ }
+ }
+ }
else if (imp->name().empty())
- {
- auto scope = m_scopes.find(_sourceUnits.at(path));
- solAssert(scope != end(m_scopes), "");
for (auto const& nameAndDeclaration: scope->second->declarations())
for (auto const& declaration: nameAndDeclaration.second)
- target.registerDeclaration(*declaration, &nameAndDeclaration.first);
- }
+ if (!target.registerDeclaration(*declaration, &nameAndDeclaration.first))
+ {
+ reportDeclarationError(
+ imp->location(),
+ "Identifier \"" + nameAndDeclaration.first + "\" already declared."
+ );
+ error = true;
+ }
}
return !error;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index ab1151a1..69357043 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -292,17 +292,21 @@ void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _co
if (f->isPartOfExternalInterface())
{
auto functionType = make_shared<FunctionType>(*f);
- externalDeclarations[functionType->externalSignature()].push_back(
- make_pair(f, functionType)
- );
+ // under non error circumstances this should be true
+ if (functionType->interfaceFunctionType())
+ externalDeclarations[functionType->externalSignature()].push_back(
+ make_pair(f, functionType)
+ );
}
for (VariableDeclaration const* v: contract->stateVariables())
if (v->isPartOfExternalInterface())
{
auto functionType = make_shared<FunctionType>(*v);
- externalDeclarations[functionType->externalSignature()].push_back(
- make_pair(v, functionType)
- );
+ // under non error circumstances this should be true
+ if (functionType->interfaceFunctionType())
+ externalDeclarations[functionType->externalSignature()].push_back(
+ make_pair(v, functionType)
+ );
}
}
for (auto const& it: externalDeclarations)
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 604a12a0..4baf95d3 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -201,6 +201,10 @@ public:
virtual void accept(ASTConstVisitor& _visitor) const override;
ASTString const& path() const { return *m_path; }
+ std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> const& symbolAliases() const
+ {
+ return m_symbolAliases;
+ }
virtual ImportAnnotation& annotation() const override;
virtual TypePointer type() const override;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 2e9b56a1..79e5bb02 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -1593,6 +1593,10 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
else
return FunctionTypePointer();
}
+ auto variable = dynamic_cast<VariableDeclaration const*>(m_declaration);
+ if (variable && retParamTypes.empty())
+ return FunctionTypePointer();
+
return make_shared<FunctionType>(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters);
}
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index f0dab41a..040217da 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -807,7 +807,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
);
auto contract = dynamic_cast<ContractDefinition const*>(funType->declaration().scope());
solAssert(contract && contract->isLibrary(), "");
- //@TODO library name might not be unique
m_context.appendLibraryAddress(contract->name());
m_context << funType->externalIdentifier();
utils().moveIntoStack(funType->selfType()->sizeOnStack(), 2);
@@ -1118,7 +1117,6 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{
if (contract->isLibrary())
- //@todo name should be unique, change once we have module management
m_context.appendLibraryAddress(contract->name());
}
else if (dynamic_cast<EventDefinition const*>(declaration))
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 8ff63056..83459183 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -39,11 +39,8 @@
#include <libdevcore/SHA3.h>
using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
+using namespace dev;
+using namespace dev::solidity;
const map<string, string> StandardSources = map<string, string>{
{"coin", R"(import "CoinReg";import "Config";import "configUser";contract coin is configUser{function coin(bytes3 name, uint denom) {CoinReg(Config(configAddr()).lookup(3)).register(name, denom);}})"},
@@ -59,8 +56,8 @@ const map<string, string> StandardSources = map<string, string>{
{"std", R"(import "owned";import "mortal";import "Config";import "configUser";import "NameReg";import "named";)"}
};
-CompilerStack::CompilerStack(bool _addStandardSources):
- m_parseSuccessful(false)
+CompilerStack::CompilerStack(bool _addStandardSources, ReadFileCallback const& _readFile):
+ m_readFile(_readFile), m_parseSuccessful(false)
{
if (_addStandardSources)
addSources(StandardSources, true); // add them as libraries
@@ -105,16 +102,30 @@ bool CompilerStack::parse()
m_errors.clear();
m_parseSuccessful = false;
+ vector<string> sourcesToParse;
+ for (auto const& s: m_sources)
+ sourcesToParse.push_back(s.first);
map<string, SourceUnit const*> sourceUnitsByName;
- for (auto& sourcePair: m_sources)
+ for (size_t i = 0; i < sourcesToParse.size(); ++i)
{
- sourcePair.second.scanner->reset();
- sourcePair.second.ast = Parser(m_errors).parse(sourcePair.second.scanner);
- if (!sourcePair.second.ast)
+ string const& path = sourcesToParse[i];
+ Source& source = m_sources[path];
+ source.scanner->reset();
+ source.ast = Parser(m_errors).parse(source.scanner);
+ sourceUnitsByName[path] = source.ast.get();
+ if (!source.ast)
solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error.");
else
- sourcePair.second.ast->annotation().path = sourcePair.first;
- sourceUnitsByName[sourcePair.first] = sourcePair.second.ast.get();
+ {
+ source.ast->annotation().path = path;
+ for (auto const& newSource: loadMissingSources(*source.ast, path))
+ {
+ string const& newPath = newSource.first;
+ string const& newContents = newSource.second;
+ m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents), newPath);
+ sourcesToParse.push_back(newPath);
+ }
+ }
}
if (!Error::containsOnlyWarnings(m_errors))
// errors while parsing. sould stop before type checking
@@ -154,6 +165,9 @@ bool CompilerStack::parse()
m_contracts[contract->name()].contract = contract;
}
+ if (!checkLibraryNameClashes())
+ noErrors = false;
+
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
@@ -370,13 +384,44 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati
return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn);
}
+StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _path)
+{
+ StringMap newSources;
+ for (auto const& node: _ast.nodes())
+ if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
+ {
+ string path = absolutePath(import->path(), _path);
+ import->annotation().absolutePath = path;
+ if (m_sources.count(path) || newSources.count(path))
+ continue;
+ string contents;
+ string errorMessage;
+ if (!m_readFile)
+ errorMessage = "File not supplied initially.";
+ else
+ tie(contents, errorMessage) = m_readFile(path);
+ if (!errorMessage.empty())
+ {
+ auto err = make_shared<Error>(Error::Type::ParserError);
+ *err <<
+ errinfo_sourceLocation(import->location()) <<
+ errinfo_comment("Source not found: " + errorMessage);
+ m_errors.push_back(std::move(err));
+ continue;
+ }
+ else
+ newSources[path] = contents;
+ }
+ return newSources;
+}
+
void CompilerStack::resolveImports()
{
// topological sorting (depth first search) of the import graph, cutting potential cycles
vector<Source const*> sourceOrder;
set<Source const*> sourcesSeen;
- function<void(string const&, Source const*)> toposort = [&](string const& _sourceName, Source const* _source)
+ function<void(Source const*)> toposort = [&](Source const* _source)
{
if (sourcesSeen.count(_source))
return;
@@ -384,28 +429,53 @@ void CompilerStack::resolveImports()
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
{
- string path = absolutePath(import->path(), _sourceName);
- import->annotation().absolutePath = path;
- if (!m_sources.count(path))
- BOOST_THROW_EXCEPTION(
- Error(Error::Type::ParserError)
- << errinfo_sourceLocation(import->location())
- << errinfo_comment("Source not found.")
- );
- import->annotation().sourceUnit = m_sources.at(path).ast.get();
-
- toposort(path, &m_sources[path]);
+ string const& path = import->annotation().absolutePath;
+ solAssert(!path.empty(), "");
+ solAssert(m_sources.count(path), "");
+ import->annotation().sourceUnit = m_sources[path].ast.get();
+ toposort(&m_sources[path]);
}
sourceOrder.push_back(_source);
};
for (auto const& sourcePair: m_sources)
if (!sourcePair.second.isLibrary)
- toposort(sourcePair.first, &sourcePair.second);
+ toposort(&sourcePair.second);
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
{
// Anything that does not start with `.` is an absolute path.
@@ -479,6 +549,3 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co
return it->second;
}
-
-}
-}
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index 3e6dc456..517d0055 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -27,6 +27,7 @@
#include <string>
#include <memory>
#include <vector>
+#include <functional>
#include <boost/noncopyable.hpp>
#include <json/json.h>
#include <libdevcore/Common.h>
@@ -74,8 +75,14 @@ enum class DocumentationType: uint8_t
class CompilerStack: boost::noncopyable
{
public:
- /// Creates a new compiler stack. Adds standard sources if @a _addStandardSources.
- explicit CompilerStack(bool _addStandardSources = true);
+ /// File reading callback, should return a pair of content and error message (exactly one nonempty)
+ /// for a given path.
+ using ReadFileCallback = std::function<std::pair<std::string, std::string>(std::string const&)>;
+
+ /// Creates a new compiler stack.
+ /// @param _readFile callback to used to read files for import statements. Should return
+ /// @param _addStandardSources Adds standard sources if @a _addStandardSources.
+ explicit CompilerStack(bool _addStandardSources = true, ReadFileCallback const& _readFile = ReadFileCallback());
/// Resets the compiler to a state where the sources are not parsed or even removed.
void reset(bool _keepSources = false, bool _addStandardSources = true);
@@ -198,7 +205,14 @@ private:
mutable std::unique_ptr<std::string const> devDocumentation;
};
+ /// Loads the missing sources from @a _ast (named @a _path) using the callback
+ /// @a m_readFile and stores the absolute paths of all imports in the AST annotations.
+ /// @returns the newly loaded sources.
+ StringMap loadMissingSources(SourceUnit const& _ast, std::string const& _path);
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;
/// Compile a single contract and put the result in @a _compiledContracts.
@@ -212,6 +226,7 @@ private:
Contract const& contract(std::string const& _contractName = "") const;
Source const& source(std::string const& _sourceName = "") const;
+ ReadFileCallback m_readFile;
bool m_parseSuccessful;
std::map<std::string const, Source> m_sources;
std::shared_ptr<GlobalContext> m_globalContext;
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index 7dd3564d..4ac3381c 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -145,7 +145,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
expectToken(Token::As);
alias = expectIdentifierToken();
}
- symbolAliases.push_back(move(make_pair(move(id), move(alias))));
+ symbolAliases.push_back(make_pair(move(id), move(alias)));
if (m_scanner->currentToken() != Token::Comma)
break;
m_scanner->next();
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index fe760fdf..4c9de3c8 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -497,7 +497,18 @@ bool CommandLineInterface::processInput()
return link();
}
- m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0));
+ function<pair<string,string>(string const&)> fileReader = [this](string const& _path)
+ {
+ auto path = boost::filesystem::path(_path);
+ if (!boost::filesystem::exists(path))
+ return make_pair(string(), string("File not found."));
+ else if (!boost::filesystem::is_regular_file(path))
+ return make_pair(string(), string("Not a valid file."));
+ else
+ return make_pair(m_sourceCodes[_path] = dev::contentsString(_path), string());
+ };
+
+ m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0, fileReader));
try
{
for (auto const& sourceCode: m_sourceCodes)
diff --git a/test/libsolidity/Imports.cpp b/test/libsolidity/Imports.cpp
index f0f67785..94d3e423 100644
--- a/test/libsolidity/Imports.cpp
+++ b/test/libsolidity/Imports.cpp
@@ -101,6 +101,47 @@ BOOST_AUTO_TEST_CASE(simple_alias)
BOOST_CHECK(c.compile());
}
+BOOST_AUTO_TEST_CASE(library_name_clash)
+{
+ CompilerStack c;
+ c.addSource("a", "library A {}");
+ c.addSource("b", "library A {}");
+ BOOST_CHECK(!c.compile());
+}
+
+BOOST_AUTO_TEST_CASE(library_name_clash_with_contract)
+{
+ CompilerStack c;
+ c.addSource("a", "contract A {}");
+ c.addSource("b", "library A {}");
+ BOOST_CHECK(c.compile());
+}
+
+BOOST_AUTO_TEST_CASE(complex_import)
+{
+ CompilerStack c;
+ c.addSource("a", "contract A {} contract B {} contract C { struct S { uint a; } }");
+ c.addSource("b", "import \"a\" as x; import {B as b, C as c, C} from \"a\"; "
+ "contract D is b { function f(c.S var1, x.C.S var2, C.S var3) internal {} }");
+ BOOST_CHECK(c.compile());
+}
+
+BOOST_AUTO_TEST_CASE(name_clash_in_import)
+{
+ CompilerStack c;
+ c.addSource("a", "contract A {}");
+ c.addSource("b", "import \"a\"; contract A {} ");
+ BOOST_CHECK(!c.compile());
+ c.addSource("b", "import \"a\" as A; contract A {} ");
+ BOOST_CHECK(!c.compile());
+ c.addSource("b", "import {A as b} from \"a\"; contract b {} ");
+ BOOST_CHECK(!c.compile());
+ c.addSource("b", "import {A} from \"a\"; contract A {} ");
+ BOOST_CHECK(!c.compile());
+ c.addSource("b", "import {A} from \"a\"; contract B {} ");
+ BOOST_CHECK(c.compile());
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index a95021ea..c8e901e4 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -1008,6 +1008,17 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
BOOST_CHECK(success(text));
}
+BOOST_AUTO_TEST_CASE(struct_accessor_one_array_only)
+{
+ char const* sourceCode = R"(
+ contract test {
+ struct Data { uint[15] m_array; }
+ Data public data;
+ }
+ )";
+ BOOST_CHECK(expectError(sourceCode) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
{
char const* text = "contract Parent {\n"
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 732f599f..2f1eb04e 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -369,6 +369,27 @@ BOOST_AUTO_TEST_CASE(successor_not_found_bug)
compileBothVersions(sourceCode);
}
+BOOST_AUTO_TEST_CASE(incorrect_storage_access_bug)
+{
+ // This bug appeared because a sha3 operation with too low sequence number was used,
+ // resulting in memory not being rewritten before the sha3. The fix was to
+ // take the max of the min sequence numbers when merging the states.
+ char const* sourceCode = R"(
+ contract C
+ {
+ mapping(uint => uint) data;
+ function f() returns (uint)
+ {
+ if(data[now] == 0)
+ data[uint(-7)] = 5;
+ return data[now];
+ }
+ }
+ )";
+ compileBothVersions(sourceCode);
+ compareVersions("f()");
+}
+
BOOST_AUTO_TEST_CASE(cse_intermediate_swap)
{
eth::KnownState state;