From e510e7e7929326de3a556d6d2e66b8b4376af7a9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 5 Dec 2015 02:26:54 +0100 Subject: Bugfix concerning pointers to moved data. --- libsolidity/analysis/NameAndTypeResolver.cpp | 38 +++++++++++++++------------- libsolidity/analysis/NameAndTypeResolver.h | 10 +++++--- 2 files changed, 27 insertions(+), 21 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 612989e1..fb3e9305 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -38,8 +38,9 @@ NameAndTypeResolver::NameAndTypeResolver( ) : m_errors(_errors) { + m_scopes[nullptr].reset(new DeclarationContainer()); for (Declaration const* declaration: _globals) - m_scopes[nullptr].registerDeclaration(*declaration); + m_scopes[nullptr]->registerDeclaration(*declaration); } bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit) @@ -62,7 +63,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { try { - m_currentScope = &m_scopes[nullptr]; + m_currentScope = m_scopes[nullptr].get(); ReferencesResolver resolver(m_errors, *this, nullptr); bool success = true; @@ -70,7 +71,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) if (!resolver.resolve(*baseContract)) success = false; - m_currentScope = &m_scopes[&_contract]; + m_currentScope = m_scopes[&_contract].get(); if (success) { @@ -87,7 +88,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) // these can contain code, only resolve parameters for now for (ASTPointer const& node: _contract.subNodes()) { - m_currentScope = &m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract]; + m_currentScope = m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract].get(); if (!resolver.resolve(*node)) success = false; } @@ -95,12 +96,12 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) if (!success) return false; - m_currentScope = &m_scopes[&_contract]; + m_currentScope = m_scopes[&_contract].get(); // now resolve references inside the code for (ModifierDefinition const* modifier: _contract.functionModifiers()) { - m_currentScope = &m_scopes[modifier]; + m_currentScope = m_scopes[modifier].get(); ReferencesResolver resolver(m_errors, *this, nullptr, true); if (!resolver.resolve(*modifier)) success = false; @@ -108,7 +109,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) for (FunctionDefinition const* function: _contract.definedFunctions()) { - m_currentScope = &m_scopes[function]; + m_currentScope = m_scopes[function].get(); if (!ReferencesResolver( m_errors, *this, @@ -133,7 +134,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) { try { - m_scopes[nullptr].registerDeclaration(_declaration, false, true); + m_scopes[nullptr]->registerDeclaration(_declaration, false, true); solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope."); } catch (FatalError const&) @@ -150,7 +151,7 @@ vector NameAndTypeResolver::resolveName(ASTString const& _na auto iterator = m_scopes.find(_scope); if (iterator == end(m_scopes)) return vector({}); - return iterator->second.resolveName(_name, false); + return iterator->second->resolveName(_name, false); } vector NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _recursive) const @@ -166,7 +167,7 @@ Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector c { if (!m_scopes.count(candidates.front())) return nullptr; - candidates = m_scopes.at(candidates.front()).resolveName(_path[i], false); + candidates = m_scopes.at(candidates.front())->resolveName(_path[i], false); } if (candidates.size() == 1) return candidates.front(); @@ -210,7 +211,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) { auto iterator = m_scopes.find(&_base); solAssert(iterator != end(m_scopes), ""); - for (auto const& nameAndDeclaration: iterator->second.declarations()) + for (auto const& nameAndDeclaration: iterator->second->declarations()) for (auto const& declaration: nameAndDeclaration.second) // Import if it was declared in the base, is not the constructor and is visible in derived classes if (declaration->scope() == &_base && declaration->isVisibleInDerivedContracts()) @@ -342,7 +343,7 @@ void NameAndTypeResolver::reportFatalTypeError(Error const& _e) } DeclarationRegistrationHelper::DeclarationRegistrationHelper( - map& _scopes, + map>& _scopes, ASTNode& _astRoot, ErrorList& _errors ): @@ -450,9 +451,10 @@ void DeclarationRegistrationHelper::endVisit(EventDefinition&) void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration) { - map::iterator iter; + map>::iterator iter; bool newlyAdded; - tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope])); + std::unique_ptr container(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get())); + tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, move(container)); solAssert(newlyAdded, "Unable to add new scope."); m_currentScope = &_declaration; } @@ -460,16 +462,16 @@ void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declara void DeclarationRegistrationHelper::closeCurrentScope() { solAssert(m_currentScope, "Closed non-existing scope."); - m_currentScope = m_scopes[m_currentScope].enclosingDeclaration(); + m_currentScope = m_scopes[m_currentScope]->enclosingDeclaration(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract())) + if (!m_scopes[m_currentScope]->registerDeclaration(_declaration, !_declaration.isVisibleInContract())) { SourceLocation firstDeclarationLocation; SourceLocation secondDeclarationLocation; - Declaration const* conflictingDeclaration = m_scopes[m_currentScope].conflictingDeclaration(_declaration); + Declaration const* conflictingDeclaration = m_scopes[m_currentScope]->conflictingDeclaration(_declaration); solAssert(conflictingDeclaration, ""); if (_declaration.location().start < conflictingDeclaration->location().start) @@ -502,7 +504,7 @@ string DeclarationRegistrationHelper::currentCanonicalName() const for ( Declaration const* scope = m_currentScope; scope != nullptr; - scope = m_scopes[scope].enclosingDeclaration() + scope = m_scopes[scope]->enclosingDeclaration() ) { if (!ret.empty()) diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 1547a274..805a5596 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -91,7 +91,7 @@ private: /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration, /// where nullptr denotes the global scope. Note that structs are not scope since they do /// not contain code. - std::map m_scopes; + std::map> m_scopes; // creates the Declaration error and adds it in the errors list void reportDeclarationError( @@ -121,7 +121,11 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot, ErrorList& _errors); + DeclarationRegistrationHelper( + std::map>& _scopes, + ASTNode& _astRoot, + ErrorList& _errors + ); private: bool visit(ContractDefinition& _contract) override; @@ -159,7 +163,7 @@ private: // creates the Declaration error and adds it in the errors list and throws FatalError void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description); - std::map& m_scopes; + std::map>& m_scopes; Declaration const* m_currentScope = nullptr; VariableScope* m_currentFunction = nullptr; ErrorList& m_errors; -- cgit v1.2.3 From 7cb7818ceaf8f2e50cdd66b33a4e0d17c2a0e879 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 5 Dec 2015 03:09:47 +0100 Subject: Source units are independent scopes. --- libsolidity/analysis/DeclarationContainer.cpp | 38 ++++++++++------- libsolidity/analysis/DeclarationContainer.h | 13 +++--- libsolidity/analysis/NameAndTypeResolver.cpp | 59 +++++++++++++++++++++------ libsolidity/analysis/NameAndTypeResolver.h | 19 +++++---- libsolidity/analysis/ReferencesResolver.cpp | 10 +++-- libsolidity/ast/AST.h | 6 +-- libsolidity/interface/CompilerStack.cpp | 6 +++ 7 files changed, 105 insertions(+), 46 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index 7339ad5d..ac56562e 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -28,15 +28,19 @@ using namespace std; using namespace dev; using namespace dev::solidity; -Declaration const* DeclarationContainer::conflictingDeclaration(Declaration const& _declaration) const +Declaration const* DeclarationContainer::conflictingDeclaration( + Declaration const& _declaration, + ASTString const* _name +) const { - ASTString const& declarationName(_declaration.name()); - solAssert(!declarationName.empty(), ""); + if (!_name) + _name = &_declaration.name(); + solAssert(!_name->empty(), ""); vector declarations; - if (m_declarations.count(declarationName)) - declarations += m_declarations.at(declarationName); - if (m_invisibleDeclarations.count(declarationName)) - declarations += m_invisibleDeclarations.at(declarationName); + if (m_declarations.count(*_name)) + declarations += m_declarations.at(*_name); + if (m_invisibleDeclarations.count(*_name)) + declarations += m_invisibleDeclarations.at(*_name); if (dynamic_cast(&_declaration)) { @@ -51,25 +55,31 @@ Declaration const* DeclarationContainer::conflictingDeclaration(Declaration cons return nullptr; } -bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update) +bool DeclarationContainer::registerDeclaration( + Declaration const& _declaration, + ASTString const* _name, + bool _invisible, + bool _update +) { - ASTString const& declarationName(_declaration.name()); - if (declarationName.empty()) + if (!_name) + _name = &_declaration.name(); + if (_name->empty()) return true; if (_update) { solAssert(!dynamic_cast(&_declaration), "Attempt to update function definition."); - m_declarations.erase(declarationName); - m_invisibleDeclarations.erase(declarationName); + m_declarations.erase(*_name); + m_invisibleDeclarations.erase(*_name); } else if (conflictingDeclaration(_declaration)) return false; if (_invisible) - m_invisibleDeclarations[declarationName].push_back(&_declaration); + m_invisibleDeclarations[*_name].push_back(&_declaration); else - m_declarations[declarationName].push_back(&_declaration); + m_declarations[*_name].push_back(&_declaration); return true; } diff --git a/libsolidity/analysis/DeclarationContainer.h b/libsolidity/analysis/DeclarationContainer.h index 064724d1..5862f7a5 100644 --- a/libsolidity/analysis/DeclarationContainer.h +++ b/libsolidity/analysis/DeclarationContainer.h @@ -41,23 +41,24 @@ class DeclarationContainer { public: explicit DeclarationContainer( - Declaration const* _enclosingDeclaration = nullptr, + ASTNode const* _enclosingNode = nullptr, DeclarationContainer const* _enclosingContainer = nullptr ): - m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} + m_enclosingNode(_enclosingNode), m_enclosingContainer(_enclosingContainer) {} /// Registers the declaration in the scope unless its name is already declared or the name is empty. + /// @param _name the name to register, if nullptr the intrinsic name of @a _declaration is used. /// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName /// @param _update if true, replaces a potential declaration that is already present /// @returns false if the name was already declared. - bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false); + bool registerDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr, bool _invisible = false, bool _update = false); std::vector resolveName(ASTString const& _name, bool _recursive = false) const; - Declaration const* enclosingDeclaration() const { return m_enclosingDeclaration; } + ASTNode const* enclosingNode() const { return m_enclosingNode; } std::map> const& declarations() const { return m_declarations; } /// @returns whether declaration is valid, and if not also returns previous declaration. - Declaration const* conflictingDeclaration(Declaration const& _declaration) const; + Declaration const* conflictingDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr) const; private: - Declaration const* m_enclosingDeclaration; + ASTNode const* m_enclosingNode; DeclarationContainer const* m_enclosingContainer; std::map> m_declarations; std::map> m_invisibleDeclarations; diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index fb3e9305..907d703c 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -38,13 +38,18 @@ NameAndTypeResolver::NameAndTypeResolver( ) : m_errors(_errors) { - m_scopes[nullptr].reset(new DeclarationContainer()); + if (!m_scopes[nullptr]) + m_scopes[nullptr].reset(new DeclarationContainer()); for (Declaration const* declaration: _globals) m_scopes[nullptr]->registerDeclaration(*declaration); } bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit) { + solAssert(!m_scopes[&_sourceUnit], ""); + m_scopes[&_sourceUnit].reset(new DeclarationContainer(nullptr, m_scopes[nullptr].get())); + m_currentScope = m_scopes[&_sourceUnit].get(); + // The helper registers all declarations in m_scopes as a side-effect of its construction. try { @@ -59,11 +64,37 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit) return true; } +bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map const& _sourceUnits) +{ + DeclarationContainer& target = *m_scopes.at(&_sourceUnit); + bool error = false; + for (auto const& node: _sourceUnit.nodes()) + if (auto imp = dynamic_cast(node.get())) + { + if (!_sourceUnits.count(imp->identifier())) + { + reportDeclarationError(node->location(), "Import \"" + imp->identifier() + "\" not found."); + error = true; + } + else + { + auto scope = m_scopes.find(_sourceUnits.at(imp->identifier())); + solAssert(scope != end(m_scopes), ""); + for (auto const& nameAndDeclaration: scope->second->declarations()) + for (auto const& declaration: nameAndDeclaration.second) + target.registerDeclaration(*declaration, &nameAndDeclaration.first); + + } + } + return !error; +} + bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { try { - m_currentScope = m_scopes[nullptr].get(); + m_currentScope = m_scopes[_contract.scope()].get(); + solAssert(!!m_currentScope, ""); ReferencesResolver resolver(m_errors, *this, nullptr); bool success = true; @@ -134,7 +165,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) { try { - m_scopes[nullptr]->registerDeclaration(_declaration, false, true); + m_scopes[nullptr]->registerDeclaration(_declaration, nullptr, false, true); solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope."); } catch (FatalError const&) @@ -146,7 +177,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) return true; } -vector NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const +vector NameAndTypeResolver::resolveName(ASTString const& _name, ASTNode const* _scope) const { auto iterator = m_scopes.find(_scope); if (iterator == end(m_scopes)) @@ -348,9 +379,10 @@ DeclarationRegistrationHelper::DeclarationRegistrationHelper( ErrorList& _errors ): m_scopes(_scopes), - m_currentScope(nullptr), + m_currentScope(&_astRoot), m_errors(_errors) { + solAssert(!!m_scopes.at(m_currentScope), ""); _astRoot.accept(*this); } @@ -462,12 +494,12 @@ void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declara void DeclarationRegistrationHelper::closeCurrentScope() { solAssert(m_currentScope, "Closed non-existing scope."); - m_currentScope = m_scopes[m_currentScope]->enclosingDeclaration(); + m_currentScope = m_scopes[m_currentScope]->enclosingNode(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - if (!m_scopes[m_currentScope]->registerDeclaration(_declaration, !_declaration.isVisibleInContract())) + if (!m_scopes[m_currentScope]->registerDeclaration(_declaration, nullptr, !_declaration.isVisibleInContract())) { SourceLocation firstDeclarationLocation; SourceLocation secondDeclarationLocation; @@ -502,14 +534,17 @@ string DeclarationRegistrationHelper::currentCanonicalName() const { string ret; for ( - Declaration const* scope = m_currentScope; + ASTNode const* scope = m_currentScope; scope != nullptr; - scope = m_scopes[scope]->enclosingDeclaration() + scope = m_scopes[scope]->enclosingNode() ) { - if (!ret.empty()) - ret = "." + ret; - ret = scope->name() + ret; + if (auto decl = dynamic_cast(scope)) + { + if (!ret.empty()) + ret = "." + ret; + ret = decl->name() + ret; + } } return ret; } diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 805a5596..3c444aba 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -46,6 +46,8 @@ public: /// Registers all declarations found in the source unit. /// @returns false in case of error. bool registerDeclarations(SourceUnit& _sourceUnit); + /// Applies the effect of import directives. + bool performImports(SourceUnit& _sourceUnit, std::map const& _sourceUnits); /// Resolves all names and types referenced from the given contract. /// @returns false in case of error. bool resolveNamesAndTypes(ContractDefinition& _contract); @@ -55,9 +57,9 @@ public: bool updateDeclaration(Declaration const& _declaration); /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, - /// the global scope is used (i.e. the one containing only the contract). + /// the global scope is used (i.e. the one containing only the pre-defined global variables). /// @returns a pointer to the declaration on success or nullptr on failure. - std::vector resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + std::vector resolveName(ASTString const& _name, ASTNode const* _scope = nullptr) const; /// Resolves a name in the "current" scope. Should only be called during the initial /// resolving phase. @@ -88,11 +90,6 @@ private: template static std::vector<_T const*> cThreeMerge(std::list>& _toMerge); - /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration, - /// where nullptr denotes the global scope. Note that structs are not scope since they do - /// not contain code. - std::map> m_scopes; - // creates the Declaration error and adds it in the errors list void reportDeclarationError( SourceLocation _sourceLoction, @@ -110,6 +107,12 @@ private: // creates the Declaration error and adds it in the errors list and throws FatalError void reportFatalTypeError(Error const& _e); + + /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration, + /// where nullptr denotes the global scope. Note that structs are not scope since they do + /// not contain code. + std::map> m_scopes; + DeclarationContainer* m_currentScope = nullptr; ErrorList& m_errors; }; @@ -164,7 +167,7 @@ private: void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description); std::map>& m_scopes; - Declaration const* m_currentScope = nullptr; + ASTNode const* m_currentScope = nullptr; VariableScope* m_currentFunction = nullptr; ErrorList& m_errors; }; diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 2fe53e8b..ca002f58 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -139,7 +139,9 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) bool isPointer = true; if (_variable.isExternalCallableParameter()) { - auto const& contract = dynamic_cast(*_variable.scope()->scope()); + auto const& contract = dynamic_cast( + *dynamic_cast(*_variable.scope()).scope() + ); if (contract.isLibrary()) { if (varLoc == Location::Memory) @@ -162,9 +164,11 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) else typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; } - else if (_variable.isCallableParameter() && _variable.scope()->isPublic()) + else if (_variable.isCallableParameter() && dynamic_cast(*_variable.scope()).isPublic()) { - auto const& contract = dynamic_cast(*_variable.scope()->scope()); + auto const& contract = dynamic_cast( + *dynamic_cast(*_variable.scope()).scope() + ); // force locations of public or external function (return) parameters to memory if (varLoc == Location::Storage && !contract.isLibrary()) fatalTypeError(_variable.location(), diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 1217d945..446088ad 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -172,8 +172,8 @@ public: /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. - Declaration const* scope() const { return m_scope; } - void setScope(Declaration const* _scope) { m_scope = _scope; } + ASTNode const* scope() const { return m_scope; } + void setScope(ASTNode const* _scope) { m_scope = _scope; } virtual bool isLValue() const { return false; } virtual bool isPartOfExternalInterface() const { return false; } @@ -190,7 +190,7 @@ protected: private: ASTPointer m_name; Visibility m_visibility; - Declaration const* m_scope; + ASTNode const* m_scope; }; /** diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 18eec0a2..38fe5956 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -103,12 +103,14 @@ bool CompilerStack::parse() m_errors.clear(); m_parseSuccessful = false; + map sourceUnitsByName; for (auto& sourcePair: m_sources) { sourcePair.second.scanner->reset(); sourcePair.second.ast = Parser(m_errors).parse(sourcePair.second.scanner); if (!sourcePair.second.ast) solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error."); + sourceUnitsByName[sourcePair.first] = sourcePair.second.ast.get(); } if (!Error::containsOnlyWarnings(m_errors)) // errors while parsing. sould stop before type checking @@ -128,6 +130,10 @@ bool CompilerStack::parse() if (!resolver.registerDeclarations(*source->ast)) return false; + for (Source const* source: m_sourceOrder) + if (!resolver.performImports(*source->ast, sourceUnitsByName)) + return false; + for (Source const* source: m_sourceOrder) for (ASTPointer const& node: source->ast->nodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) -- cgit v1.2.3 From f8228e8ab116799a1b28ea9cbb01fdd7342b395c Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 9 Dec 2015 17:35:20 +0100 Subject: Relative paths in import directives. --- libsolidity/analysis/NameAndTypeResolver.cpp | 14 ++++++++++---- libsolidity/ast/AST.cpp | 7 +++++++ libsolidity/ast/AST.h | 1 + libsolidity/ast/ASTAnnotations.h | 6 ++++++ libsolidity/interface/CompilerStack.cpp | 29 +++++++++++++++++++++++----- libsolidity/interface/CompilerStack.h | 2 ++ 6 files changed, 50 insertions(+), 9 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 907d703c..ca866ddb 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -71,19 +71,25 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map(node.get())) { - if (!_sourceUnits.count(imp->identifier())) + string const& path = imp->annotation().absolutePath; + if (!_sourceUnits.count(path)) { - reportDeclarationError(node->location(), "Import \"" + imp->identifier() + "\" not found."); + reportDeclarationError( node->location(), + "Import \"" + + path + + "\" (referenced as \"" + + imp->identifier() + + "\") not found." + ); error = true; } else { - auto scope = m_scopes.find(_sourceUnits.at(imp->identifier())); + 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); - } } return !error; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 6006d441..701202f9 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -56,6 +56,13 @@ Error ASTNode::createTypeError(string const& _description) const return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description); } +ImportAnnotation& ImportDirective::annotation() const +{ + if (!m_annotation) + m_annotation = new ImportAnnotation(); + return static_cast(*m_annotation); +} + map, FunctionTypePointer> ContractDefinition::interfaceFunctions() const { auto exportedFunctionList = interfaceFunctionList(); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 446088ad..75cb9ab2 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -142,6 +142,7 @@ public: virtual void accept(ASTConstVisitor& _visitor) const override; ASTString const& identifier() const { return *m_identifier; } + virtual ImportAnnotation& annotation() const override; private: ASTPointer m_identifier; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 4e0187cf..0bc91c60 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -54,6 +54,12 @@ struct DocumentedAnnotation std::multimap docTags; }; +struct ImportAnnotation: ASTAnnotation +{ + /// The absolute path of the source unit to import. + std::string absolutePath; +}; + struct TypeDeclarationAnnotation: ASTAnnotation { /// The name of this type, prefixed by proper namespaces if globally accessible. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 38fe5956..7f097523 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -367,7 +368,7 @@ void CompilerStack::resolveImports() vector sourceOrder; set sourcesSeen; - function toposort = [&](Source const* _source) + function toposort = [&](string const& _sourceName, Source const* _source) { if (sourcesSeen.count(_source)) return; @@ -375,26 +376,44 @@ void CompilerStack::resolveImports() for (ASTPointer const& node: _source->ast->nodes()) if (ImportDirective const* import = dynamic_cast(node.get())) { - string const& id = import->identifier(); - if (!m_sources.count(id)) + string path = absolutePath(import->identifier(), _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.") ); - toposort(&m_sources[id]); + toposort(path, &m_sources[path]); } sourceOrder.push_back(_source); }; for (auto const& sourcePair: m_sources) if (!sourcePair.second.isLibrary) - toposort(&sourcePair.second); + toposort(sourcePair.first, &sourcePair.second); swap(m_sourceOrder, sourceOrder); } +string CompilerStack::absolutePath(string const& _path, string const& _reference) const +{ + // Anything that does not start with `.` is an absolute path. + if (_path.empty() || _path.front() != '.') + return _path; + using path = boost::filesystem::path; + path p(_path); + path result(_reference); + result.remove_filename(); + for (path::iterator it = p.begin(); it != p.end(); ++it) + if (*it == "..") + result = result.parent_path(); + else if (*it != ".") + result /= *it; + return result.string(); +} + void CompilerStack::compileContract( bool _optimize, unsigned _runs, diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 0473d58b..3e6dc456 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -199,6 +199,8 @@ private: }; void resolveImports(); + /// @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. void compileContract( bool _optimize, -- cgit v1.2.3 From 53da78e6091d9bb0229b4a54a0042e23487550db Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 14 Dec 2015 18:01:40 +0100 Subject: Style. --- libsolidity/analysis/NameAndTypeResolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index ca866ddb..efdb1953 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -113,7 +113,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) if (success) { linearizeBaseContracts(_contract); - std::vector properBases( + vector properBases( ++_contract.annotation().linearizedBaseContracts.begin(), _contract.annotation().linearizedBaseContracts.end() ); @@ -380,7 +380,7 @@ void NameAndTypeResolver::reportFatalTypeError(Error const& _e) } DeclarationRegistrationHelper::DeclarationRegistrationHelper( - map>& _scopes, + map>& _scopes, ASTNode& _astRoot, ErrorList& _errors ): @@ -489,9 +489,9 @@ void DeclarationRegistrationHelper::endVisit(EventDefinition&) void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration) { - map>::iterator iter; + map>::iterator iter; bool newlyAdded; - std::unique_ptr container(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get())); + unique_ptr container(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get())); tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, move(container)); solAssert(newlyAdded, "Unable to add new scope."); m_currentScope = &_declaration; -- cgit v1.2.3