mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
changed the way of resolving declarations. now the cleanup of function duplications in libsolidity/NameAndTypeResolver.cpp(WIP)
This commit is contained in:
parent
4fdfbaa367
commit
115c22c0e0
8
AST.h
8
AST.h
@ -1217,10 +1217,10 @@ public:
|
|||||||
}
|
}
|
||||||
Declaration const& getReferencedDeclaration() const;
|
Declaration const& getReferencedDeclaration() const;
|
||||||
|
|
||||||
/// Stores a set of possible declarations referenced by this identifier. Has to be resolved
|
/// Stores a possible declarations referenced by this identifier. Has to be resolved
|
||||||
/// providing argument types using overloadResolution before the referenced declaration
|
/// providing argument types using overloadResolution before the referenced declaration
|
||||||
/// is accessed.
|
/// is accessed.
|
||||||
void setOverloadedDeclarations(std::set<Declaration const*> const& _declarations)
|
void setOverloadedDeclarations(std::vector<Declaration const*> const& _declarations)
|
||||||
{
|
{
|
||||||
m_overloadedDeclarations = _declarations;
|
m_overloadedDeclarations = _declarations;
|
||||||
}
|
}
|
||||||
@ -1237,8 +1237,8 @@ private:
|
|||||||
/// Stores a reference to the current contract. This is needed because types of base contracts
|
/// Stores a reference to the current contract. This is needed because types of base contracts
|
||||||
/// change depending on the context.
|
/// change depending on the context.
|
||||||
ContractDefinition const* m_currentContract = nullptr;
|
ContractDefinition const* m_currentContract = nullptr;
|
||||||
/// A set of overloaded declarations, right now only FunctionDefinition has overloaded declarations.
|
/// A vector of overloaded declarations, right now only FunctionDefinition has overloaded declarations.
|
||||||
std::set<Declaration const*> m_overloadedDeclarations;
|
std::vector<Declaration const*> m_overloadedDeclarations;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +37,7 @@ Declaration const* DeclarationContainer::conflictingDeclaration(Declaration cons
|
|||||||
declarations += m_declarations.at(name);
|
declarations += m_declarations.at(name);
|
||||||
if (m_invisibleDeclarations.count(name))
|
if (m_invisibleDeclarations.count(name))
|
||||||
declarations += m_invisibleDeclarations.at(name);
|
declarations += m_invisibleDeclarations.at(name);
|
||||||
|
|
||||||
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
|
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
|
||||||
{
|
{
|
||||||
// check that all other declarations with the same name are functions
|
// check that all other declarations with the same name are functions
|
||||||
@ -66,14 +67,13 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_invisible)
|
if (_invisible)
|
||||||
m_invisibleDeclarations[name].insert(&_declaration);
|
m_invisibleDeclarations[name].push_back(&_declaration);
|
||||||
else
|
else
|
||||||
m_declarations[name].insert(&_declaration);
|
m_declarations[name].push_back(&_declaration);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
set<Declaration const*> DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const
|
std::vector<const Declaration *> DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const
|
||||||
{
|
{
|
||||||
solAssert(!_name.empty(), "Attempt to resolve empty name.");
|
solAssert(!_name.empty(), "Attempt to resolve empty name.");
|
||||||
auto result = m_declarations.find(_name);
|
auto result = m_declarations.find(_name);
|
||||||
@ -81,5 +81,5 @@ set<Declaration const*> DeclarationContainer::resolveName(ASTString const& _name
|
|||||||
return result->second;
|
return result->second;
|
||||||
if (_recursive && m_enclosingContainer)
|
if (_recursive && m_enclosingContainer)
|
||||||
return m_enclosingContainer->resolveName(_name, true);
|
return m_enclosingContainer->resolveName(_name, true);
|
||||||
return set<Declaration const*>({});
|
return vector<Declaration const*>({});
|
||||||
}
|
}
|
||||||
|
@ -48,17 +48,17 @@ public:
|
|||||||
/// @param _update if true, replaces a potential declaration that is already present
|
/// @param _update if true, replaces a potential declaration that is already present
|
||||||
/// @returns false if the name was already declared.
|
/// @returns false if the name was already declared.
|
||||||
bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false);
|
bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false);
|
||||||
std::set<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
|
std::vector<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
|
||||||
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
|
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
|
||||||
std::map<ASTString, std::set<Declaration const*>> const& getDeclarations() const { return m_declarations; }
|
std::map<ASTString, std::vector<Declaration const*>> const& getDeclarations() const { return m_declarations; }
|
||||||
/// @returns whether declaration is valid, and if not also returns previous declaration.
|
/// @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) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Declaration const* m_enclosingDeclaration;
|
Declaration const* m_enclosingDeclaration;
|
||||||
DeclarationContainer const* m_enclosingContainer;
|
DeclarationContainer const* m_enclosingContainer;
|
||||||
std::map<ASTString, std::set<Declaration const*>> m_declarations;
|
std::map<ASTString, std::vector<Declaration const*>> m_declarations;
|
||||||
std::map<ASTString, std::set<Declaration const*>> m_invisibleDeclarations;
|
std::map<ASTString, std::vector<Declaration const*>> m_invisibleDeclarations;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,13 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
m_currentScope = &m_scopes[&_contract];
|
m_currentScope = &m_scopes[&_contract];
|
||||||
|
|
||||||
linearizeBaseContracts(_contract);
|
linearizeBaseContracts(_contract);
|
||||||
// we first import non-functions only as we do not yet know the argument types
|
std::vector<ContractDefinition const*> realBases(
|
||||||
for (ContractDefinition const* base: _contract.getLinearizedBaseContracts())
|
++_contract.getLinearizedBaseContracts().begin(),
|
||||||
importInheritedScope(*base, false); // import non-functions
|
_contract.getLinearizedBaseContracts().end()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (ContractDefinition const* base: realBases)
|
||||||
|
importInheritedScope(*base);
|
||||||
|
|
||||||
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
|
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
|
||||||
ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
|
ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
|
||||||
@ -80,8 +84,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_currentScope = &m_scopes[&_contract];
|
m_currentScope = &m_scopes[&_contract];
|
||||||
for (ContractDefinition const* base: _contract.getLinearizedBaseContracts())
|
|
||||||
importInheritedScope(*base, true); // import functions
|
|
||||||
|
|
||||||
// now resolve references inside the code
|
// now resolve references inside the code
|
||||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.getFunctionModifiers())
|
for (ASTPointer<ModifierDefinition> const& modifier: _contract.getFunctionModifiers())
|
||||||
@ -115,20 +117,41 @@ void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
|||||||
solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope.");
|
solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope.");
|
||||||
}
|
}
|
||||||
|
|
||||||
set<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
|
vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
|
||||||
{
|
{
|
||||||
auto iterator = m_scopes.find(_scope);
|
auto iterator = m_scopes.find(_scope);
|
||||||
if (iterator == end(m_scopes))
|
if (iterator == end(m_scopes))
|
||||||
return set<Declaration const*>({});
|
return vector<Declaration const*>({});
|
||||||
return iterator->second.resolveName(_name, false);
|
return iterator->second.resolveName(_name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
set<Declaration const*> NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive)
|
vector<Declaration const*> NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive)
|
||||||
{
|
{
|
||||||
return m_currentScope->resolveName(_name, _recursive);
|
return m_currentScope->resolveName(_name, _recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base, bool _importFunctions)
|
vector<Declaration const*> NameAndTypeResolver::cleanupedDeclarations(Identifier const& _identifier)
|
||||||
|
{
|
||||||
|
vector<Declaration const*> result;
|
||||||
|
for (auto declaration : m_currentScope->resolveName(_identifier.getName()))
|
||||||
|
{
|
||||||
|
solAssert(declaration, "");
|
||||||
|
// the declaration is functionDefinition while declarations > 1
|
||||||
|
FunctionDefinition const& functionDefinition = dynamic_cast<FunctionDefinition const&>(*declaration);
|
||||||
|
FunctionType functionType(functionDefinition);
|
||||||
|
for(auto parameter: functionType.getParameterTypes() + functionType.getReturnParameterTypes())
|
||||||
|
if (!parameter)
|
||||||
|
BOOST_THROW_EXCEPTION(
|
||||||
|
DeclarationError() <<
|
||||||
|
errinfo_sourceLocation(_identifier.getLocation()) <<
|
||||||
|
errinfo_comment("Function type can not be used in this context")
|
||||||
|
);
|
||||||
|
//////////delete repitations. check by hasequalparameter types of function type
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
|
||||||
{
|
{
|
||||||
auto iterator = m_scopes.find(&_base);
|
auto iterator = m_scopes.find(&_base);
|
||||||
solAssert(iterator != end(m_scopes), "");
|
solAssert(iterator != end(m_scopes), "");
|
||||||
@ -136,30 +159,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base,
|
|||||||
for (auto const& declaration: nameAndDeclaration.second)
|
for (auto const& declaration: nameAndDeclaration.second)
|
||||||
// Import if it was declared in the base, is not the constructor and is visible in derived classes
|
// Import if it was declared in the base, is not the constructor and is visible in derived classes
|
||||||
if (declaration->getScope() == &_base && 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);
|
m_currentScope->registerDeclaration(*declaration);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const
|
void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const
|
||||||
@ -465,10 +465,9 @@ bool ReferencesResolver::visit(Identifier& _identifier)
|
|||||||
errinfo_comment("Undeclared identifier.")
|
errinfo_comment("Undeclared identifier.")
|
||||||
);
|
);
|
||||||
else if (declarations.size() == 1)
|
else if (declarations.size() == 1)
|
||||||
_identifier.setReferencedDeclaration(**declarations.begin(), m_currentContract);
|
_identifier.setReferencedDeclaration(*declarations.front(), m_currentContract);
|
||||||
else
|
else
|
||||||
// Duplicate declaration will be checked in checkTypeRequirements()
|
_identifier.setOverloadedDeclarations(m_resolver.cleanupedDeclarations(_identifier));
|
||||||
_identifier.setOverloadedDeclarations(declarations);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,19 +56,20 @@ public:
|
|||||||
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
|
/// 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 contract).
|
||||||
/// @returns a pointer to the declaration on success or nullptr on failure.
|
/// @returns a pointer to the declaration on success or nullptr on failure.
|
||||||
std::set<Declaration const*> resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const;
|
std::vector<const Declaration *> resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const;
|
||||||
|
|
||||||
/// Resolves a name in the "current" scope. Should only be called during the initial
|
/// Resolves a name in the "current" scope. Should only be called during the initial
|
||||||
/// resolving phase.
|
/// resolving phase.
|
||||||
std::set<Declaration const*> getNameFromCurrentScope(ASTString const& _name, bool _recursive = true);
|
std::vector<Declaration const*> getNameFromCurrentScope(ASTString const& _name, bool _recursive = true);
|
||||||
|
|
||||||
|
std::vector<Declaration const*> cleanupedDeclarations(Identifier const& _identifier);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
/// Either imports all non-function members or all function members declared directly in the
|
/// Imports all members declared directly in the given contract (i.e. does not import inherited members)
|
||||||
/// given contract (i.e. does not import inherited members) into the current scope if they are
|
/// into the current scope if they are not present already.
|
||||||
///not present already.
|
void importInheritedScope(ContractDefinition const& _base);
|
||||||
void importInheritedScope(ContractDefinition const& _base, bool _importFunctions);
|
|
||||||
|
|
||||||
/// Computes "C3-Linearization" of base contracts and stores it inside the contract.
|
/// Computes "C3-Linearization" of base contracts and stores it inside the contract.
|
||||||
void linearizeBaseContracts(ContractDefinition& _contract) const;
|
void linearizeBaseContracts(ContractDefinition& _contract) const;
|
||||||
|
1
Types.h
1
Types.h
@ -617,6 +617,7 @@ public:
|
|||||||
/// @returns true if this function can take the given argument types (possibly
|
/// @returns true if this function can take the given argument types (possibly
|
||||||
/// after implicit conversion).
|
/// after implicit conversion).
|
||||||
bool canTakeArguments(TypePointers const& _arguments) const;
|
bool canTakeArguments(TypePointers const& _arguments) const;
|
||||||
|
/// @returns true if the types of parameters are equal(does't check return parameter types)
|
||||||
bool hasEqualArgumentTypes(FunctionType const& _other) const;
|
bool hasEqualArgumentTypes(FunctionType const& _other) const;
|
||||||
|
|
||||||
Location const& getLocation() const { return m_location; }
|
Location const& getLocation() const { return m_location; }
|
||||||
|
Loading…
Reference in New Issue
Block a user