mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Refactor NameAndTypeResolver and SyntaxChecker to allow other entry points.
This commit is contained in:
parent
d4da4ef35f
commit
fc8e50f688
@ -132,27 +132,28 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
|
||||
return !error;
|
||||
}
|
||||
|
||||
bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||
bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode)
|
||||
{
|
||||
bool success = true;
|
||||
try
|
||||
{
|
||||
m_currentScope = m_scopes[_contract.scope()].get();
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(&_node))
|
||||
{
|
||||
m_currentScope = m_scopes[contract->scope()].get();
|
||||
solAssert(!!m_currentScope, "");
|
||||
|
||||
ReferencesResolver resolver(m_errors, *this, nullptr);
|
||||
bool success = true;
|
||||
for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts())
|
||||
if (!resolver.resolve(*baseContract))
|
||||
for (ASTPointer<InheritanceSpecifier> const& baseContract: contract->baseContracts())
|
||||
if (!resolveNamesAndTypes(*baseContract, false))
|
||||
success = false;
|
||||
|
||||
m_currentScope = m_scopes[&_contract].get();
|
||||
m_currentScope = m_scopes[contract].get();
|
||||
|
||||
if (success)
|
||||
{
|
||||
linearizeBaseContracts(_contract);
|
||||
linearizeBaseContracts(*contract);
|
||||
vector<ContractDefinition const*> properBases(
|
||||
++_contract.annotation().linearizedBaseContracts.begin(),
|
||||
_contract.annotation().linearizedBaseContracts.end()
|
||||
++contract->annotation().linearizedBaseContracts.begin(),
|
||||
contract->annotation().linearizedBaseContracts.end()
|
||||
);
|
||||
|
||||
for (ContractDefinition const* base: properBases)
|
||||
@ -160,40 +161,35 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||
}
|
||||
|
||||
// these can contain code, only resolve parameters for now
|
||||
for (ASTPointer<ASTNode> const& node: _contract.subNodes())
|
||||
for (ASTPointer<ASTNode> const& node: contract->subNodes())
|
||||
{
|
||||
m_currentScope = m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract].get();
|
||||
if (!resolver.resolve(*node))
|
||||
m_currentScope = m_scopes[contract].get();
|
||||
if (!resolveNamesAndTypes(*node, false))
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
m_currentScope = m_scopes[&_contract].get();
|
||||
if (!_resolveInsideCode)
|
||||
return success;
|
||||
|
||||
m_currentScope = m_scopes[contract].get();
|
||||
|
||||
// now resolve references inside the code
|
||||
for (ModifierDefinition const* modifier: _contract.functionModifiers())
|
||||
for (ASTPointer<ASTNode> const& node: contract->subNodes())
|
||||
{
|
||||
m_currentScope = m_scopes[modifier].get();
|
||||
ReferencesResolver resolver(m_errors, *this, nullptr, true);
|
||||
if (!resolver.resolve(*modifier))
|
||||
m_currentScope = m_scopes[contract].get();
|
||||
if (!resolveNamesAndTypes(*node, true))
|
||||
success = false;
|
||||
}
|
||||
|
||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||
{
|
||||
m_currentScope = m_scopes[function].get();
|
||||
if (!ReferencesResolver(
|
||||
m_errors,
|
||||
*this,
|
||||
function->returnParameterList().get(),
|
||||
true
|
||||
).resolve(*function))
|
||||
success = false;
|
||||
}
|
||||
if (!success)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
if (m_scopes.count(&_node))
|
||||
m_currentScope = m_scopes[&_node].get();
|
||||
return ReferencesResolver(m_errors, *this, _resolveInsideCode).resolve(_node);
|
||||
}
|
||||
}
|
||||
catch (FatalError const&)
|
||||
{
|
||||
@ -201,7 +197,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||
throw; // Something is weird here, rather throw again.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
||||
|
@ -48,9 +48,12 @@ public:
|
||||
bool registerDeclarations(SourceUnit& _sourceUnit);
|
||||
/// Applies the effect of import directives.
|
||||
bool performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits);
|
||||
/// Resolves all names and types referenced from the given contract.
|
||||
/// Resolves all names and types referenced from the given AST Node.
|
||||
/// This is usually only called at the contract level, but with a bit of care, it can also
|
||||
/// be called at deeper levels.
|
||||
/// @param _avoidCode if false, does not descend into nodes that contain code.
|
||||
/// @returns false in case of error.
|
||||
bool resolveNamesAndTypes(ContractDefinition& _contract);
|
||||
bool resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode = true);
|
||||
/// Updates the given global declaration (used for "this"). Not to be used with declarations
|
||||
/// that create their own scope.
|
||||
/// @returns false in case of error.
|
||||
@ -77,8 +80,6 @@ public:
|
||||
);
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
/// Imports all members declared directly in the given contract (i.e. does not import inherited members)
|
||||
/// into the current scope if they are not present already.
|
||||
void importInheritedScope(ContractDefinition const& _base);
|
||||
|
@ -65,6 +65,30 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
m_returnParameters.push_back(_functionDefinition.returnParameterList().get());
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(FunctionDefinition const&)
|
||||
{
|
||||
solAssert(!m_returnParameters.empty(), "");
|
||||
m_returnParameters.pop_back();
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(ModifierDefinition const&)
|
||||
{
|
||||
m_returnParameters.push_back(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(ModifierDefinition const&)
|
||||
{
|
||||
solAssert(!m_returnParameters.empty(), "");
|
||||
m_returnParameters.pop_back();
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
||||
{
|
||||
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
||||
@ -161,7 +185,8 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
||||
|
||||
bool ReferencesResolver::visit(Return const& _return)
|
||||
{
|
||||
_return.annotation().functionReturnParameters = m_returnParameters;
|
||||
solAssert(!m_returnParameters.empty(), "");
|
||||
_return.annotation().functionReturnParameters = m_returnParameters.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -45,12 +45,10 @@ public:
|
||||
ReferencesResolver(
|
||||
ErrorList& _errors,
|
||||
NameAndTypeResolver& _resolver,
|
||||
ParameterList const* _returnParameters,
|
||||
bool _resolveInsideCode = false
|
||||
):
|
||||
m_errors(_errors),
|
||||
m_resolver(_resolver),
|
||||
m_returnParameters(_returnParameters),
|
||||
m_resolveInsideCode(_resolveInsideCode)
|
||||
{}
|
||||
|
||||
@ -61,6 +59,10 @@ private:
|
||||
virtual bool visit(Block const&) override { return m_resolveInsideCode; }
|
||||
virtual bool visit(Identifier const& _identifier) override;
|
||||
virtual bool visit(ElementaryTypeName const& _typeName) override;
|
||||
virtual bool visit(FunctionDefinition const& _functionDefinition) override;
|
||||
virtual void endVisit(FunctionDefinition const& _functionDefinition) override;
|
||||
virtual bool visit(ModifierDefinition const& _modifierDefinition) override;
|
||||
virtual void endVisit(ModifierDefinition const& _modifierDefinition) override;
|
||||
virtual void endVisit(UserDefinedTypeName const& _typeName) override;
|
||||
virtual void endVisit(FunctionTypeName const& _typeName) override;
|
||||
virtual void endVisit(Mapping const& _typeName) override;
|
||||
@ -83,7 +85,8 @@ private:
|
||||
|
||||
ErrorList& m_errors;
|
||||
NameAndTypeResolver& m_resolver;
|
||||
ParameterList const* m_returnParameters;
|
||||
/// Stack of return parameters.
|
||||
std::vector<ParameterList const*> m_returnParameters;
|
||||
bool const m_resolveInsideCode;
|
||||
bool m_errorOccurred = false;
|
||||
};
|
||||
|
@ -26,9 +26,9 @@ using namespace dev;
|
||||
using namespace dev::solidity;
|
||||
|
||||
|
||||
bool SyntaxChecker::checkSyntax(SourceUnit const& _sourceUnit)
|
||||
bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot)
|
||||
{
|
||||
_sourceUnit.accept(*this);
|
||||
_astRoot.accept(*this);
|
||||
return Error::containsOnlyWarnings(m_errors);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
/// @param _errors the reference to the list of errors and warnings to add them found during type checking.
|
||||
SyntaxChecker(ErrorList& _errors): m_errors(_errors) {}
|
||||
|
||||
bool checkSyntax(SourceUnit const& _sourceUnit);
|
||||
bool checkSyntax(ASTNode const& _astRoot);
|
||||
|
||||
private:
|
||||
/// Adds a new error to the list of errors.
|
||||
|
@ -1080,7 +1080,7 @@ BOOST_AUTO_TEST_CASE(modifier_returns_value)
|
||||
modifier mod(uint a) { _; return 7; }
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "");
|
||||
CHECK_ERROR(text, TypeError, "Return arguments not allowed.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(state_variable_accessors)
|
||||
|
Loading…
Reference in New Issue
Block a user