diff options
author | chriseth <c@ethdev.com> | 2015-04-15 23:40:50 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-04-15 23:40:50 +0800 |
commit | 0c69d5fdcd3286f47c81dbcbcfb8802861eab8b5 (patch) | |
tree | f78c665e6084300b939cc4cfcebb97d3bd44d9f5 /NameAndTypeResolver.cpp | |
parent | 158795e48f4285d713b11f78cdd04de8c6d1f667 (diff) | |
download | dexon-solidity-0c69d5fdcd3286f47c81dbcbcfb8802861eab8b5.tar.gz dexon-solidity-0c69d5fdcd3286f47c81dbcbcfb8802861eab8b5.tar.zst dexon-solidity-0c69d5fdcd3286f47c81dbcbcfb8802861eab8b5.zip |
Fixed function overloads.
Added tests, disallowed non-calling usage of non-unique function
references.
Diffstat (limited to 'NameAndTypeResolver.cpp')
-rw-r--r-- | NameAndTypeResolver.cpp | 80 |
1 files changed, 67 insertions, 13 deletions
diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index c787ae6b..1c527b89 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -53,8 +53,9 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[&_contract]; linearizeBaseContracts(_contract); + // we first import non-functions only as we do not yet know the argument types for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) - importInheritedScope(*base); + importInheritedScope(*base, false); // import non-functions for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); @@ -64,6 +65,8 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) ReferencesResolver resolver(*variable, *this, &_contract, nullptr); for (ASTPointer<EventDefinition> const& event: _contract.getEvents()) ReferencesResolver resolver(*event, *this, &_contract, nullptr); + + // these can contain code, only resolve parameters for now for (ASTPointer<ModifierDefinition> const& modifier: _contract.getFunctionModifiers()) { m_currentScope = &m_scopes[modifier.get()]; @@ -75,6 +78,28 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) ReferencesResolver referencesResolver(*function, *this, &_contract, function->getReturnParameterList().get()); } + + m_currentScope = &m_scopes[&_contract]; + for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) + importInheritedScope(*base, true); // import functions + + // now resolve references inside the code + for (ASTPointer<ModifierDefinition> const& modifier: _contract.getFunctionModifiers()) + { + m_currentScope = &m_scopes[modifier.get()]; + ReferencesResolver resolver(*modifier, *this, &_contract, nullptr, true); + } + for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) + { + m_currentScope = &m_scopes[function.get()]; + ReferencesResolver referencesResolver( + *function, + *this, + &_contract, + function->getReturnParameterList().get(), + true + ); + } } void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract) @@ -90,7 +115,7 @@ void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope."); } -std::set<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const +set<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const { auto iterator = m_scopes.find(_scope); if (iterator == end(m_scopes)) @@ -98,21 +123,43 @@ std::set<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _ return iterator->second.resolveName(_name, false); } -std::set<Declaration const*> NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) +set<Declaration const*> NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) { return m_currentScope->resolveName(_name, _recursive); } -void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) +void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base, bool _importFunctions) { auto iterator = m_scopes.find(&_base); solAssert(iterator != end(m_scopes), ""); for (auto const& nameAndDeclaration: iterator->second.getDeclarations()) 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->getScope() == &_base && declaration->getName() != _base.getName() && - declaration->isVisibleInDerivedContracts()) + if (declaration->getScope() == &_base && declaration->isVisibleInDerivedContracts()) + { + auto function = dynamic_cast<FunctionDefinition const*>(declaration); + if ((function == nullptr) == _importFunctions) + continue; + if (!!function) + { + FunctionType functionType(*function); + // only import if a function with the same arguments does not exist yet + bool functionWithEqualArgumentsFound = false; + for (auto knownDeclaration: m_currentScope->resolveName(nameAndDeclaration.first)) + { + auto knownFunction = dynamic_cast<FunctionDefinition const*>(knownDeclaration); + if (!knownFunction) + continue; // this is not legal, but will be caught later + if (!FunctionType(*knownFunction).hasEqualArgumentTypes(functionType)) + continue; + functionWithEqualArgumentsFound = true; + break; + } + if (functionWithEqualArgumentsFound) + continue; + } m_currentScope->registerDeclaration(*declaration); + } } void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const @@ -123,8 +170,7 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: _contract.getBaseContracts()) { ASTPointer<Identifier> baseName = baseSpecifier->getName(); - ContractDefinition const* base = dynamic_cast<ContractDefinition const*>( - baseName->getReferencedDeclaration()); + auto base = dynamic_cast<ContractDefinition const*>(&baseName->getReferencedDeclaration()); if (!base) BOOST_THROW_EXCEPTION(baseName->createTypeError("Contract expected.")); // "push_front" has the effect that bases mentioned later can overwrite members of bases @@ -316,11 +362,19 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio enterNewSubScope(_declaration); } -ReferencesResolver::ReferencesResolver(ASTNode& _root, NameAndTypeResolver& _resolver, - ContractDefinition const* _currentContract, - ParameterList const* _returnParameters, bool _allowLazyTypes): - m_resolver(_resolver), m_currentContract(_currentContract), - m_returnParameters(_returnParameters), m_allowLazyTypes(_allowLazyTypes) +ReferencesResolver::ReferencesResolver( + ASTNode& _root, + NameAndTypeResolver& _resolver, + ContractDefinition const* _currentContract, + ParameterList const* _returnParameters, + bool _resolveInsideCode, + bool _allowLazyTypes +): + m_resolver(_resolver), + m_currentContract(_currentContract), + m_returnParameters(_returnParameters), + m_resolveInsideCode(_resolveInsideCode), + m_allowLazyTypes(_allowLazyTypes) { _root.accept(*this); } |