Refactor NameAndTypeResolver and SyntaxChecker to allow other entry points.

This commit is contained in:
chriseth 2017-01-27 18:27:59 +01:00
parent d4da4ef35f
commit fc8e50f688
7 changed files with 92 additions and 67 deletions

View File

@ -132,68 +132,64 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
return !error; return !error;
} }
bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode)
{ {
bool success = true;
try try
{ {
m_currentScope = m_scopes[_contract.scope()].get(); if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(&_node))
solAssert(!!m_currentScope, "");
ReferencesResolver resolver(m_errors, *this, nullptr);
bool success = true;
for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts())
if (!resolver.resolve(*baseContract))
success = false;
m_currentScope = m_scopes[&_contract].get();
if (success)
{ {
linearizeBaseContracts(_contract); m_currentScope = m_scopes[contract->scope()].get();
vector<ContractDefinition const*> properBases( solAssert(!!m_currentScope, "");
++_contract.annotation().linearizedBaseContracts.begin(),
_contract.annotation().linearizedBaseContracts.end()
);
for (ContractDefinition const* base: properBases) for (ASTPointer<InheritanceSpecifier> const& baseContract: contract->baseContracts())
importInheritedScope(*base); if (!resolveNamesAndTypes(*baseContract, false))
success = false;
m_currentScope = m_scopes[contract].get();
if (success)
{
linearizeBaseContracts(*contract);
vector<ContractDefinition const*> properBases(
++contract->annotation().linearizedBaseContracts.begin(),
contract->annotation().linearizedBaseContracts.end()
);
for (ContractDefinition const* base: properBases)
importInheritedScope(*base);
}
// these can contain code, only resolve parameters for now
for (ASTPointer<ASTNode> const& node: contract->subNodes())
{
m_currentScope = m_scopes[contract].get();
if (!resolveNamesAndTypes(*node, false))
success = false;
}
if (!success)
return false;
if (!_resolveInsideCode)
return success;
m_currentScope = m_scopes[contract].get();
// now resolve references inside the code
for (ASTPointer<ASTNode> const& node: contract->subNodes())
{
m_currentScope = m_scopes[contract].get();
if (!resolveNamesAndTypes(*node, true))
success = false;
}
} }
else
// these can contain code, only resolve parameters for now
for (ASTPointer<ASTNode> const& node: _contract.subNodes())
{ {
m_currentScope = m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract].get(); if (m_scopes.count(&_node))
if (!resolver.resolve(*node)) m_currentScope = m_scopes[&_node].get();
success = false; return ReferencesResolver(m_errors, *this, _resolveInsideCode).resolve(_node);
} }
if (!success)
return false;
m_currentScope = m_scopes[&_contract].get();
// now resolve references inside the code
for (ModifierDefinition const* modifier: _contract.functionModifiers())
{
m_currentScope = m_scopes[modifier].get();
ReferencesResolver resolver(m_errors, *this, nullptr, true);
if (!resolver.resolve(*modifier))
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;
} }
catch (FatalError const&) catch (FatalError const&)
{ {
@ -201,7 +197,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
throw; // Something is weird here, rather throw again. throw; // Something is weird here, rather throw again.
return false; return false;
} }
return true; return success;
} }
bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)

View File

@ -48,9 +48,12 @@ public:
bool registerDeclarations(SourceUnit& _sourceUnit); bool registerDeclarations(SourceUnit& _sourceUnit);
/// Applies the effect of import directives. /// Applies the effect of import directives.
bool performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits); 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. /// @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 /// Updates the given global declaration (used for "this"). Not to be used with declarations
/// that create their own scope. /// that create their own scope.
/// @returns false in case of error. /// @returns false in case of error.
@ -77,8 +80,6 @@ public:
); );
private: private:
void reset();
/// Imports all members declared directly in the given contract (i.e. does not import inherited members) /// 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. /// into the current scope if they are not present already.
void importInheritedScope(ContractDefinition const& _base); void importInheritedScope(ContractDefinition const& _base);

View File

@ -65,6 +65,30 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
return true; 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) void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
{ {
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath()); Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
@ -161,7 +185,8 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
bool ReferencesResolver::visit(Return const& _return) bool ReferencesResolver::visit(Return const& _return)
{ {
_return.annotation().functionReturnParameters = m_returnParameters; solAssert(!m_returnParameters.empty(), "");
_return.annotation().functionReturnParameters = m_returnParameters.back();
return true; return true;
} }

View File

@ -45,12 +45,10 @@ public:
ReferencesResolver( ReferencesResolver(
ErrorList& _errors, ErrorList& _errors,
NameAndTypeResolver& _resolver, NameAndTypeResolver& _resolver,
ParameterList const* _returnParameters,
bool _resolveInsideCode = false bool _resolveInsideCode = false
): ):
m_errors(_errors), m_errors(_errors),
m_resolver(_resolver), m_resolver(_resolver),
m_returnParameters(_returnParameters),
m_resolveInsideCode(_resolveInsideCode) m_resolveInsideCode(_resolveInsideCode)
{} {}
@ -61,6 +59,10 @@ private:
virtual bool visit(Block const&) override { return m_resolveInsideCode; } virtual bool visit(Block const&) override { return m_resolveInsideCode; }
virtual bool visit(Identifier const& _identifier) override; virtual bool visit(Identifier const& _identifier) override;
virtual bool visit(ElementaryTypeName const& _typeName) 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(UserDefinedTypeName const& _typeName) override;
virtual void endVisit(FunctionTypeName const& _typeName) override; virtual void endVisit(FunctionTypeName const& _typeName) override;
virtual void endVisit(Mapping const& _typeName) override; virtual void endVisit(Mapping const& _typeName) override;
@ -83,7 +85,8 @@ private:
ErrorList& m_errors; ErrorList& m_errors;
NameAndTypeResolver& m_resolver; NameAndTypeResolver& m_resolver;
ParameterList const* m_returnParameters; /// Stack of return parameters.
std::vector<ParameterList const*> m_returnParameters;
bool const m_resolveInsideCode; bool const m_resolveInsideCode;
bool m_errorOccurred = false; bool m_errorOccurred = false;
}; };

View File

@ -26,9 +26,9 @@ using namespace dev;
using namespace dev::solidity; 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); return Error::containsOnlyWarnings(m_errors);
} }

View File

@ -39,7 +39,7 @@ public:
/// @param _errors the reference to the list of errors and warnings to add them found during type checking. /// @param _errors the reference to the list of errors and warnings to add them found during type checking.
SyntaxChecker(ErrorList& _errors): m_errors(_errors) {} SyntaxChecker(ErrorList& _errors): m_errors(_errors) {}
bool checkSyntax(SourceUnit const& _sourceUnit); bool checkSyntax(ASTNode const& _astRoot);
private: private:
/// Adds a new error to the list of errors. /// Adds a new error to the list of errors.

View File

@ -1080,7 +1080,7 @@ BOOST_AUTO_TEST_CASE(modifier_returns_value)
modifier mod(uint a) { _; return 7; } 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) BOOST_AUTO_TEST_CASE(state_variable_accessors)