diff options
author | chriseth <c@ethdev.com> | 2015-12-15 18:43:59 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-12-15 18:43:59 +0800 |
commit | 591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0 (patch) | |
tree | 282c36887814420e2fa86e132587ec9f192f30ad /libsolidity/analysis | |
parent | 98684cca9035c754adcdc99fd196716cb7802efd (diff) | |
parent | 53da78e6091d9bb0229b4a54a0042e23487550db (diff) | |
download | dexon-solidity-591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0.tar.gz dexon-solidity-591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0.tar.zst dexon-solidity-591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0.zip |
Merge pull request #288 from chriseth/import_contexts
Do not clutter importee when importing.
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 | 93 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.h | 27 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 10 |
5 files changed, 123 insertions, 58 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 612989e1..efdb1953 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -38,12 +38,18 @@ NameAndTypeResolver::NameAndTypeResolver( ) : m_errors(_errors) { + if (!m_scopes[nullptr]) + 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) { + 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 { @@ -58,11 +64,43 @@ 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())) + { + string const& path = imp->annotation().absolutePath; + if (!_sourceUnits.count(path)) + { + reportDeclarationError( node->location(), + "Import \"" + + path + + "\" (referenced as \"" + + imp->identifier() + + "\") not found." + ); + error = true; + } + else + { + 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; +} + bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { try { - m_currentScope = &m_scopes[nullptr]; + m_currentScope = m_scopes[_contract.scope()].get(); + solAssert(!!m_currentScope, ""); ReferencesResolver resolver(m_errors, *this, nullptr); bool success = true; @@ -70,12 +108,12 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) if (!resolver.resolve(*baseContract)) success = false; - m_currentScope = &m_scopes[&_contract]; + m_currentScope = m_scopes[&_contract].get(); if (success) { linearizeBaseContracts(_contract); - std::vector<ContractDefinition const*> properBases( + vector<ContractDefinition const*> properBases( ++_contract.annotation().linearizedBaseContracts.begin(), _contract.annotation().linearizedBaseContracts.end() ); @@ -87,7 +125,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) // these can contain code, only resolve parameters for now for (ASTPointer<ASTNode> 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 +133,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 +146,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 +171,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&) @@ -145,12 +183,12 @@ 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)) return vector<Declaration const*>({}); - return iterator->second.resolveName(_name, false); + return iterator->second->resolveName(_name, false); } vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _recursive) const @@ -166,7 +204,7 @@ Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector<ASTString> 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 +248,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,14 +380,15 @@ void NameAndTypeResolver::reportFatalTypeError(Error const& _e) } DeclarationRegistrationHelper::DeclarationRegistrationHelper( - map<ASTNode const*, DeclarationContainer>& _scopes, + map<ASTNode const*, unique_ptr<DeclarationContainer>>& _scopes, ASTNode& _astRoot, ErrorList& _errors ): m_scopes(_scopes), - m_currentScope(nullptr), + m_currentScope(&_astRoot), m_errors(_errors) { + solAssert(!!m_scopes.at(m_currentScope), ""); _astRoot.accept(*this); } @@ -450,9 +489,10 @@ void DeclarationRegistrationHelper::endVisit(EventDefinition&) void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration) { - map<ASTNode const*, DeclarationContainer>::iterator iter; + map<ASTNode const*, unique_ptr<DeclarationContainer>>::iterator iter; bool newlyAdded; - tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope])); + unique_ptr<DeclarationContainer> 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 +500,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]->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; - 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) @@ -500,14 +540,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 1547a274..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*, 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; }; @@ -121,7 +124,11 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot, ErrorList& _errors); + DeclarationRegistrationHelper( + std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& _scopes, + ASTNode& _astRoot, + ErrorList& _errors + ); private: bool visit(ContractDefinition& _contract) override; @@ -159,8 +166,8 @@ 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<ASTNode const*, DeclarationContainer>& m_scopes; - Declaration const* m_currentScope = nullptr; + std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& m_scopes; + 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(), |