diff options
author | chriseth <c@ethdev.com> | 2015-12-05 10:09:47 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-12-10 02:09:24 +0800 |
commit | 7cb7818ceaf8f2e50cdd66b33a4e0d17c2a0e879 (patch) | |
tree | d6ac5e5fe041afc29dcea2aafa97d60dca82a991 /libsolidity/analysis | |
parent | e510e7e7929326de3a556d6d2e66b8b4376af7a9 (diff) | |
download | dexon-solidity-7cb7818ceaf8f2e50cdd66b33a4e0d17c2a0e879.tar.gz dexon-solidity-7cb7818ceaf8f2e50cdd66b33a4e0d17c2a0e879.tar.zst dexon-solidity-7cb7818ceaf8f2e50cdd66b33a4e0d17c2a0e879.zip |
Source units are independent scopes.
Diffstat (limited to 'libsolidity/analysis')
-rw-r--r-- | libsolidity/analysis/DeclarationContainer.cpp | 38 | ||||
-rw-r--r-- | libsolidity/analysis/DeclarationContainer.h | 13 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.cpp | 59 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.h | 19 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 10 |
5 files changed, 96 insertions, 43 deletions
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<Declaration const*> 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<FunctionDefinition const*>(&_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<FunctionDefinition const*>(&_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<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const; - Declaration const* enclosingDeclaration() const { return m_enclosingDeclaration; } + ASTNode const* enclosingNode() const { return m_enclosingNode; } std::map<ASTString, std::vector<Declaration const*>> 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<ASTString, std::vector<Declaration const*>> m_declarations; std::map<ASTString, std::vector<Declaration const*>> 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<string, SourceUnit const*> const& _sourceUnits) +{ + DeclarationContainer& target = *m_scopes.at(&_sourceUnit); + bool error = false; + for (auto const& node: _sourceUnit.nodes()) + if (auto imp = dynamic_cast<ImportDirective const*>(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<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const +vector<Declaration const*> 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<Declaration const*>(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<std::string, SourceUnit const*> 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<Declaration const*> resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + std::vector<Declaration const*> 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 <class _T> static std::vector<_T const*> cThreeMerge(std::list<std::list<_T const*>>& _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<ASTNode const*, std::unique_ptr<DeclarationContainer>> 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<ASTNode const*, std::unique_ptr<DeclarationContainer>> m_scopes; + DeclarationContainer* m_currentScope = nullptr; ErrorList& m_errors; }; @@ -164,7 +167,7 @@ private: void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description); std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& 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<ContractDefinition const&>(*_variable.scope()->scope()); + auto const& contract = dynamic_cast<ContractDefinition const&>( + *dynamic_cast<Declaration const&>(*_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<Declaration const&>(*_variable.scope()).isPublic()) { - auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope()); + auto const& contract = dynamic_cast<ContractDefinition const&>( + *dynamic_cast<Declaration const&>(*_variable.scope()).scope() + ); // force locations of public or external function (return) parameters to memory if (varLoc == Location::Storage && !contract.isLibrary()) fatalTypeError(_variable.location(), |