Respect "pragma stdlib" during name resolution.

This commit is contained in:
chriseth 2022-07-14 17:18:38 +02:00 committed by Nikola Matic
parent 2d490a0213
commit dc992ae767
5 changed files with 53 additions and 6 deletions

View File

@ -147,9 +147,18 @@ vector<Declaration const*> DeclarationContainer::resolveName(
ResolvingSettings _settings ResolvingSettings _settings
) const ) const
{ {
updateSettingsBasedOnStdlibPragma(_settings);
solAssert(!_name.empty(), "Attempt to resolve empty name."); solAssert(!_name.empty(), "Attempt to resolve empty name.");
vector<Declaration const*> result; vector<Declaration const*> result;
if (!_settings.autoPopulateStdlib && m_stdlibIdentifiers && m_stdlibIdentifiers->count(_name))
{
solAssert(!m_enclosingContainer);
return result;
}
if (m_declarations.count(_name)) if (m_declarations.count(_name))
{ {
if (_settings.onlyVisibleAsUnqualifiedNames) if (_settings.onlyVisibleAsUnqualifiedNames)
@ -211,7 +220,18 @@ void DeclarationContainer::populateHomonyms(back_insert_iterator<Homonyms> _it)
settings.recursive = true; settings.recursive = true;
settings.alsoInvisible = true; settings.alsoInvisible = true;
vector<Declaration const*> const& declarations = m_enclosingContainer->resolveName(name, std::move(settings)); vector<Declaration const*> const& declarations = m_enclosingContainer->resolveName(name, std::move(settings));
if (!declarations.empty()) if (!declarations.empty())
_it = make_pair(location, declarations); _it = make_pair(location, declarations);
} }
} }
void DeclarationContainer::updateSettingsBasedOnStdlibPragma(ResolvingSettings& _settings) const
{
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(m_selfNode))
{
solAssert(sourceUnit->annotation().useStdlib.set());
if (*sourceUnit->annotation().useStdlib)
_settings.autoPopulateStdlib = false;
}
}

View File

@ -45,6 +45,9 @@ struct ResolvingSettings
/// if true, do not include declarations which can never actually be referenced using their /// 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). /// name alone (without being qualified with the name of scope in which they are declared).
bool onlyVisibleAsUnqualifiedNames = false; 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<std::pair<langutil::SourceLocation const*, std::vector<Declaration const*>>>; using Homonyms = std::vector<std::pair<langutil::SourceLocation const*, std::vector<Declaration const*>>>;
DeclarationContainer() = default; 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_enclosingNode(_enclosingNode),
m_enclosingContainer(_enclosingContainer) m_enclosingContainer(_enclosingContainer)
{ {
if (_enclosingContainer) if (_enclosingContainer)
_enclosingContainer->m_innerContainers.emplace_back(this); _enclosingContainer->m_innerContainers.emplace_back(this);
} }
void setStdlibIdentifiers(std::set<std::string> const& _stdlibIdentifiers)
{
m_stdlibIdentifiers = &_stdlibIdentifiers;
}
/// Registers the declaration in the scope unless its name is already declared or the name is empty. /// 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 _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. /// @param _location alternative location, used to point at homonymous declarations.
@ -100,11 +108,16 @@ public:
void populateHomonyms(std::back_insert_iterator<Homonyms> _it) const; void populateHomonyms(std::back_insert_iterator<Homonyms> _it) const;
private: 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; ASTNode const* m_enclosingNode = nullptr;
DeclarationContainer const* m_enclosingContainer = nullptr; DeclarationContainer const* m_enclosingContainer = nullptr;
std::vector<DeclarationContainer const*> m_innerContainers; std::vector<DeclarationContainer const*> m_innerContainers;
std::map<ASTString, std::vector<Declaration const*>> m_declarations; std::map<ASTString, std::vector<Declaration const*>> m_declarations;
std::map<ASTString, std::vector<Declaration const*>> m_invisibleDeclarations; std::map<ASTString, std::vector<Declaration const*>> m_invisibleDeclarations;
std::set<std::string> const* m_stdlibIdentifiers = nullptr;
/// List of declarations (name and location) to check later for homonymity. /// List of declarations (name and location) to check later for homonymity.
std::vector<std::pair<std::string, langutil::SourceLocation const*>> m_homonymCandidates; std::vector<std::pair<std::string, langutil::SourceLocation const*>> m_homonymCandidates;
}; };

View File

@ -125,6 +125,16 @@ vector<Declaration const*> GlobalContext::declarations() const
return declarations; return declarations;
} }
set<string> const& GlobalContext::stdlibIdentifiers()
{
set<string> static names{
"ecrecover",
"ripemd160",
"sha256"
};
return names;
}
MagicVariableDeclaration const* GlobalContext::currentThis() const MagicVariableDeclaration const* GlobalContext::currentThis() const
{ {
if (!m_thisPointer[m_currentContract]) if (!m_thisPointer[m_currentContract])

View File

@ -28,6 +28,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
namespace solidity::frontend namespace solidity::frontend
{ {
@ -55,6 +56,9 @@ public:
/// @returns a vector of all implicit global declarations excluding "this". /// @returns a vector of all implicit global declarations excluding "this".
std::vector<Declaration const*> declarations() const; std::vector<Declaration const*> declarations() const;
/// @returns the set of identifiers that are not present in the global scope
/// when the "pragma stdlib" is active.
static std::set<std::string> const& stdlibIdentifiers();
private: private:
std::vector<std::shared_ptr<MagicVariableDeclaration const>> m_magicVariables; std::vector<std::shared_ptr<MagicVariableDeclaration const>> m_magicVariables;

View File

@ -47,9 +47,8 @@ NameAndTypeResolver::NameAndTypeResolver(
{ {
m_scopes[nullptr] = make_shared<DeclarationContainer>(); m_scopes[nullptr] = make_shared<DeclarationContainer>();
for (Declaration const* declaration: _globalContext.declarations()) for (Declaration const* declaration: _globalContext.declarations())
{
solAssert(m_scopes[nullptr]->registerDeclaration(*declaration, false, false), "Unable to register global declaration."); 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) bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode const* _currentScope)
@ -573,7 +572,7 @@ bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit)
{ {
if (!m_scopes[&_sourceUnit]) if (!m_scopes[&_sourceUnit])
// By importing, it is possible that the container already exists. // By importing, it is possible that the container already exists.
m_scopes[&_sourceUnit] = make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get()); m_scopes[&_sourceUnit] = make_shared<DeclarationContainer>(&_sourceUnit, m_currentScope, m_scopes[m_currentScope].get());
return ASTVisitor::visit(_sourceUnit); return ASTVisitor::visit(_sourceUnit);
} }
@ -587,7 +586,8 @@ bool DeclarationRegistrationHelper::visit(ImportDirective& _import)
SourceUnit const* importee = _import.annotation().sourceUnit; SourceUnit const* importee = _import.annotation().sourceUnit;
solAssert(!!importee, ""); solAssert(!!importee, "");
if (!m_scopes[importee]) if (!m_scopes[importee])
m_scopes[importee] = make_shared<DeclarationContainer>(nullptr, m_scopes[nullptr].get()); m_scopes[importee] = make_shared<DeclarationContainer>(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]; m_scopes[&_import] = m_scopes[importee];
ASTVisitor::visit(_import); ASTVisitor::visit(_import);
return false; // Do not recurse into child nodes (Identifier for symbolAliases) 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( bool newlyAdded = m_scopes.emplace(
&_subScope, &_subScope,
make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get()) make_shared<DeclarationContainer>(&_subScope, m_currentScope, m_scopes[m_currentScope].get())
).second; ).second;
solAssert(newlyAdded, "Unable to add new scope."); solAssert(newlyAdded, "Unable to add new scope.");
} }