diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 968aa744c..239aadf45 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -185,8 +185,18 @@ vector NameAndTypeResolver::nameFromCurrentScope(ASTString c } Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector const& _path) const +{ + if (auto declarations = pathFromCurrentScopeWithAllDeclarations(_path); !declarations.empty()) + return declarations.back(); + + return nullptr; +} + +std::vector NameAndTypeResolver::pathFromCurrentScopeWithAllDeclarations(std::vector const& _path) const { solAssert(!_path.empty(), ""); + vector pathDeclarations; + vector candidates = m_currentScope->resolveName( _path.front(), /* _recursive */ true, @@ -197,13 +207,19 @@ Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector c for (size_t i = 1; i < _path.size() && candidates.size() == 1; i++) { if (!m_scopes.count(candidates.front())) - return nullptr; + return {}; + + pathDeclarations.push_back(candidates.front()); + candidates = m_scopes.at(candidates.front())->resolveName(_path[i], false); } if (candidates.size() == 1) - return candidates.front(); + { + pathDeclarations.push_back(candidates.front()); + return pathDeclarations; + } else - return nullptr; + return {}; } void NameAndTypeResolver::warnHomonymDeclarations() const diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 36a22ed2e..2bf238a00 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -93,6 +93,10 @@ public: /// Should only be called during the initial resolving phase. /// @note Returns a null pointer if any component in the path was not unique or not found. Declaration const* pathFromCurrentScope(std::vector const& _path) const; + /// Resolves a path starting from the "current" scope, but also searches parent scopes. + /// Should only be called during the initial resolving phase. + /// @note Returns an empty vector if any component in the path was non-unique or not found. Otherwise, all declarations along the path are returned. + std::vector pathFromCurrentScopeWithAllDeclarations(std::vector const& _path) const; /// Generate and store warnings about declarations with the same name. void warnHomonymDeclarations() const; diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 6b58ab27c..bf1fef7aa 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -173,14 +173,15 @@ void ReferencesResolver::endVisit(ModifierDefinition const&) void ReferencesResolver::endVisit(IdentifierPath const& _path) { - Declaration const* declaration = m_resolver.pathFromCurrentScope(_path.path()); - if (!declaration) + std::vector declarations = m_resolver.pathFromCurrentScopeWithAllDeclarations(_path.path()); + if (declarations.empty()) { m_errorReporter.fatalDeclarationError(7920_error, _path.location(), "Identifier not found or not unique."); return; } - _path.annotation().referencedDeclaration = declaration; + _path.annotation().referencedDeclaration = declarations.back(); + _path.annotation().pathDeclarations = std::move(declarations); } bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 3497a2ea8..2615e6af7 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -256,6 +256,9 @@ struct IdentifierPathAnnotation: ASTAnnotation Declaration const* referencedDeclaration = nullptr; /// What kind of lookup needs to be done (static, virtual, super) find the declaration. util::SetOnce requiredLookup; + + /// Declaration of each path element. + std::vector pathDeclarations; }; struct ExpressionAnnotation: ASTAnnotation