diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 60703f76e..2fec31fdd 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -448,12 +448,16 @@ bool VariableDeclaration::isLocalVariable() const dynamic_cast(s) || dynamic_cast(s) || dynamic_cast(s) || + dynamic_cast(s) || dynamic_cast(s); } bool VariableDeclaration::isCallableParameter() const { - if (isReturnParameter()) + // TODO Adjust for catch params. + // I think catch params should return true here. + // some of the error strings would need to be adjusted. + if (isReturnParameter() || dynamic_cast(scope())) return true; vector> const* parameters = nullptr; @@ -472,6 +476,7 @@ bool VariableDeclaration::isCallableParameter() const bool VariableDeclaration::isLocalOrReturn() const { + // TODO adjust for catch params return isReturnParameter() || (isLocalVariable() && !isCallableParameter()); } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 741262682..ce0eb5d62 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -553,7 +553,7 @@ public: }; /** - * Parameter list, used as function parameter list and return list. + * Parameter list, used as function parameter list, return list and for try and catch. * None of the parameters is allowed to contain mappings (not even recursively * inside structs). */ @@ -1174,6 +1174,76 @@ private: ASTPointer m_falseBody; ///< "else" part, optional }; +/** + * Clause of a try-catch block. Includes both the successful case and the + * unsuccessful cases. + * Names are only allowed for the unsuccessful cases. + */ +class TryCatchClause: public ASTNode, public Scopable +{ +public: + TryCatchClause( + SourceLocation const& _location, + ASTPointer const& _errorName, + ASTPointer const& _parameters, + ASTPointer const& _block + ): + ASTNode(_location), + m_errorName(_errorName), + m_parameters(_parameters), + m_block(_block) + {} + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + + ASTString const& errorName() const { return *m_errorName; } + ParameterList const* parameters() const { return m_parameters.get(); } + Block const& block() const { return *m_block; } + +private: + ASTPointer m_errorName; + ASTPointer m_parameters; + ASTPointer m_block; +}; + +/** + * Try-statement with a variable number of catch statements. + * Syntax: + * try returns (uint x, uint y) { + * // success code + * } catch Error(string memory cause) { + * // error code, reason provided + * } catch (bytes memory lowLevelData) { + * // error code, no reason provided or non-matching error signature. + * } + * + * The last statement given above can also be specified as + * } catch () { + */ +class TryStatement: public Statement +{ +public: + TryStatement( + SourceLocation const& _location, + ASTPointer const& _docString, + ASTPointer const& _externalCall, + std::vector> const& _clauses + ): + Statement(_location, _docString), + m_externalCall(_externalCall), + m_clauses(_clauses) + {} + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + + Expression const& externalCall() const { return *m_externalCall; } + std::vector> const& clauses() const { return m_clauses; } + +private: + ASTPointer m_externalCall; + std::vector> m_clauses; +}; + /** * Statement in which a break statement is legal (abstract class). */ diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 539ba85bf..807d003a2 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -218,6 +218,8 @@ enum class FunctionCallKind struct FunctionCallAnnotation: ExpressionAnnotation { FunctionCallKind kind = FunctionCallKind::Unset; + /// If true, this is the external call of a try statement. + bool tryCall = false; }; } diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index db6952694..d950a35f9 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -64,6 +64,8 @@ class Statement; class Block; class PlaceholderStatement; class IfStatement; +class TryCatchClause; +class TryStatement; class BreakableStatement; class WhileStatement; class ForStatement; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index ed5b56d71..0f2121b7e 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -499,6 +499,25 @@ bool ASTJsonConverter::visit(IfStatement const& _node) return false; } +bool ASTJsonConverter::visit(TryCatchClause const& _node) +{ + setJsonNode(_node, "TryCatchClause", { + make_pair("errorName", _node.errorName()), + make_pair("parameters", toJsonOrNull(_node.parameters())), + make_pair("block", toJson(_node.block())) + }); + return false; +} + +bool ASTJsonConverter::visit(TryStatement const& _node) +{ + setJsonNode(_node, "TryStatement", { + make_pair("externalCall", toJson(_node.externalCall())), + make_pair("clauses", toJson(_node.clauses())) + }); + return false; +} + bool ASTJsonConverter::visit(WhileStatement const& _node) { setJsonNode( @@ -647,7 +666,8 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) std::vector> attributes = { make_pair("expression", toJson(_node.expression())), make_pair("names", std::move(names)), - make_pair("arguments", toJson(_node.arguments())) + make_pair("arguments", toJson(_node.arguments())), + make_pair("tryCall", _node.annotation().tryCall) }; if (m_legacy) { diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 0c79d63d1..55235f413 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -93,6 +93,8 @@ public: bool visit(Block const& _node) override; bool visit(PlaceholderStatement const& _node) override; bool visit(IfStatement const& _node) override; + bool visit(TryCatchClause const& _node) override; + bool visit(TryStatement const& _node) override; bool visit(WhileStatement const& _node) override; bool visit(ForStatement const& _node) override; bool visit(Continue const& _node) override; diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 901b93ef8..ed328633f 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -69,6 +69,8 @@ public: virtual bool visit(Block& _node) { return visitNode(_node); } virtual bool visit(PlaceholderStatement& _node) { return visitNode(_node); } virtual bool visit(IfStatement& _node) { return visitNode(_node); } + virtual bool visit(TryCatchClause& _node) { return visitNode(_node); } + virtual bool visit(TryStatement& _node) { return visitNode(_node); } virtual bool visit(WhileStatement& _node) { return visitNode(_node); } virtual bool visit(ForStatement& _node) { return visitNode(_node); } virtual bool visit(Continue& _node) { return visitNode(_node); } @@ -117,6 +119,8 @@ public: virtual void endVisit(Block& _node) { endVisitNode(_node); } virtual void endVisit(PlaceholderStatement& _node) { endVisitNode(_node); } virtual void endVisit(IfStatement& _node) { endVisitNode(_node); } + virtual void endVisit(TryCatchClause& _node) { endVisitNode(_node); } + virtual void endVisit(TryStatement& _node) { endVisitNode(_node); } virtual void endVisit(WhileStatement& _node) { endVisitNode(_node); } virtual void endVisit(ForStatement& _node) { endVisitNode(_node); } virtual void endVisit(Continue& _node) { endVisitNode(_node); } @@ -177,6 +181,8 @@ public: virtual bool visit(Block const& _node) { return visitNode(_node); } virtual bool visit(PlaceholderStatement const& _node) { return visitNode(_node); } virtual bool visit(IfStatement const& _node) { return visitNode(_node); } + virtual bool visit(TryCatchClause const& _node) { return visitNode(_node); } + virtual bool visit(TryStatement const& _node) { return visitNode(_node); } virtual bool visit(WhileStatement const& _node) { return visitNode(_node); } virtual bool visit(ForStatement const& _node) { return visitNode(_node); } virtual bool visit(Continue const& _node) { return visitNode(_node); } @@ -225,6 +231,8 @@ public: virtual void endVisit(Block const& _node) { endVisitNode(_node); } virtual void endVisit(PlaceholderStatement const& _node) { endVisitNode(_node); } virtual void endVisit(IfStatement const& _node) { endVisitNode(_node); } + virtual void endVisit(TryCatchClause const& _node) { endVisitNode(_node); } + virtual void endVisit(TryStatement const& _node) { endVisitNode(_node); } virtual void endVisit(WhileStatement const& _node) { endVisitNode(_node); } virtual void endVisit(ForStatement const& _node) { endVisitNode(_node); } virtual void endVisit(Continue const& _node) { endVisitNode(_node); } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index fd676c1ea..01e0042f8 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -461,6 +461,48 @@ void IfStatement::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void TryCatchClause::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + if (m_parameters) + m_parameters->accept(_visitor); + m_block->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void TryCatchClause::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + if (m_parameters) + m_parameters->accept(_visitor); + m_block->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void TryStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_externalCall->accept(_visitor); + listAccept(m_clauses, _visitor); + } + _visitor.endVisit(*this); +} + +void TryStatement::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_externalCall->accept(_visitor); + listAccept(m_clauses, _visitor); + } + _visitor.endVisit(*this); +} + void WhileStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this))