Assign scopes as a separate step.

This commit is contained in:
chriseth 2020-08-06 14:46:04 +02:00
parent 767d06b297
commit 2934a1f037
10 changed files with 147 additions and 18 deletions

View File

@ -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

View File

@ -607,7 +607,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionDefinition&)
bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause) bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause)
{ {
_tryCatchClause.annotation().scope = m_currentScope; solAssert(_tryCatchClause.annotation().scope == m_currentScope, "");
enterNewSubScope(_tryCatchClause); enterNewSubScope(_tryCatchClause);
return true; return true;
} }
@ -643,7 +643,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionTypeName&)
bool DeclarationRegistrationHelper::visit(Block& _block) bool DeclarationRegistrationHelper::visit(Block& _block)
{ {
_block.annotation().scope = m_currentScope; solAssert(_block.annotation().scope == m_currentScope, "");
enterNewSubScope(_block); enterNewSubScope(_block);
return true; return true;
} }
@ -655,7 +655,7 @@ void DeclarationRegistrationHelper::endVisit(Block&)
bool DeclarationRegistrationHelper::visit(ForStatement& _for) bool DeclarationRegistrationHelper::visit(ForStatement& _for)
{ {
_for.annotation().scope = m_currentScope; solAssert(_for.annotation().scope == m_currentScope, "");
enterNewSubScope(_for); enterNewSubScope(_for);
return true; return true;
} }
@ -729,8 +729,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) if (_opensScope)
enterNewSubScope(_declaration); enterNewSubScope(_declaration);
} }

View 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();
}

View 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;
};
}

View File

@ -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(

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -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");