diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index b6cd3eef0..3fd45f41a 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -147,9 +147,18 @@ vector DeclarationContainer::resolveName( ResolvingSettings _settings ) const { + updateSettingsBasedOnStdlibPragma(_settings); + solAssert(!_name.empty(), "Attempt to resolve empty name."); vector result; + if (!_settings.autoPopulateStdlib && m_stdlibIdentifiers && m_stdlibIdentifiers->count(_name)) + { + solAssert(!m_enclosingContainer); + return result; + } + + if (m_declarations.count(_name)) { if (_settings.onlyVisibleAsUnqualifiedNames) @@ -211,7 +220,18 @@ void DeclarationContainer::populateHomonyms(back_insert_iterator _it) settings.recursive = true; settings.alsoInvisible = true; vector const& declarations = m_enclosingContainer->resolveName(name, std::move(settings)); + if (!declarations.empty()) _it = make_pair(location, declarations); } } + +void DeclarationContainer::updateSettingsBasedOnStdlibPragma(ResolvingSettings& _settings) const +{ + if (auto const* sourceUnit = dynamic_cast(m_selfNode)) + { + solAssert(sourceUnit->annotation().useStdlib.set()); + if (*sourceUnit->annotation().useStdlib) + _settings.autoPopulateStdlib = false; + } +} diff --git a/libsolidity/analysis/DeclarationContainer.h b/libsolidity/analysis/DeclarationContainer.h index 279ee1806..e4cc97d1a 100644 --- a/libsolidity/analysis/DeclarationContainer.h +++ b/libsolidity/analysis/DeclarationContainer.h @@ -45,6 +45,9 @@ struct ResolvingSettings /// if true, do not include declarations which can never actually be referenced using their /// name alone (without being qualified with the name of scope in which they are declared). bool onlyVisibleAsUnqualifiedNames = false; + /// If false, ignores symbols in the global scope that are part of the standard library + /// (this is set to false with "pragma stdlib"). + bool autoPopulateStdlib = true; }; @@ -58,13 +61,18 @@ public: using Homonyms = std::vector>>; DeclarationContainer() = default; - explicit DeclarationContainer(ASTNode const* _enclosingNode, DeclarationContainer* _enclosingContainer): + explicit DeclarationContainer(ASTNode const* _selfNode, ASTNode const* _enclosingNode, DeclarationContainer* _enclosingContainer): + m_selfNode(_selfNode), m_enclosingNode(_enclosingNode), m_enclosingContainer(_enclosingContainer) { if (_enclosingContainer) _enclosingContainer->m_innerContainers.emplace_back(this); } + void setStdlibIdentifiers(std::set const& _stdlibIdentifiers) + { + m_stdlibIdentifiers = &_stdlibIdentifiers; + } /// 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 _location alternative location, used to point at homonymous declarations. @@ -100,11 +108,16 @@ public: void populateHomonyms(std::back_insert_iterator _it) const; private: + /// Disables autoPopulateStdlib in _settinsg if "pragma stdlib" is active in m_selfNode. + void updateSettingsBasedOnStdlibPragma(ResolvingSettings& _settings) const; + + ASTNode const* m_selfNode = nullptr; ASTNode const* m_enclosingNode = nullptr; DeclarationContainer const* m_enclosingContainer = nullptr; std::vector m_innerContainers; std::map> m_declarations; std::map> m_invisibleDeclarations; + std::set const* m_stdlibIdentifiers = nullptr; /// List of declarations (name and location) to check later for homonymity. std::vector> m_homonymCandidates; }; diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 58ebea7b1..784c330e9 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -125,6 +125,16 @@ vector GlobalContext::declarations() const return declarations; } +set const& GlobalContext::stdlibIdentifiers() +{ + set static names{ + "ecrecover", + "ripemd160", + "sha256" + }; + return names; +} + MagicVariableDeclaration const* GlobalContext::currentThis() const { if (!m_thisPointer[m_currentContract]) diff --git a/libsolidity/analysis/GlobalContext.h b/libsolidity/analysis/GlobalContext.h index 69344537c..09d9efce1 100644 --- a/libsolidity/analysis/GlobalContext.h +++ b/libsolidity/analysis/GlobalContext.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace solidity::frontend { @@ -55,6 +56,9 @@ public: /// @returns a vector of all implicit global declarations excluding "this". std::vector declarations() const; + /// @returns the set of identifiers that are not present in the global scope + /// when the "pragma stdlib" is active. + static std::set const& stdlibIdentifiers(); private: std::vector> m_magicVariables; diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 1b58d3c9a..1a9d0104c 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -47,9 +47,8 @@ NameAndTypeResolver::NameAndTypeResolver( { m_scopes[nullptr] = make_shared(); for (Declaration const* declaration: _globalContext.declarations()) - { solAssert(m_scopes[nullptr]->registerDeclaration(*declaration, false, false), "Unable to register global declaration."); - } + m_scopes[nullptr]->setStdlibIdentifiers(_globalContext.stdlibIdentifiers()); } bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode const* _currentScope) @@ -573,7 +572,7 @@ bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit) { if (!m_scopes[&_sourceUnit]) // By importing, it is possible that the container already exists. - m_scopes[&_sourceUnit] = make_shared(m_currentScope, m_scopes[m_currentScope].get()); + m_scopes[&_sourceUnit] = make_shared(&_sourceUnit, m_currentScope, m_scopes[m_currentScope].get()); return ASTVisitor::visit(_sourceUnit); } @@ -587,7 +586,8 @@ bool DeclarationRegistrationHelper::visit(ImportDirective& _import) SourceUnit const* importee = _import.annotation().sourceUnit; solAssert(!!importee, ""); if (!m_scopes[importee]) - m_scopes[importee] = make_shared(nullptr, m_scopes[nullptr].get()); + m_scopes[importee] = make_shared(importee, nullptr, m_scopes[nullptr].get()); + // TODO here, m_selfNode inside the contanier does not point to the key of m_scopes (_import) - is that a problem? m_scopes[&_import] = m_scopes[importee]; ASTVisitor::visit(_import); return false; // Do not recurse into child nodes (Identifier for symbolAliases) @@ -677,7 +677,7 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope) { bool newlyAdded = m_scopes.emplace( &_subScope, - make_shared(m_currentScope, m_scopes[m_currentScope].get()) + make_shared(&_subScope, m_currentScope, m_scopes[m_currentScope].get()) ).second; solAssert(newlyAdded, "Unable to add new scope."); }