mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #9586 from ethereum/scoper
Assign scopes as a separate step.
This commit is contained in:
		
						commit
						72f8a753a9
					
				| @ -30,6 +30,8 @@ set(sources | |||||||
| 	analysis/PostTypeChecker.h | 	analysis/PostTypeChecker.h | ||||||
| 	analysis/ReferencesResolver.cpp | 	analysis/ReferencesResolver.cpp | ||||||
| 	analysis/ReferencesResolver.h | 	analysis/ReferencesResolver.h | ||||||
|  | 	analysis/Scoper.cpp | ||||||
|  | 	analysis/Scoper.h | ||||||
| 	analysis/StaticAnalyzer.cpp | 	analysis/StaticAnalyzer.cpp | ||||||
| 	analysis/StaticAnalyzer.h | 	analysis/StaticAnalyzer.h | ||||||
| 	analysis/SyntaxChecker.cpp | 	analysis/SyntaxChecker.cpp | ||||||
|  | |||||||
| @ -519,14 +519,13 @@ 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>(m_currentScope, m_scopes[m_currentScope].get()); | ||||||
| 	m_currentScope = &_sourceUnit; | 	return ASTVisitor::visit(_sourceUnit); | ||||||
| 	return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit) | void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit) | ||||||
| { | { | ||||||
| 	_sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations(); | 	_sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations(); | ||||||
| 	closeCurrentScope(); | 	ASTVisitor::endVisit(_sourceUnit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool DeclarationRegistrationHelper::visit(ImportDirective& _import) | bool DeclarationRegistrationHelper::visit(ImportDirective& _import) | ||||||
| @ -536,8 +535,7 @@ bool DeclarationRegistrationHelper::visit(ImportDirective& _import) | |||||||
| 	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>(nullptr, m_scopes[nullptr].get()); | ||||||
| 	m_scopes[&_import] = m_scopes[importee]; | 	m_scopes[&_import] = m_scopes[importee]; | ||||||
| 	registerDeclaration(_import, false); | 	return ASTVisitor::visit(_import); | ||||||
| 	return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract) | bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract) | ||||||
| @ -547,122 +545,17 @@ bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract) | |||||||
| 	m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, false, true); | 	m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, false, true); | ||||||
| 	m_currentContract = &_contract; | 	m_currentContract = &_contract; | ||||||
| 
 | 
 | ||||||
| 	registerDeclaration(_contract, true); | 	return ASTVisitor::visit(_contract); | ||||||
| 	_contract.annotation().canonicalName = currentCanonicalName(); |  | ||||||
| 	return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DeclarationRegistrationHelper::endVisit(ContractDefinition&) | void DeclarationRegistrationHelper::endVisit(ContractDefinition& _contract) | ||||||
| { | { | ||||||
| 	// make "this" and "super" invisible.
 | 	// make "this" and "super" invisible.
 | ||||||
| 	m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentThis(), nullptr, true, true); | 	m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentThis(), nullptr, true, true); | ||||||
| 	m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, true, true); | 	m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, true, true); | ||||||
| 	m_globalContext.resetCurrentContract(); | 	m_globalContext.resetCurrentContract(); | ||||||
| 	m_currentContract = nullptr; | 	m_currentContract = nullptr; | ||||||
| 	closeCurrentScope(); | 	ASTVisitor::endVisit(_contract); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(StructDefinition& _struct) |  | ||||||
| { |  | ||||||
| 	registerDeclaration(_struct, true); |  | ||||||
| 	_struct.annotation().canonicalName = currentCanonicalName(); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(StructDefinition&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(EnumDefinition& _enum) |  | ||||||
| { |  | ||||||
| 	registerDeclaration(_enum, true); |  | ||||||
| 	_enum.annotation().canonicalName = currentCanonicalName(); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(EnumDefinition&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(EnumValue& _value) |  | ||||||
| { |  | ||||||
| 	registerDeclaration(_value, false); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(FunctionDefinition& _function) |  | ||||||
| { |  | ||||||
| 	registerDeclaration(_function, true); |  | ||||||
| 	m_currentFunction = &_function; |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(FunctionDefinition&) |  | ||||||
| { |  | ||||||
| 	m_currentFunction = nullptr; |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause) |  | ||||||
| { |  | ||||||
| 	_tryCatchClause.annotation().scope = m_currentScope; |  | ||||||
| 	enterNewSubScope(_tryCatchClause); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(TryCatchClause&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(ModifierDefinition& _modifier) |  | ||||||
| { |  | ||||||
| 	registerDeclaration(_modifier, true); |  | ||||||
| 	m_currentFunction = &_modifier; |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(ModifierDefinition&) |  | ||||||
| { |  | ||||||
| 	m_currentFunction = nullptr; |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(FunctionTypeName& _funTypeName) |  | ||||||
| { |  | ||||||
| 	enterNewSubScope(_funTypeName); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(FunctionTypeName&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(Block& _block) |  | ||||||
| { |  | ||||||
| 	_block.annotation().scope = m_currentScope; |  | ||||||
| 	enterNewSubScope(_block); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(Block&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DeclarationRegistrationHelper::visit(ForStatement& _for) |  | ||||||
| { |  | ||||||
| 	_for.annotation().scope = m_currentScope; |  | ||||||
| 	enterNewSubScope(_for); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeclarationRegistrationHelper::endVisit(ForStatement&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) | void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) | ||||||
| @ -673,32 +566,42 @@ void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _vari | |||||||
| 	for (ASTPointer<VariableDeclaration> const& var: _variableDeclarationStatement.declarations()) | 	for (ASTPointer<VariableDeclaration> const& var: _variableDeclarationStatement.declarations()) | ||||||
| 		if (var) | 		if (var) | ||||||
| 			m_currentFunction->addLocalVariable(*var); | 			m_currentFunction->addLocalVariable(*var); | ||||||
|  | 	ASTVisitor::endVisit(_variableDeclarationStatement); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) | bool DeclarationRegistrationHelper::visitNode(ASTNode& _node) | ||||||
| { | { | ||||||
| 	registerDeclaration(_declaration, false); | 	if (auto const* scopable = dynamic_cast<Scopable const*>(&_node)) | ||||||
|  | 		solAssert(scopable->annotation().scope == m_currentScope, ""); | ||||||
|  | 
 | ||||||
|  | 	if (auto* declaration = dynamic_cast<Declaration*>(&_node)) | ||||||
|  | 		registerDeclaration(*declaration); | ||||||
|  | 	if (dynamic_cast<ScopeOpener const*>(&_node)) | ||||||
|  | 		enterNewSubScope(_node); | ||||||
|  | 
 | ||||||
|  | 	if (auto* variableScope = dynamic_cast<VariableScope*>(&_node)) | ||||||
|  | 		m_currentFunction = variableScope; | ||||||
|  | 	if (auto* annotation = dynamic_cast<TypeDeclarationAnnotation*>(&_node.annotation())) | ||||||
|  | 		annotation->canonicalName = currentCanonicalName(); | ||||||
|  | 
 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool DeclarationRegistrationHelper::visit(EventDefinition& _event) | void DeclarationRegistrationHelper::endVisitNode(ASTNode& _node) | ||||||
| { | { | ||||||
| 	registerDeclaration(_event, true); | 	if (dynamic_cast<ScopeOpener const*>(&_node)) | ||||||
| 	return true; | 		closeCurrentScope(); | ||||||
| } | 	if (dynamic_cast<VariableScope*>(&_node)) | ||||||
| 
 | 		m_currentFunction = nullptr; | ||||||
| void DeclarationRegistrationHelper::endVisit(EventDefinition&) |  | ||||||
| { |  | ||||||
| 	closeCurrentScope(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope) | void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope) | ||||||
| { | { | ||||||
| 	map<ASTNode const*, shared_ptr<DeclarationContainer>>::iterator iter; |  | ||||||
| 	bool newlyAdded; |  | ||||||
| 	shared_ptr<DeclarationContainer> container{make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get())}; | 	shared_ptr<DeclarationContainer> container{make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get())}; | ||||||
| 	tie(iter, newlyAdded) = m_scopes.emplace(&_subScope, move(container)); | 	bool newlyAdded = m_scopes.emplace(&_subScope, move(container)).second; | ||||||
| 	solAssert(newlyAdded, "Unable to add new scope."); | 	// Source units are the only AST nodes for which containers can be created from multiple places
 | ||||||
|  | 	// due to imports.
 | ||||||
|  | 	solAssert(newlyAdded || dynamic_cast<SourceUnit const*>(&_subScope), "Unable to add new scope."); | ||||||
| 	m_currentScope = &_subScope; | 	m_currentScope = &_subScope; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -708,7 +611,7 @@ void DeclarationRegistrationHelper::closeCurrentScope() | |||||||
| 	m_currentScope = m_scopes[m_currentScope]->enclosingNode(); | 	m_currentScope = m_scopes[m_currentScope]->enclosingNode(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) | void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration) | ||||||
| { | { | ||||||
| 	solAssert(m_currentScope && m_scopes.count(m_currentScope), "No current scope."); | 	solAssert(m_currentScope && m_scopes.count(m_currentScope), "No current scope."); | ||||||
| 
 | 
 | ||||||
| @ -729,10 +632,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio | |||||||
| 
 | 
 | ||||||
| 	registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter); | 	registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter); | ||||||
| 
 | 
 | ||||||
| 	_declaration.annotation().scope = m_currentScope; | 	solAssert(_declaration.annotation().scope == m_currentScope, ""); | ||||||
| 	_declaration.annotation().contract = m_currentContract; | 	solAssert(_declaration.annotation().contract == m_currentContract, ""); | ||||||
| 	if (_opensScope) |  | ||||||
| 		enterNewSubScope(_declaration); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| string DeclarationRegistrationHelper::currentCanonicalName() const | string DeclarationRegistrationHelper::currentCanonicalName() const | ||||||
|  | |||||||
| @ -163,31 +163,15 @@ private: | |||||||
| 	bool visit(ImportDirective& _import) override; | 	bool visit(ImportDirective& _import) override; | ||||||
| 	bool visit(ContractDefinition& _contract) override; | 	bool visit(ContractDefinition& _contract) override; | ||||||
| 	void endVisit(ContractDefinition& _contract) override; | 	void endVisit(ContractDefinition& _contract) override; | ||||||
| 	bool visit(StructDefinition& _struct) override; |  | ||||||
| 	void endVisit(StructDefinition& _struct) override; |  | ||||||
| 	bool visit(EnumDefinition& _enum) override; |  | ||||||
| 	void endVisit(EnumDefinition& _enum) override; |  | ||||||
| 	bool visit(EnumValue& _value) override; |  | ||||||
| 	bool visit(FunctionDefinition& _function) override; |  | ||||||
| 	void endVisit(FunctionDefinition& _function) override; |  | ||||||
| 	bool visit(TryCatchClause& _tryCatchClause) override; |  | ||||||
| 	void endVisit(TryCatchClause& _tryCatchClause) override; |  | ||||||
| 	bool visit(ModifierDefinition& _modifier) override; |  | ||||||
| 	void endVisit(ModifierDefinition& _modifier) override; |  | ||||||
| 	bool visit(FunctionTypeName& _funTypeName) override; |  | ||||||
| 	void endVisit(FunctionTypeName& _funTypeName) override; |  | ||||||
| 	bool visit(Block& _block) override; |  | ||||||
| 	void endVisit(Block& _block) override; |  | ||||||
| 	bool visit(ForStatement& _forLoop) override; |  | ||||||
| 	void endVisit(ForStatement& _forLoop) override; |  | ||||||
| 	void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; | 	void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; | ||||||
| 	bool visit(VariableDeclaration& _declaration) override; | 
 | ||||||
| 	bool visit(EventDefinition& _event) override; | 	bool visitNode(ASTNode& _node) override; | ||||||
| 	void endVisit(EventDefinition& _event) override; | 	void endVisitNode(ASTNode& _node) override; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	void enterNewSubScope(ASTNode& _subScope); | 	void enterNewSubScope(ASTNode& _subScope); | ||||||
| 	void closeCurrentScope(); | 	void closeCurrentScope(); | ||||||
| 	void registerDeclaration(Declaration& _declaration, bool _opensScope); | 	void registerDeclaration(Declaration& _declaration); | ||||||
| 
 | 
 | ||||||
| 	static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2); | 	static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										63
									
								
								libsolidity/analysis/Scoper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								libsolidity/analysis/Scoper.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | /*
 | ||||||
|  | 	This file is part of solidity. | ||||||
|  | 
 | ||||||
|  | 	solidity is free software: you can redistribute it and/or modify | ||||||
|  | 	it under the terms of the GNU General Public License as published by | ||||||
|  | 	the Free Software Foundation, either version 3 of the License, or | ||||||
|  | 	(at your option) any later version. | ||||||
|  | 
 | ||||||
|  | 	solidity is distributed in the hope that it will be useful, | ||||||
|  | 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | 	GNU General Public License for more details. | ||||||
|  | 
 | ||||||
|  | 	You should have received a copy of the GNU General Public License | ||||||
|  | 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | */ | ||||||
|  | // SPDX-License-Identifier: GPL-3.0
 | ||||||
|  | 
 | ||||||
|  | #include <libsolidity/analysis/Scoper.h> | ||||||
|  | 
 | ||||||
|  | #include <libsolidity/ast/AST.h> | ||||||
|  | 
 | ||||||
|  | using namespace std; | ||||||
|  | using namespace solidity; | ||||||
|  | using namespace solidity::frontend; | ||||||
|  | 
 | ||||||
|  | void Scoper::assignScopes(ASTNode const& _astRoot) | ||||||
|  | { | ||||||
|  | 	Scoper scoper; | ||||||
|  | 	_astRoot.accept(scoper); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Scoper::visit(ContractDefinition const& _contract) | ||||||
|  | { | ||||||
|  | 	solAssert(m_contract == nullptr, ""); | ||||||
|  | 	m_contract = &_contract; | ||||||
|  | 	return ASTConstVisitor::visit(_contract); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Scoper::endVisit(ContractDefinition const& _contract) | ||||||
|  | { | ||||||
|  | 	solAssert(m_contract == &_contract, ""); | ||||||
|  | 	m_contract = nullptr; | ||||||
|  | 	ASTConstVisitor::endVisit(_contract); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Scoper::visitNode(ASTNode const& _node) | ||||||
|  | { | ||||||
|  | 	if (auto const* scopable = dynamic_cast<Scopable const*>(&_node)) | ||||||
|  | 	{ | ||||||
|  | 		scopable->annotation().scope = m_scopes.empty() ? nullptr : m_scopes.back(); | ||||||
|  | 		scopable->annotation().contract = m_contract; | ||||||
|  | 	} | ||||||
|  | 	if (dynamic_cast<ScopeOpener const*>(&_node)) | ||||||
|  | 		m_scopes.push_back(&_node); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Scoper::endVisitNode(ASTNode const& _node) | ||||||
|  | { | ||||||
|  | 	if (dynamic_cast<ScopeOpener const*>(&_node)) | ||||||
|  | 		m_scopes.pop_back(); | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								libsolidity/analysis/Scoper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								libsolidity/analysis/Scoper.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | /*
 | ||||||
|  | 	This file is part of solidity. | ||||||
|  | 
 | ||||||
|  | 	solidity is free software: you can redistribute it and/or modify | ||||||
|  | 	it under the terms of the GNU General Public License as published by | ||||||
|  | 	the Free Software Foundation, either version 3 of the License, or | ||||||
|  | 	(at your option) any later version. | ||||||
|  | 
 | ||||||
|  | 	solidity is distributed in the hope that it will be useful, | ||||||
|  | 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | 	GNU General Public License for more details. | ||||||
|  | 
 | ||||||
|  | 	You should have received a copy of the GNU General Public License | ||||||
|  | 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | */ | ||||||
|  | // SPDX-License-Identifier: GPL-3.0
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <libsolidity/ast/ASTForward.h> | ||||||
|  | #include <libsolidity/ast/ASTVisitor.h> | ||||||
|  | 
 | ||||||
|  | namespace solidity::frontend | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * AST visitor that assigns syntactic scopes. | ||||||
|  |  */ | ||||||
|  | class Scoper: private ASTConstVisitor | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	static void assignScopes(ASTNode const& _astRoot); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	bool visit(ContractDefinition const& _contract) override; | ||||||
|  | 	void endVisit(ContractDefinition const& _contract) override; | ||||||
|  | 	bool visitNode(ASTNode const& _node) override; | ||||||
|  | 	void endVisitNode(ASTNode const& _node) override; | ||||||
|  | 
 | ||||||
|  | 	ContractDefinition const* m_contract = nullptr; | ||||||
|  | 	std::vector<ASTNode const*> m_scopes; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -152,10 +152,19 @@ std::vector<T const*> ASTNode::filteredNodes(std::vector<ASTPointer<ASTNode>> co | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Abstract marker class that specifies that this AST node opens a scope. | ||||||
|  |  */ | ||||||
|  | class ScopeOpener | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	virtual ~ScopeOpener() = default; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Source unit containing import directives and contract definitions. |  * Source unit containing import directives and contract definitions. | ||||||
|  */ |  */ | ||||||
| class SourceUnit: public ASTNode | class SourceUnit: public ASTNode, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	SourceUnit( | 	SourceUnit( | ||||||
| @ -455,7 +464,7 @@ protected: | |||||||
|  * document order. It first visits all struct declarations, then all variable declarations and |  * document order. It first visits all struct declarations, then all variable declarations and | ||||||
|  * finally all function declarations. |  * finally all function declarations. | ||||||
|  */ |  */ | ||||||
| class ContractDefinition: public Declaration, public StructurallyDocumented | class ContractDefinition: public Declaration, public StructurallyDocumented, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	ContractDefinition( | 	ContractDefinition( | ||||||
| @ -593,7 +602,7 @@ private: | |||||||
| 	ASTPointer<TypeName> m_typeName; | 	ASTPointer<TypeName> m_typeName; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class StructDefinition: public Declaration | class StructDefinition: public Declaration, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	StructDefinition( | 	StructDefinition( | ||||||
| @ -620,7 +629,7 @@ private: | |||||||
| 	std::vector<ASTPointer<VariableDeclaration>> m_members; | 	std::vector<ASTPointer<VariableDeclaration>> m_members; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class EnumDefinition: public Declaration | class EnumDefinition: public Declaration, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	EnumDefinition( | 	EnumDefinition( | ||||||
| @ -765,7 +774,7 @@ protected: | |||||||
| 	std::vector<ASTPointer<UserDefinedTypeName>> m_overrides; | 	std::vector<ASTPointer<UserDefinedTypeName>> m_overrides; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional | class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	FunctionDefinition( | 	FunctionDefinition( | ||||||
| @ -989,7 +998,7 @@ private: | |||||||
| /**
 | /**
 | ||||||
|  * Definition of a function modifier. |  * Definition of a function modifier. | ||||||
|  */ |  */ | ||||||
| class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional | class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	ModifierDefinition( | 	ModifierDefinition( | ||||||
| @ -1061,7 +1070,7 @@ private: | |||||||
| /**
 | /**
 | ||||||
|  * Definition of a (loggable) event. |  * Definition of a (loggable) event. | ||||||
|  */ |  */ | ||||||
| class EventDefinition: public CallableDeclaration, public StructurallyDocumented | class EventDefinition: public CallableDeclaration, public StructurallyDocumented, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	EventDefinition( | 	EventDefinition( | ||||||
| @ -1199,7 +1208,7 @@ private: | |||||||
| /**
 | /**
 | ||||||
|  * A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)" |  * A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)" | ||||||
|  */ |  */ | ||||||
| class FunctionTypeName: public TypeName | class FunctionTypeName: public TypeName, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	FunctionTypeName( | 	FunctionTypeName( | ||||||
| @ -1334,7 +1343,7 @@ private: | |||||||
| /**
 | /**
 | ||||||
|  * Brace-enclosed block containing zero or more statements. |  * Brace-enclosed block containing zero or more statements. | ||||||
|  */ |  */ | ||||||
| class Block: public Statement, public Scopable | class Block: public Statement, public Scopable, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	Block( | 	Block( | ||||||
| @ -1411,7 +1420,7 @@ private: | |||||||
|  * unsuccessful cases. |  * unsuccessful cases. | ||||||
|  * Names are only allowed for the unsuccessful cases. |  * Names are only allowed for the unsuccessful cases. | ||||||
|  */ |  */ | ||||||
| class TryCatchClause: public ASTNode, public Scopable | class TryCatchClause: public ASTNode, public Scopable, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	TryCatchClause( | 	TryCatchClause( | ||||||
| @ -1526,7 +1535,7 @@ private: | |||||||
| /**
 | /**
 | ||||||
|  * For loop statement |  * For loop statement | ||||||
|  */ |  */ | ||||||
| class ForStatement: public BreakableStatement, public Scopable | class ForStatement: public BreakableStatement, public Scopable, public ScopeOpener | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	ForStatement( | 	ForStatement( | ||||||
|  | |||||||
| @ -108,10 +108,10 @@ struct ScopableAnnotation | |||||||
| 	virtual ~ScopableAnnotation() = default; | 	virtual ~ScopableAnnotation() = default; | ||||||
| 
 | 
 | ||||||
| 	/// The scope this declaration resides in. Can be nullptr if it is the global scope.
 | 	/// The scope this declaration resides in. Can be nullptr if it is the global scope.
 | ||||||
| 	/// Available only after name and type resolution step.
 | 	/// Filled by the Scoper.
 | ||||||
| 	ASTNode const* scope = nullptr; | 	ASTNode const* scope = nullptr; | ||||||
| 	/// Pointer to the contract this declaration resides in. Can be nullptr if the current scope
 | 	/// Pointer to the contract this declaration resides in. Can be nullptr if the current scope
 | ||||||
| 	/// is not part of a contract. Available only after name and type resolution step.
 | 	/// is not part of a contract. Filled by the Scoper.
 | ||||||
| 	ContractDefinition const* contract = nullptr; | 	ContractDefinition const* contract = nullptr; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ namespace solidity::frontend | |||||||
| { | { | ||||||
| 
 | 
 | ||||||
| class ASTNode; | class ASTNode; | ||||||
|  | class ScopeOpener; | ||||||
| class SourceUnit; | class SourceUnit; | ||||||
| class PragmaDirective; | class PragmaDirective; | ||||||
| class ImportDirective; | class ImportDirective; | ||||||
|  | |||||||
| @ -36,6 +36,7 @@ | |||||||
| #include <libsolidity/analysis/PostTypeChecker.h> | #include <libsolidity/analysis/PostTypeChecker.h> | ||||||
| #include <libsolidity/analysis/StaticAnalyzer.h> | #include <libsolidity/analysis/StaticAnalyzer.h> | ||||||
| #include <libsolidity/analysis/SyntaxChecker.h> | #include <libsolidity/analysis/SyntaxChecker.h> | ||||||
|  | #include <libsolidity/analysis/Scoper.h> | ||||||
| #include <libsolidity/analysis/TypeChecker.h> | #include <libsolidity/analysis/TypeChecker.h> | ||||||
| #include <libsolidity/analysis/ViewPureChecker.h> | #include <libsolidity/analysis/ViewPureChecker.h> | ||||||
| #include <libsolidity/analysis/ImmutableValidator.h> | #include <libsolidity/analysis/ImmutableValidator.h> | ||||||
| @ -297,6 +298,10 @@ bool CompilerStack::analyze() | |||||||
| 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed.")); | 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed.")); | ||||||
| 	resolveImports(); | 	resolveImports(); | ||||||
| 
 | 
 | ||||||
|  | 	for (Source const* source: m_sourceOrder) | ||||||
|  | 		if (source->ast) | ||||||
|  | 			Scoper::assignScopes(*source->ast); | ||||||
|  | 
 | ||||||
| 	bool noErrors = true; | 	bool noErrors = true; | ||||||
| 
 | 
 | ||||||
| 	try | 	try | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ | |||||||
| #include <libsolidity/parsing/Parser.h> | #include <libsolidity/parsing/Parser.h> | ||||||
| #include <libsolidity/analysis/DeclarationTypeChecker.h> | #include <libsolidity/analysis/DeclarationTypeChecker.h> | ||||||
| #include <libsolidity/analysis/NameAndTypeResolver.h> | #include <libsolidity/analysis/NameAndTypeResolver.h> | ||||||
|  | #include <libsolidity/analysis/Scoper.h> | ||||||
| #include <libsolidity/codegen/Compiler.h> | #include <libsolidity/codegen/Compiler.h> | ||||||
| #include <libsolidity/ast/AST.h> | #include <libsolidity/ast/AST.h> | ||||||
| #include <libsolidity/analysis/TypeChecker.h> | #include <libsolidity/analysis/TypeChecker.h> | ||||||
| @ -59,6 +60,7 @@ evmasm::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode) | |||||||
| 	BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(_sourceCode))); | 	BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(_sourceCode))); | ||||||
| 	BOOST_CHECK(!!sourceUnit); | 	BOOST_CHECK(!!sourceUnit); | ||||||
| 
 | 
 | ||||||
|  | 	Scoper::assignScopes(*sourceUnit); | ||||||
| 	GlobalContext globalContext; | 	GlobalContext globalContext; | ||||||
| 	NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); | 	NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); | ||||||
| 	DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion()); | 	DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion()); | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ | |||||||
| #include <liblangutil/Scanner.h> | #include <liblangutil/Scanner.h> | ||||||
| #include <libsolidity/parsing/Parser.h> | #include <libsolidity/parsing/Parser.h> | ||||||
| #include <libsolidity/analysis/NameAndTypeResolver.h> | #include <libsolidity/analysis/NameAndTypeResolver.h> | ||||||
|  | #include <libsolidity/analysis/Scoper.h> | ||||||
| #include <libsolidity/analysis/DeclarationTypeChecker.h> | #include <libsolidity/analysis/DeclarationTypeChecker.h> | ||||||
| #include <libsolidity/codegen/CompilerContext.h> | #include <libsolidity/codegen/CompilerContext.h> | ||||||
| #include <libsolidity/codegen/ExpressionCompiler.h> | #include <libsolidity/codegen/ExpressionCompiler.h> | ||||||
| @ -117,6 +118,7 @@ bytes compileFirstExpression( | |||||||
| 	ErrorList errors; | 	ErrorList errors; | ||||||
| 	ErrorReporter errorReporter(errors); | 	ErrorReporter errorReporter(errors); | ||||||
| 	GlobalContext globalContext; | 	GlobalContext globalContext; | ||||||
|  | 	Scoper::assignScopes(*sourceUnit); | ||||||
| 	NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); | 	NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); | ||||||
| 	resolver.registerDeclarations(*sourceUnit); | 	resolver.registerDeclarations(*sourceUnit); | ||||||
| 	BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed"); | 	BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed"); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user