diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 697ffe8e3..8174d138a 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace std; @@ -33,250 +34,6 @@ namespace dev namespace solidity { -void SourceUnit::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - listAccept(m_nodes, _visitor); - _visitor.endVisit(*this); -} - -void ImportDirective::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void ContractDefinition::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - listAccept(m_definedStructs, _visitor); - listAccept(m_stateVariables, _visitor); - listAccept(m_definedFunctions, _visitor); - } - _visitor.endVisit(*this); -} - -void StructDefinition::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - listAccept(m_members, _visitor); - _visitor.endVisit(*this); -} - -void StructDefinition::checkValidityOfMembers() -{ - checkMemberTypes(); - checkRecursion(); -} - -void ParameterList::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - listAccept(m_parameters, _visitor); - _visitor.endVisit(*this); -} - -void FunctionDefinition::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_parameters->accept(_visitor); - if (m_returnParameters) - m_returnParameters->accept(_visitor); - m_body->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void VariableDeclaration::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - if (m_typeName) - m_typeName->accept(_visitor); - _visitor.endVisit(*this); -} - -void TypeName::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void ElementaryTypeName::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void UserDefinedTypeName::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void Mapping::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_keyType->accept(_visitor); - m_valueType->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void Statement::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void Block::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - listAccept(m_statements, _visitor); - _visitor.endVisit(*this); -} - -void IfStatement::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_condition->accept(_visitor); - m_trueBody->accept(_visitor); - if (m_falseBody) - m_falseBody->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void BreakableStatement::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void WhileStatement::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_condition->accept(_visitor); - m_body->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void Continue::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void Break::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void Return::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - if (m_expression) - m_expression->accept(_visitor); - _visitor.endVisit(*this); -} - -void ExpressionStatement::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - if (m_expression) - m_expression->accept(_visitor); - _visitor.endVisit(*this); -} - -void VariableDefinition::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void Assignment::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_leftHandSide->accept(_visitor); - m_rightHandSide->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void UnaryOperation::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - m_subExpression->accept(_visitor); - _visitor.endVisit(*this); -} - -void BinaryOperation::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_left->accept(_visitor); - m_right->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void FunctionCall::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_expression->accept(_visitor); - listAccept(m_arguments, _visitor); - } - _visitor.endVisit(*this); -} - -void MemberAccess::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - m_expression->accept(_visitor); - _visitor.endVisit(*this); -} - -void IndexAccess::accept(ASTVisitor& _visitor) -{ - if (_visitor.visit(*this)) - { - m_base->accept(_visitor); - m_index->accept(_visitor); - } - _visitor.endVisit(*this); -} - -void Identifier::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void Literal::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - TypeError ASTNode::createTypeError(string const& _description) const { return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); @@ -297,14 +54,14 @@ vector ContractDefinition::getInterfaceFunctions() co return exportedFunctions; } -void StructDefinition::checkMemberTypes() +void StructDefinition::checkMemberTypes() const { for (ASTPointer const& member: getMembers()) if (!member->getType()->canBeStored()) BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct.")); } -void StructDefinition::checkRecursion() +void StructDefinition::checkRecursion() const { set definitionsSeen; vector queue = {this}; @@ -319,7 +76,7 @@ void StructDefinition::checkRecursion() for (ASTPointer const& member: def->getMembers()) if (member->getType()->getCategory() == Type::Category::STRUCT) { - UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName()); + UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName()); queue.push_back(&dynamic_cast(*typeName.getReferencedDeclaration())); } } @@ -532,7 +289,7 @@ void Identifier::checkTypeRequirements() if (asserts(m_referencedDeclaration)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier not resolved.")); - VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration); + VariableDeclaration const* variable = dynamic_cast(m_referencedDeclaration); if (variable) { if (!variable->getType()) @@ -542,29 +299,29 @@ void Identifier::checkTypeRequirements() return; } //@todo can we unify these with TypeName::toType()? - StructDefinition* structDef = dynamic_cast(m_referencedDeclaration); + StructDefinition const* structDef = dynamic_cast(m_referencedDeclaration); if (structDef) { // note that we do not have a struct type here - m_type = make_shared(make_shared(*structDef)); + m_type = make_shared(make_shared(*structDef)); return; } - FunctionDefinition* functionDef = dynamic_cast(m_referencedDeclaration); + FunctionDefinition const* functionDef = dynamic_cast(m_referencedDeclaration); if (functionDef) { // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // conversion. - m_type = make_shared(*functionDef); + m_type = make_shared(*functionDef); return; } - ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration); + ContractDefinition const* contractDef = dynamic_cast(m_referencedDeclaration); if (contractDef) { - m_type = make_shared(make_shared(*contractDef)); + m_type = make_shared(make_shared(*contractDef)); return; } - MagicVariableDeclaration* magicVariable = dynamic_cast(m_referencedDeclaration); + MagicVariableDeclaration const* magicVariable = dynamic_cast(m_referencedDeclaration); if (magicVariable) { m_type = magicVariable->getType(); @@ -575,7 +332,7 @@ void Identifier::checkTypeRequirements() void ElementaryTypeNameExpression::checkTypeRequirements() { - m_type = make_shared(Type::fromElementaryTypeName(m_typeToken)); + m_type = make_shared(Type::fromElementaryTypeName(m_typeToken)); } void Literal::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 10616022b..19c4b4275 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -39,6 +39,7 @@ namespace solidity { class ASTVisitor; +class ASTConstVisitor; /** @@ -54,12 +55,19 @@ public: virtual ~ASTNode() {} virtual void accept(ASTVisitor& _visitor) = 0; + virtual void accept(ASTConstVisitor& _visitor) const = 0; template static void listAccept(std::vector>& _list, ASTVisitor& _visitor) { for (ASTPointer& element: _list) element->accept(_visitor); } + template + static void listAccept(std::vector> const& _list, ASTConstVisitor& _visitor) + { + for (ASTPointer const& element: _list) + element->accept(_visitor); + } /// Returns the source code location of this node. Location const& getLocation() const { return m_location; } @@ -89,6 +97,7 @@ public: ASTNode(_location), m_nodes(_nodes) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; std::vector> getNodes() const { return m_nodes; } @@ -108,6 +117,7 @@ public: ASTNode(_location), m_identifier(_identifier) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; ASTString const& getIdentifier() const { return *m_identifier; } @@ -122,18 +132,18 @@ class Declaration: public ASTNode { public: Declaration(Location const& _location, ASTPointer const& _name): - ASTNode(_location), m_name(_name) {} + ASTNode(_location), m_name(_name), m_scope(nullptr) {} /// @returns the declared name. ASTString const& getName() const { return *m_name; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. - Declaration* getScope() const { return m_scope; } - void setScope(Declaration* const& _scope) { m_scope = _scope; } + Declaration const* getScope() const { return m_scope; } + void setScope(Declaration const* _scope) { m_scope = _scope; } private: ASTPointer m_name; - Declaration* m_scope; + Declaration const* m_scope; }; /** @@ -146,21 +156,28 @@ class ContractDefinition: public Declaration public: ContractDefinition(Location const& _location, ASTPointer const& _name, + ASTPointer const& _documentation, std::vector> const& _definedStructs, std::vector> const& _stateVariables, std::vector> const& _definedFunctions): Declaration(_location, _name), m_definedStructs(_definedStructs), m_stateVariables(_stateVariables), - m_definedFunctions(_definedFunctions) + m_definedFunctions(_definedFunctions), + m_documentation(_documentation) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; std::vector> const& getDefinedStructs() const { return m_definedStructs; } std::vector> const& getStateVariables() const { return m_stateVariables; } std::vector> const& getDefinedFunctions() const { return m_definedFunctions; } + /// @return A shared pointer of an ASTString. + /// Can contain a nullptr in which case indicates absence of documentation + ASTPointer const& getDocumentation() const { return m_documentation; } + /// Returns the functions that make up the calling interface in the intended order. std::vector getInterfaceFunctions() const; @@ -168,6 +185,7 @@ private: std::vector> m_definedStructs; std::vector> m_stateVariables; std::vector> m_definedFunctions; + ASTPointer m_documentation; }; class StructDefinition: public Declaration @@ -178,16 +196,17 @@ public: std::vector> const& _members): Declaration(_location, _name), m_members(_members) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; std::vector> const& getMembers() const { return m_members; } /// Checks that the members do not include any recursive structs and have valid types /// (e.g. no functions). - void checkValidityOfMembers(); + void checkValidityOfMembers() const; private: - void checkMemberTypes(); - void checkRecursion(); + void checkMemberTypes() const; + void checkRecursion() const; std::vector> m_members; }; @@ -204,6 +223,7 @@ public: std::vector> const& _parameters): ASTNode(_location), m_parameters(_parameters) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; std::vector> const& getParameters() const { return m_parameters; } @@ -230,14 +250,15 @@ public: {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; bool isPublic() const { return m_isPublic; } bool isDeclaredConst() const { return m_isDeclaredConst; } std::vector> const& getParameters() const { return m_parameters->getParameters(); } - ParameterList& getParameterList() { return *m_parameters; } + ParameterList const& getParameterList() const { return *m_parameters; } std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } - Block& getBody() { return *m_body; } + Block const& getBody() const { return *m_body; } /// @return A shared pointer of an ASTString. /// Can contain a nullptr in which case indicates absence of documentation ASTPointer const& getDocumentation() const { return m_documentation; } @@ -270,15 +291,16 @@ public: ASTPointer const& _name): Declaration(_location, _name), m_typeName(_type) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; - TypeName* getTypeName() const { return m_typeName.get(); } + TypeName const* getTypeName() const { return m_typeName.get(); } /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// declared and there is no assignment to the variable that fixes the type. std::shared_ptr const& getType() const { return m_type; } void setType(std::shared_ptr const& _type) { m_type = _type; } - bool isLocalVariable() const { return !!dynamic_cast(getScope()); } + bool isLocalVariable() const { return !!dynamic_cast(getScope()); } private: ASTPointer m_typeName; ///< can be empty ("var") @@ -297,6 +319,8 @@ public: Declaration(Location(), std::make_shared(_name)), m_type(_type) {} virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } + virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError() + << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } std::shared_ptr const& getType() const { return m_type; } @@ -315,11 +339,12 @@ class TypeName: public ASTNode public: explicit TypeName(Location const& _location): ASTNode(_location) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; /// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared /// pointer until the types have been resolved using the @ref NameAndTypeResolver. /// If it returns an empty shared pointer after that, this indicates that the type was not found. - virtual std::shared_ptr toType() const = 0; + virtual std::shared_ptr toType() const = 0; }; /** @@ -335,7 +360,8 @@ public: if (asserts(Token::isElementaryTypeName(_type))) BOOST_THROW_EXCEPTION(InternalCompilerError()); } virtual void accept(ASTVisitor& _visitor) override; - virtual std::shared_ptr toType() const override { return Type::fromElementaryTypeName(m_type); } + virtual void accept(ASTConstVisitor& _visitor) const override; + virtual std::shared_ptr toType() const override { return Type::fromElementaryTypeName(m_type); } Token::Value getTypeName() const { return m_type; } @@ -350,18 +376,19 @@ class UserDefinedTypeName: public TypeName { public: UserDefinedTypeName(Location const& _location, ASTPointer const& _name): - TypeName(_location), m_name(_name) {} + TypeName(_location), m_name(_name), m_referencedDeclaration(nullptr) {} virtual void accept(ASTVisitor& _visitor) override; - virtual std::shared_ptr toType() const override { return Type::fromUserDefinedTypeName(*this); } + virtual void accept(ASTConstVisitor& _visitor) const override; + virtual std::shared_ptr toType() const override { return Type::fromUserDefinedTypeName(*this); } ASTString const& getName() const { return *m_name; } - void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } + void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; } private: ASTPointer m_name; - Declaration* m_referencedDeclaration; + Declaration const* m_referencedDeclaration; }; /** @@ -374,7 +401,8 @@ public: ASTPointer const& _valueType): TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {} virtual void accept(ASTVisitor& _visitor) override; - virtual std::shared_ptr toType() const override { return Type::fromMapping(*this); } + virtual void accept(ASTConstVisitor& _visitor) const override; + virtual std::shared_ptr toType() const override { return Type::fromMapping(*this); } ElementaryTypeName const& getKeyType() const { return *m_keyType; } TypeName const& getValueType() const { return *m_valueType; } @@ -397,7 +425,6 @@ class Statement: public ASTNode { public: explicit Statement(Location const& _location): ASTNode(_location) {} - virtual void accept(ASTVisitor& _visitor) override; /// Check all type requirements, throws exception if some requirement is not met. /// This includes checking that operators are applicable to their arguments but also that @@ -414,6 +441,7 @@ public: Block(Location const& _location, std::vector> const& _statements): Statement(_location), m_statements(_statements) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; @@ -433,12 +461,13 @@ public: Statement(_location), m_condition(_condition), m_trueBody(_trueBody), m_falseBody(_falseBody) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getCondition() const { return *m_condition; } - Statement& getTrueStatement() const { return *m_trueBody; } + Expression const& getCondition() const { return *m_condition; } + Statement const& getTrueStatement() const { return *m_trueBody; } /// @returns the "else" part of the if statement or nullptr if there is no "else" part. - Statement* getFalseStatement() const { return m_falseBody.get(); } + Statement const* getFalseStatement() const { return m_falseBody.get(); } private: ASTPointer m_condition; @@ -447,13 +476,12 @@ private: }; /** - * Statement in which a break statement is legal. + * Statement in which a break statement is legal (abstract class). */ class BreakableStatement: public Statement { public: BreakableStatement(Location const& _location): Statement(_location) {} - virtual void accept(ASTVisitor& _visitor) override; }; class WhileStatement: public BreakableStatement @@ -463,10 +491,11 @@ public: ASTPointer const& _body): BreakableStatement(_location), m_condition(_condition), m_body(_body) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getCondition() const { return *m_condition; } - Statement& getBody() const { return *m_body; } + Expression const& getCondition() const { return *m_condition; } + Statement const& getBody() const { return *m_body; } private: ASTPointer m_condition; @@ -478,6 +507,7 @@ class Continue: public Statement public: Continue(Location const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override {} }; @@ -486,6 +516,7 @@ class Break: public Statement public: Break(Location const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override {} }; @@ -493,8 +524,9 @@ class Return: public Statement { public: Return(Location const& _location, ASTPointer _expression): - Statement(_location), m_expression(_expression) {} + Statement(_location), m_expression(_expression), m_returnParameters(nullptr) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } @@ -504,7 +536,7 @@ public: BOOST_THROW_EXCEPTION(InternalCompilerError()); return *m_returnParameters; } - Expression* getExpression() const { return m_expression.get(); } + Expression const* getExpression() const { return m_expression.get(); } private: ASTPointer m_expression; ///< value to return, optional @@ -525,10 +557,11 @@ public: ASTPointer _value): Statement(_location), m_variable(_variable), m_value(_value) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; VariableDeclaration const& getDeclaration() const { return *m_variable; } - Expression* getExpression() const { return m_value.get(); } + Expression const* getExpression() const { return m_value.get(); } private: ASTPointer m_variable; @@ -544,9 +577,10 @@ public: ExpressionStatement(Location const& _location, ASTPointer _expression): Statement(_location), m_expression(_expression) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getExpression() const { return *m_expression; } + Expression const& getExpression() const { return *m_expression; } private: ASTPointer m_expression; @@ -608,11 +642,12 @@ public: if (asserts(Token::isAssignmentOp(_assignmentOperator))) BOOST_THROW_EXCEPTION(InternalCompilerError()); } virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getLeftHandSide() const { return *m_leftHandSide; } + Expression const& getLeftHandSide() const { return *m_leftHandSide; } Token::Value getAssignmentOperator() const { return m_assigmentOperator; } - Expression& getRightHandSide() const { return *m_rightHandSide; } + Expression const& getRightHandSide() const { return *m_rightHandSide; } private: ASTPointer m_leftHandSide; @@ -635,11 +670,12 @@ public: if (asserts(Token::isUnaryOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError()); } virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; Token::Value getOperator() const { return m_operator; } bool isPrefixOperation() const { return m_isPrefix; } - Expression& getSubExpression() const { return *m_subExpression; } + Expression const& getSubExpression() const { return *m_subExpression; } private: Token::Value m_operator; @@ -661,10 +697,11 @@ public: if (asserts(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError()); } virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getLeftExpression() const { return *m_left; } - Expression& getRightExpression() const { return *m_right; } + Expression const& getLeftExpression() const { return *m_left; } + Expression const& getRightExpression() const { return *m_right; } Token::Value getOperator() const { return m_operator; } Type const& getCommonType() const { return *m_commonType; } @@ -688,10 +725,11 @@ public: std::vector> const& _arguments): Expression(_location), m_expression(_expression), m_arguments(_arguments) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getExpression() const { return *m_expression; } - std::vector> const& getArguments() const { return m_arguments; } + Expression const& getExpression() const { return *m_expression; } + std::vector> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; } /// Returns true if this is not an actual function call, but an explicit type conversion /// or constructor call. @@ -712,7 +750,8 @@ public: ASTPointer const& _memberName): Expression(_location), m_expression(_expression), m_memberName(_memberName) {} virtual void accept(ASTVisitor& _visitor) override; - Expression& getExpression() const { return *m_expression; } + virtual void accept(ASTConstVisitor& _visitor) const override; + Expression const& getExpression() const { return *m_expression; } ASTString const& getMemberName() const { return *m_memberName; } virtual void checkTypeRequirements() override; @@ -731,10 +770,11 @@ public: ASTPointer const& _index): Expression(_location), m_base(_base), m_index(_index) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - Expression& getBaseExpression() const { return *m_base; } - Expression& getIndexExpression() const { return *m_index; } + Expression const& getBaseExpression() const { return *m_base; } + Expression const& getIndexExpression() const { return *m_index; } private: ASTPointer m_base; @@ -758,20 +798,21 @@ class Identifier: public PrimaryExpression { public: Identifier(Location const& _location, ASTPointer const& _name): - PrimaryExpression(_location), m_name(_name) {} + PrimaryExpression(_location), m_name(_name), m_referencedDeclaration(nullptr) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; ASTString const& getName() const { return *m_name; } - void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } - Declaration* getReferencedDeclaration() { return m_referencedDeclaration; } + void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } + Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; } private: ASTPointer m_name; /// Declaration the name refers to. - Declaration* m_referencedDeclaration; + Declaration const* m_referencedDeclaration; }; /** @@ -788,6 +829,7 @@ public: if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError()); } virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; Token::Value getTypeToken() const { return m_typeToken; } @@ -805,6 +847,7 @@ public: Literal(Location const& _location, Token::Value _token, ASTPointer const& _value): PrimaryExpression(_location), m_token(_token), m_value(_value) {} virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; Token::Value getToken() const { return m_token; } diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 3d09fd9af..eddb51340 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -30,7 +30,7 @@ namespace dev namespace solidity { -ASTPrinter::ASTPrinter(ASTNode& _ast, string const& _source): +ASTPrinter::ASTPrinter(ASTNode const& _ast, string const& _source): m_indentation(0), m_source(_source), m_ast(&_ast) { } @@ -43,35 +43,35 @@ void ASTPrinter::print(ostream& _stream) } -bool ASTPrinter::visit(ImportDirective& _node) +bool ASTPrinter::visit(ImportDirective const& _node) { writeLine("ImportDirective \"" + _node.getIdentifier() + "\""); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(ContractDefinition& _node) +bool ASTPrinter::visit(ContractDefinition const& _node) { writeLine("ContractDefinition \"" + _node.getName() + "\""); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(StructDefinition& _node) +bool ASTPrinter::visit(StructDefinition const& _node) { writeLine("StructDefinition \"" + _node.getName() + "\""); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(ParameterList& _node) +bool ASTPrinter::visit(ParameterList const& _node) { writeLine("ParameterList"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(FunctionDefinition& _node) +bool ASTPrinter::visit(FunctionDefinition const& _node) { writeLine("FunctionDefinition \"" + _node.getName() + "\"" + (_node.isPublic() ? " - public" : "") + @@ -80,112 +80,112 @@ bool ASTPrinter::visit(FunctionDefinition& _node) return goDeeper(); } -bool ASTPrinter::visit(VariableDeclaration& _node) +bool ASTPrinter::visit(VariableDeclaration const& _node) { writeLine("VariableDeclaration \"" + _node.getName() + "\""); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(TypeName& _node) +bool ASTPrinter::visit(TypeName const& _node) { writeLine("TypeName"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(ElementaryTypeName& _node) +bool ASTPrinter::visit(ElementaryTypeName const& _node) { writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(UserDefinedTypeName& _node) +bool ASTPrinter::visit(UserDefinedTypeName const& _node) { writeLine("UserDefinedTypeName \"" + _node.getName() + "\""); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Mapping& _node) +bool ASTPrinter::visit(Mapping const& _node) { writeLine("Mapping"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Statement& _node) +bool ASTPrinter::visit(Statement const& _node) { writeLine("Statement"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Block& _node) +bool ASTPrinter::visit(Block const& _node) { writeLine("Block"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(IfStatement& _node) +bool ASTPrinter::visit(IfStatement const& _node) { writeLine("IfStatement"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(BreakableStatement& _node) +bool ASTPrinter::visit(BreakableStatement const& _node) { writeLine("BreakableStatement"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(WhileStatement& _node) +bool ASTPrinter::visit(WhileStatement const& _node) { writeLine("WhileStatement"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Continue& _node) +bool ASTPrinter::visit(Continue const& _node) { writeLine("Continue"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Break& _node) +bool ASTPrinter::visit(Break const& _node) { writeLine("Break"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Return& _node) +bool ASTPrinter::visit(Return const& _node) { writeLine("Return"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(VariableDefinition& _node) +bool ASTPrinter::visit(VariableDefinition const& _node) { writeLine("VariableDefinition"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(ExpressionStatement& _node) +bool ASTPrinter::visit(ExpressionStatement const& _node) { writeLine("ExpressionStatement"); printSourcePart(_node); return goDeeper(); } -bool ASTPrinter::visit(Expression& _node) +bool ASTPrinter::visit(Expression const& _node) { writeLine("Expression"); printType(_node); @@ -193,7 +193,7 @@ bool ASTPrinter::visit(Expression& _node) return goDeeper(); } -bool ASTPrinter::visit(Assignment& _node) +bool ASTPrinter::visit(Assignment const& _node) { writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); printType(_node); @@ -201,7 +201,7 @@ bool ASTPrinter::visit(Assignment& _node) return goDeeper(); } -bool ASTPrinter::visit(UnaryOperation& _node) +bool ASTPrinter::visit(UnaryOperation const& _node) { writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + ") " + Token::toString(_node.getOperator())); @@ -210,7 +210,7 @@ bool ASTPrinter::visit(UnaryOperation& _node) return goDeeper(); } -bool ASTPrinter::visit(BinaryOperation& _node) +bool ASTPrinter::visit(BinaryOperation const& _node) { writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); printType(_node); @@ -218,7 +218,7 @@ bool ASTPrinter::visit(BinaryOperation& _node) return goDeeper(); } -bool ASTPrinter::visit(FunctionCall& _node) +bool ASTPrinter::visit(FunctionCall const& _node) { writeLine("FunctionCall"); printType(_node); @@ -226,7 +226,7 @@ bool ASTPrinter::visit(FunctionCall& _node) return goDeeper(); } -bool ASTPrinter::visit(MemberAccess& _node) +bool ASTPrinter::visit(MemberAccess const& _node) { writeLine("MemberAccess to member " + _node.getMemberName()); printType(_node); @@ -234,7 +234,7 @@ bool ASTPrinter::visit(MemberAccess& _node) return goDeeper(); } -bool ASTPrinter::visit(IndexAccess& _node) +bool ASTPrinter::visit(IndexAccess const& _node) { writeLine("IndexAccess"); printType(_node); @@ -242,7 +242,7 @@ bool ASTPrinter::visit(IndexAccess& _node) return goDeeper(); } -bool ASTPrinter::visit(PrimaryExpression& _node) +bool ASTPrinter::visit(PrimaryExpression const& _node) { writeLine("PrimaryExpression"); printType(_node); @@ -250,7 +250,7 @@ bool ASTPrinter::visit(PrimaryExpression& _node) return goDeeper(); } -bool ASTPrinter::visit(Identifier& _node) +bool ASTPrinter::visit(Identifier const& _node) { writeLine(string("Identifier ") + _node.getName()); printType(_node); @@ -258,7 +258,7 @@ bool ASTPrinter::visit(Identifier& _node) return goDeeper(); } -bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) +bool ASTPrinter::visit(ElementaryTypeNameExpression const& _node) { writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); printType(_node); @@ -266,7 +266,7 @@ bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) return goDeeper(); } -bool ASTPrinter::visit(Literal& _node) +bool ASTPrinter::visit(Literal const& _node) { char const* tokenString = Token::toString(_node.getToken()); if (!tokenString) @@ -277,157 +277,157 @@ bool ASTPrinter::visit(Literal& _node) return goDeeper(); } -void ASTPrinter::endVisit(ImportDirective&) +void ASTPrinter::endVisit(ImportDirective const&) { m_indentation--; } -void ASTPrinter::endVisit(ContractDefinition&) +void ASTPrinter::endVisit(ContractDefinition const&) { m_indentation--; } -void ASTPrinter::endVisit(StructDefinition&) +void ASTPrinter::endVisit(StructDefinition const&) { m_indentation--; } -void ASTPrinter::endVisit(ParameterList&) +void ASTPrinter::endVisit(ParameterList const&) { m_indentation--; } -void ASTPrinter::endVisit(FunctionDefinition&) +void ASTPrinter::endVisit(FunctionDefinition const&) { m_indentation--; } -void ASTPrinter::endVisit(VariableDeclaration&) +void ASTPrinter::endVisit(VariableDeclaration const&) { m_indentation--; } -void ASTPrinter::endVisit(TypeName&) +void ASTPrinter::endVisit(TypeName const&) { m_indentation--; } -void ASTPrinter::endVisit(ElementaryTypeName&) +void ASTPrinter::endVisit(ElementaryTypeName const&) { m_indentation--; } -void ASTPrinter::endVisit(UserDefinedTypeName&) +void ASTPrinter::endVisit(UserDefinedTypeName const&) { m_indentation--; } -void ASTPrinter::endVisit(Mapping&) +void ASTPrinter::endVisit(Mapping const&) { m_indentation--; } -void ASTPrinter::endVisit(Statement&) +void ASTPrinter::endVisit(Statement const&) { m_indentation--; } -void ASTPrinter::endVisit(Block&) +void ASTPrinter::endVisit(Block const&) { m_indentation--; } -void ASTPrinter::endVisit(IfStatement&) +void ASTPrinter::endVisit(IfStatement const&) { m_indentation--; } -void ASTPrinter::endVisit(BreakableStatement&) +void ASTPrinter::endVisit(BreakableStatement const&) { m_indentation--; } -void ASTPrinter::endVisit(WhileStatement&) +void ASTPrinter::endVisit(WhileStatement const&) { m_indentation--; } -void ASTPrinter::endVisit(Continue&) +void ASTPrinter::endVisit(Continue const&) { m_indentation--; } -void ASTPrinter::endVisit(Break&) +void ASTPrinter::endVisit(Break const&) { m_indentation--; } -void ASTPrinter::endVisit(Return&) +void ASTPrinter::endVisit(Return const&) { m_indentation--; } -void ASTPrinter::endVisit(VariableDefinition&) +void ASTPrinter::endVisit(VariableDefinition const&) { m_indentation--; } -void ASTPrinter::endVisit(ExpressionStatement&) +void ASTPrinter::endVisit(ExpressionStatement const&) { m_indentation--; } -void ASTPrinter::endVisit(Expression&) +void ASTPrinter::endVisit(Expression const&) { m_indentation--; } -void ASTPrinter::endVisit(Assignment&) +void ASTPrinter::endVisit(Assignment const&) { m_indentation--; } -void ASTPrinter::endVisit(UnaryOperation&) +void ASTPrinter::endVisit(UnaryOperation const&) { m_indentation--; } -void ASTPrinter::endVisit(BinaryOperation&) +void ASTPrinter::endVisit(BinaryOperation const&) { m_indentation--; } -void ASTPrinter::endVisit(FunctionCall&) +void ASTPrinter::endVisit(FunctionCall const&) { m_indentation--; } -void ASTPrinter::endVisit(MemberAccess&) +void ASTPrinter::endVisit(MemberAccess const&) { m_indentation--; } -void ASTPrinter::endVisit(IndexAccess&) +void ASTPrinter::endVisit(IndexAccess const&) { m_indentation--; } -void ASTPrinter::endVisit(PrimaryExpression&) +void ASTPrinter::endVisit(PrimaryExpression const&) { m_indentation--; } -void ASTPrinter::endVisit(Identifier&) +void ASTPrinter::endVisit(Identifier const&) { m_indentation--; } -void ASTPrinter::endVisit(ElementaryTypeNameExpression&) +void ASTPrinter::endVisit(ElementaryTypeNameExpression const&) { m_indentation--; } -void ASTPrinter::endVisit(Literal&) +void ASTPrinter::endVisit(Literal const&) { m_indentation--; } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 1a18fc4a1..5a9187154 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -33,78 +33,78 @@ namespace solidity /** * Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes. */ -class ASTPrinter: public ASTVisitor +class ASTPrinter: public ASTConstVisitor { public: /// Create a printer for the given abstract syntax tree. If the source is specified, /// the corresponding parts of the source are printed with each node. - ASTPrinter(ASTNode& _ast, std::string const& _source = std::string()); + ASTPrinter(ASTNode const& _ast, std::string const& _source = std::string()); /// Output the string representation of the AST to _stream. void print(std::ostream& _stream); - bool visit(ImportDirective& _node) override; - bool visit(ContractDefinition& _node) override; - bool visit(StructDefinition& _node) override; - bool visit(ParameterList& _node) override; - bool visit(FunctionDefinition& _node) override; - bool visit(VariableDeclaration& _node) override; - bool visit(TypeName& _node) override; - bool visit(ElementaryTypeName& _node) override; - bool visit(UserDefinedTypeName& _node) override; - bool visit(Mapping& _node) override; - bool visit(Statement& _node) override; - bool visit(Block& _node) override; - bool visit(IfStatement& _node) override; - bool visit(BreakableStatement& _node) override; - bool visit(WhileStatement& _node) override; - bool visit(Continue& _node) override; - bool visit(Break& _node) override; - bool visit(Return& _node) override; - bool visit(VariableDefinition& _node) override; - bool visit(ExpressionStatement& _node) override; - bool visit(Expression& _node) override; - bool visit(Assignment& _node) override; - bool visit(UnaryOperation& _node) override; - bool visit(BinaryOperation& _node) override; - bool visit(FunctionCall& _node) override; - bool visit(MemberAccess& _node) override; - bool visit(IndexAccess& _node) override; - bool visit(PrimaryExpression& _node) override; - bool visit(Identifier& _node) override; - bool visit(ElementaryTypeNameExpression& _node) override; - bool visit(Literal& _node) override; + bool visit(ImportDirective const& _node) override; + bool visit(ContractDefinition const& _node) override; + bool visit(StructDefinition const& _node) override; + bool visit(ParameterList const& _node) override; + bool visit(FunctionDefinition const& _node) override; + bool visit(VariableDeclaration const& _node) override; + bool visit(TypeName const& _node) override; + bool visit(ElementaryTypeName const& _node) override; + bool visit(UserDefinedTypeName const& _node) override; + bool visit(Mapping const& _node) override; + bool visit(Statement const& _node) override; + bool visit(Block const& _node) override; + bool visit(IfStatement const& _node) override; + bool visit(BreakableStatement const& _node) override; + bool visit(WhileStatement const& _node) override; + bool visit(Continue const& _node) override; + bool visit(Break const& _node) override; + bool visit(Return const& _node) override; + bool visit(VariableDefinition const& _node) override; + bool visit(ExpressionStatement const& _node) override; + bool visit(Expression const& _node) override; + bool visit(Assignment const& _node) override; + bool visit(UnaryOperation const& _node) override; + bool visit(BinaryOperation const& _node) override; + bool visit(FunctionCall const& _node) override; + bool visit(MemberAccess const& _node) override; + bool visit(IndexAccess const& _node) override; + bool visit(PrimaryExpression const& _node) override; + bool visit(Identifier const& _node) override; + bool visit(ElementaryTypeNameExpression const& _node) override; + bool visit(Literal const& _node) override; - void endVisit(ImportDirective&) override; - void endVisit(ContractDefinition&) override; - void endVisit(StructDefinition&) override; - void endVisit(ParameterList&) override; - void endVisit(FunctionDefinition&) override; - void endVisit(VariableDeclaration&) override; - void endVisit(TypeName&) override; - void endVisit(ElementaryTypeName&) override; - void endVisit(UserDefinedTypeName&) override; - void endVisit(Mapping&) override; - void endVisit(Statement&) override; - void endVisit(Block&) override; - void endVisit(IfStatement&) override; - void endVisit(BreakableStatement&) override; - void endVisit(WhileStatement&) override; - void endVisit(Continue&) override; - void endVisit(Break&) override; - void endVisit(Return&) override; - void endVisit(VariableDefinition&) override; - void endVisit(ExpressionStatement&) override; - void endVisit(Expression&) override; - void endVisit(Assignment&) override; - void endVisit(UnaryOperation&) override; - void endVisit(BinaryOperation&) override; - void endVisit(FunctionCall&) override; - void endVisit(MemberAccess&) override; - void endVisit(IndexAccess&) override; - void endVisit(PrimaryExpression&) override; - void endVisit(Identifier&) override; - void endVisit(ElementaryTypeNameExpression&) override; - void endVisit(Literal&) override; + void endVisit(ImportDirective const&) override; + void endVisit(ContractDefinition const&) override; + void endVisit(StructDefinition const&) override; + void endVisit(ParameterList const&) override; + void endVisit(FunctionDefinition const&) override; + void endVisit(VariableDeclaration const&) override; + void endVisit(TypeName const&) override; + void endVisit(ElementaryTypeName const&) override; + void endVisit(UserDefinedTypeName const&) override; + void endVisit(Mapping const&) override; + void endVisit(Statement const&) override; + void endVisit(Block const&) override; + void endVisit(IfStatement const&) override; + void endVisit(BreakableStatement const&) override; + void endVisit(WhileStatement const&) override; + void endVisit(Continue const&) override; + void endVisit(Break const&) override; + void endVisit(Return const&) override; + void endVisit(VariableDefinition const&) override; + void endVisit(ExpressionStatement const&) override; + void endVisit(Expression const&) override; + void endVisit(Assignment const&) override; + void endVisit(UnaryOperation const&) override; + void endVisit(BinaryOperation const&) override; + void endVisit(FunctionCall const&) override; + void endVisit(MemberAccess const&) override; + void endVisit(IndexAccess const&) override; + void endVisit(PrimaryExpression const&) override; + void endVisit(Identifier const&) override; + void endVisit(ElementaryTypeNameExpression const&) override; + void endVisit(Literal const&) override; private: void printSourcePart(ASTNode const& _node); @@ -115,7 +115,7 @@ private: int m_indentation; std::string m_source; - ASTNode* m_ast; + ASTNode const* m_ast; std::ostream* m_ostream; }; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index bf1ccc410..4e1a49458 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -110,5 +110,77 @@ public: virtual void endVisit(Literal&) { } }; +class ASTConstVisitor +{ +public: + virtual bool visit(ASTNode const&) { return true; } + virtual bool visit(SourceUnit const&) { return true; } + virtual bool visit(ImportDirective const&) { return true; } + virtual bool visit(ContractDefinition const&) { return true; } + virtual bool visit(StructDefinition const&) { return true; } + virtual bool visit(ParameterList const&) { return true; } + virtual bool visit(FunctionDefinition const&) { return true; } + virtual bool visit(VariableDeclaration const&) { return true; } + virtual bool visit(TypeName const&) { return true; } + virtual bool visit(ElementaryTypeName const&) { return true; } + virtual bool visit(UserDefinedTypeName const&) { return true; } + virtual bool visit(Mapping const&) { return true; } + virtual bool visit(Statement const&) { return true; } + virtual bool visit(Block const&) { return true; } + virtual bool visit(IfStatement const&) { return true; } + virtual bool visit(BreakableStatement const&) { return true; } + virtual bool visit(WhileStatement const&) { return true; } + virtual bool visit(Continue const&) { return true; } + virtual bool visit(Break const&) { return true; } + virtual bool visit(Return const&) { return true; } + virtual bool visit(VariableDefinition const&) { return true; } + virtual bool visit(ExpressionStatement const&) { return true; } + virtual bool visit(Expression const&) { return true; } + virtual bool visit(Assignment const&) { return true; } + virtual bool visit(UnaryOperation const&) { return true; } + virtual bool visit(BinaryOperation const&) { return true; } + virtual bool visit(FunctionCall const&) { return true; } + virtual bool visit(MemberAccess const&) { return true; } + virtual bool visit(IndexAccess const&) { return true; } + virtual bool visit(PrimaryExpression const&) { return true; } + virtual bool visit(Identifier const&) { return true; } + virtual bool visit(ElementaryTypeNameExpression const&) { return true; } + virtual bool visit(Literal const&) { return true; } + + virtual void endVisit(ASTNode const&) { } + virtual void endVisit(SourceUnit const&) { } + virtual void endVisit(ImportDirective const&) { } + virtual void endVisit(ContractDefinition const&) { } + virtual void endVisit(StructDefinition const&) { } + virtual void endVisit(ParameterList const&) { } + virtual void endVisit(FunctionDefinition const&) { } + virtual void endVisit(VariableDeclaration const&) { } + virtual void endVisit(TypeName const&) { } + virtual void endVisit(ElementaryTypeName const&) { } + virtual void endVisit(UserDefinedTypeName const&) { } + virtual void endVisit(Mapping const&) { } + virtual void endVisit(Statement const&) { } + virtual void endVisit(Block const&) { } + virtual void endVisit(IfStatement const&) { } + virtual void endVisit(BreakableStatement const&) { } + virtual void endVisit(WhileStatement const&) { } + virtual void endVisit(Continue const&) { } + virtual void endVisit(Break const&) { } + virtual void endVisit(Return const&) { } + virtual void endVisit(VariableDefinition const&) { } + virtual void endVisit(ExpressionStatement const&) { } + virtual void endVisit(Expression const&) { } + virtual void endVisit(Assignment const&) { } + virtual void endVisit(UnaryOperation const&) { } + virtual void endVisit(BinaryOperation const&) { } + virtual void endVisit(FunctionCall const&) { } + virtual void endVisit(MemberAccess const&) { } + virtual void endVisit(IndexAccess const&) { } + virtual void endVisit(PrimaryExpression const&) { } + virtual void endVisit(Identifier const&) { } + virtual void endVisit(ElementaryTypeNameExpression const&) { } + virtual void endVisit(Literal const&) { } +}; + } } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h new file mode 100644 index 000000000..173273c6d --- /dev/null +++ b/libsolidity/AST_accept.h @@ -0,0 +1,493 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Implementation of the accept functions of AST nodes, included by AST.cpp to not clutter that + * file with these mechanical implementations. + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace solidity +{ + +void SourceUnit::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + listAccept(m_nodes, _visitor); + _visitor.endVisit(*this); +} + +void SourceUnit::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + listAccept(m_nodes, _visitor); + _visitor.endVisit(*this); +} + +void ImportDirective::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ImportDirective::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ContractDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + listAccept(m_definedStructs, _visitor); + listAccept(m_stateVariables, _visitor); + listAccept(m_definedFunctions, _visitor); + } + _visitor.endVisit(*this); +} + +void ContractDefinition::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + listAccept(m_definedStructs, _visitor); + listAccept(m_stateVariables, _visitor); + listAccept(m_definedFunctions, _visitor); + } + _visitor.endVisit(*this); +} + +void StructDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + listAccept(m_members, _visitor); + _visitor.endVisit(*this); +} + +void StructDefinition::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + listAccept(m_members, _visitor); + _visitor.endVisit(*this); +} + +void StructDefinition::checkValidityOfMembers() const +{ + checkMemberTypes(); + checkRecursion(); +} + +void ParameterList::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + listAccept(m_parameters, _visitor); + _visitor.endVisit(*this); +} + +void ParameterList::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + listAccept(m_parameters, _visitor); + _visitor.endVisit(*this); +} + +void FunctionDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_parameters->accept(_visitor); + if (m_returnParameters) + m_returnParameters->accept(_visitor); + m_body->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void FunctionDefinition::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_parameters->accept(_visitor); + if (m_returnParameters) + m_returnParameters->accept(_visitor); + m_body->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void VariableDeclaration::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + if (m_typeName) + m_typeName->accept(_visitor); + _visitor.endVisit(*this); +} + +void VariableDeclaration::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + if (m_typeName) + m_typeName->accept(_visitor); + _visitor.endVisit(*this); +} + +void TypeName::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void TypeName::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ElementaryTypeName::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ElementaryTypeName::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void UserDefinedTypeName::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Mapping::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_keyType->accept(_visitor); + m_valueType->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Mapping::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_keyType->accept(_visitor); + m_valueType->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Block::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + listAccept(m_statements, _visitor); + _visitor.endVisit(*this); +} + +void Block::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + listAccept(m_statements, _visitor); + _visitor.endVisit(*this); +} + +void IfStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_condition->accept(_visitor); + m_trueBody->accept(_visitor); + if (m_falseBody) + m_falseBody->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void IfStatement::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_condition->accept(_visitor); + m_trueBody->accept(_visitor); + if (m_falseBody) + m_falseBody->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void WhileStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_condition->accept(_visitor); + m_body->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void WhileStatement::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_condition->accept(_visitor); + m_body->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Continue::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Continue::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Break::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Break::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Return::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + if (m_expression) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + +void Return::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + if (m_expression) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + +void ExpressionStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + if (m_expression) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + +void ExpressionStatement::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + if (m_expression) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + +void VariableDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_variable->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void VariableDefinition::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_variable->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Assignment::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_leftHandSide->accept(_visitor); + m_rightHandSide->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Assignment::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_leftHandSide->accept(_visitor); + m_rightHandSide->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void UnaryOperation::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + m_subExpression->accept(_visitor); + _visitor.endVisit(*this); +} + +void UnaryOperation::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + m_subExpression->accept(_visitor); + _visitor.endVisit(*this); +} + +void BinaryOperation::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_left->accept(_visitor); + m_right->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void BinaryOperation::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_left->accept(_visitor); + m_right->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void FunctionCall::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_expression->accept(_visitor); + listAccept(m_arguments, _visitor); + } + _visitor.endVisit(*this); +} + +void FunctionCall::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_expression->accept(_visitor); + listAccept(m_arguments, _visitor); + } + _visitor.endVisit(*this); +} + +void MemberAccess::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + +void MemberAccess::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + m_expression->accept(_visitor); + _visitor.endVisit(*this); +} + +void IndexAccess::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_base->accept(_visitor); + m_index->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void IndexAccess::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_base->accept(_visitor); + m_index->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Identifier::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Identifier::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ElementaryTypeNameExpression::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Literal::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Literal::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +} +} diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index a8a074034..b094af194 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -33,7 +33,7 @@ using namespace std; namespace dev { namespace solidity { -void Compiler::compileContract(ContractDefinition& _contract, vector const& _magicGlobals) +void Compiler::compileContract(ContractDefinition const& _contract, vector const& _magicGlobals) { m_context = CompilerContext(); // clear it just in case @@ -182,7 +182,7 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) m_context.addStateVariable(*variable); } -bool Compiler::visit(FunctionDefinition& _function) +bool Compiler::visit(FunctionDefinition const& _function) { //@todo to simplify this, the calling convention could by changed such that // caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn] @@ -244,7 +244,7 @@ bool Compiler::visit(FunctionDefinition& _function) return false; } -bool Compiler::visit(IfStatement& _ifStatement) +bool Compiler::visit(IfStatement const& _ifStatement) { ExpressionCompiler::compileExpression(m_context, _ifStatement.getCondition()); eth::AssemblyItem trueTag = m_context.appendConditionalJump(); @@ -257,7 +257,7 @@ bool Compiler::visit(IfStatement& _ifStatement) return false; } -bool Compiler::visit(WhileStatement& _whileStatement) +bool Compiler::visit(WhileStatement const& _whileStatement) { eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); @@ -279,24 +279,24 @@ bool Compiler::visit(WhileStatement& _whileStatement) return false; } -bool Compiler::visit(Continue&) +bool Compiler::visit(Continue const&) { if (!m_continueTags.empty()) m_context.appendJumpTo(m_continueTags.back()); return false; } -bool Compiler::visit(Break&) +bool Compiler::visit(Break const&) { if (!m_breakTags.empty()) m_context.appendJumpTo(m_breakTags.back()); return false; } -bool Compiler::visit(Return& _return) +bool Compiler::visit(Return const& _return) { //@todo modifications are needed to make this work with functions returning multiple values - if (Expression* expression = _return.getExpression()) + if (Expression const* expression = _return.getExpression()) { ExpressionCompiler::compileExpression(m_context, *expression); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); @@ -308,9 +308,9 @@ bool Compiler::visit(Return& _return) return false; } -bool Compiler::visit(VariableDefinition& _variableDefinition) +bool Compiler::visit(VariableDefinition const& _variableDefinition) { - if (Expression* expression = _variableDefinition.getExpression()) + if (Expression const* expression = _variableDefinition.getExpression()) { ExpressionCompiler::compileExpression(m_context, *expression); ExpressionCompiler::appendTypeConversion(m_context, @@ -321,9 +321,9 @@ bool Compiler::visit(VariableDefinition& _variableDefinition) return false; } -bool Compiler::visit(ExpressionStatement& _expressionStatement) +bool Compiler::visit(ExpressionStatement const& _expressionStatement) { - Expression& expression = _expressionStatement.getExpression(); + Expression const& expression = _expressionStatement.getExpression(); ExpressionCompiler::compileExpression(m_context, expression); CompilerUtils(m_context).popStackElement(*expression.getType()); return false; diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 70e6c44f2..4b8f02c5d 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -27,12 +27,12 @@ namespace dev { namespace solidity { -class Compiler: private ASTVisitor +class Compiler: private ASTConstVisitor { public: Compiler(): m_returnTag(m_context.newTag()) {} - void compileContract(ContractDefinition& _contract, std::vector const& _magicGlobals); + void compileContract(ContractDefinition const& _contract, std::vector const& _magicGlobals); bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); } void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } @@ -48,14 +48,14 @@ private: void registerStateVariables(ContractDefinition const& _contract); - virtual bool visit(FunctionDefinition& _function) override; - virtual bool visit(IfStatement& _ifStatement) override; - virtual bool visit(WhileStatement& _whileStatement) override; - virtual bool visit(Continue& _continue) override; - virtual bool visit(Break& _break) override; - virtual bool visit(Return& _return) override; - virtual bool visit(VariableDefinition& _variableDefinition) override; - virtual bool visit(ExpressionStatement& _expressionStatement) override; + virtual bool visit(FunctionDefinition const& _function) override; + virtual bool visit(IfStatement const& _ifStatement) override; + virtual bool visit(WhileStatement const& _whileStatement) override; + virtual bool visit(Continue const& _continue) override; + virtual bool visit(Break const& _break) override; + virtual bool visit(Return const& _return) override; + virtual bool visit(VariableDefinition const& _variableDefinition) override; + virtual bool visit(ExpressionStatement const& _expressionStatement) override; CompilerContext m_context; diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 41ae56036..d46754856 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -82,7 +82,7 @@ void CompilerStack::parse(string const& _sourceCode) parse(); } -vector CompilerStack::getContractNames() +vector CompilerStack::getContractNames() const { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); @@ -116,29 +116,29 @@ bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize) return getBytecode(); } -bytes const& CompilerStack::getBytecode(string const& _contractName) +bytes const& CompilerStack::getBytecode(string const& _contractName) const { return getContract(_contractName).bytecode; } -void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) +void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) const { getContract(_contractName).compiler->streamAssembly(_outStream); } -string const& CompilerStack::getInterface(std::string const& _contractName) +string const& CompilerStack::getInterface(string const& _contractName) const { return getJsonDocumentation(_contractName, DocumentationType::ABI_INTERFACE); } -std::string const& CompilerStack::getJsonDocumentation(std::string const& _contractName, DocumentationType _type) +string const& CompilerStack::getJsonDocumentation(string const& _contractName, DocumentationType _type) const { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - Contract& contract = getContract(_contractName); + Contract const& contract = getContract(_contractName); - std::unique_ptr* doc; + std::unique_ptr* doc; switch (_type) { case DocumentationType::NATSPEC_USER: @@ -158,12 +158,12 @@ std::string const& CompilerStack::getJsonDocumentation(std::string const& _contr return *(*doc); } -Scanner const& CompilerStack::getScanner(string const& _sourceName) +Scanner const& CompilerStack::getScanner(string const& _sourceName) const { return *getSource(_sourceName).scanner; } -SourceUnit& CompilerStack::getAST(string const& _sourceName) +SourceUnit const& CompilerStack::getAST(string const& _sourceName) const { return *getSource(_sourceName).ast; } @@ -217,7 +217,7 @@ void CompilerStack::resolveImports() swap(m_sourceOrder, sourceOrder); } -CompilerStack::Contract& CompilerStack::getContract(string const& _contractName) +CompilerStack::Contract const& CompilerStack::getContract(string const& _contractName) const { if (m_contracts.empty()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found.")); @@ -229,7 +229,7 @@ CompilerStack::Contract& CompilerStack::getContract(string const& _contractName) return it->second; } -CompilerStack::Source& CompilerStack::getSource(string const& _sourceName) +CompilerStack::Source const& CompilerStack::getSource(string const& _sourceName) const { auto it = m_sources.find(_sourceName); if (it == m_sources.end()) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 82d275498..b6c34f1ac 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -64,7 +64,7 @@ public: /// Sets the given source code as the only source unit and parses it. void parse(std::string const& _sourceCode); /// Returns a list of the contract names in the sources. - std::vector getContractNames(); + std::vector getContractNames() const; /// Compiles the source units that were previously added and parsed. void compile(bool _optimize = false); @@ -72,23 +72,23 @@ public: /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); - bytes const& getBytecode(std::string const& _contractName = ""); + bytes const& getBytecode(std::string const& _contractName = "") const; /// Streams a verbose version of the assembly to @a _outStream. /// Prerequisite: Successful compilation. - void streamAssembly(std::ostream& _outStream, std::string const& _contractName = ""); + void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "") const; /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. - std::string const& getInterface(std::string const& _contractName = ""); + std::string const& getInterface(std::string const& _contractName = "") const; /// Returns a string representing the contract's documentation in JSON. /// Prerequisite: Successful call to parse or compile. /// @param type The type of the documentation to get. /// Can be one of 3 types defined at @c DocumentationType - std::string const& getJsonDocumentation(std::string const& _contractName, DocumentationType _type); + std::string const& getJsonDocumentation(std::string const& _contractName, DocumentationType _type) const; /// Returns the previously used scanner, useful for counting lines during error reporting. - Scanner const& getScanner(std::string const& _sourceName = ""); - SourceUnit& getAST(std::string const& _sourceName = ""); + Scanner const& getScanner(std::string const& _sourceName = "") const; + SourceUnit const& getAST(std::string const& _sourceName = "") const; /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for /// scanning the source code - this is useful for printing exception information. @@ -112,9 +112,9 @@ private: std::shared_ptr compiler; bytes bytecode; std::shared_ptr interfaceHandler; - std::unique_ptr interface; - std::unique_ptr userDocumentation; - std::unique_ptr devDocumentation; + mutable std::unique_ptr interface; + mutable std::unique_ptr userDocumentation; + mutable std::unique_ptr devDocumentation; Contract(); }; @@ -122,14 +122,14 @@ private: void reset(bool _keepSources = false); void resolveImports(); - Contract& getContract(std::string const& _contractName = ""); - Source& getSource(std::string const& _sourceName = ""); + Contract const& getContract(std::string const& _contractName = "") const; + Source const& getSource(std::string const& _sourceName = "") const; bool m_parseSuccessful; - std::map m_sources; + std::map m_sources; std::shared_ptr m_globalContext; std::vector m_sourceOrder; - std::map m_contracts; + std::map m_contracts; }; } diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index c0dea757a..c7081bc78 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -28,7 +28,7 @@ namespace dev namespace solidity { -bool DeclarationContainer::registerDeclaration(Declaration& _declaration, bool _update) +bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update) { if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end()) return false; @@ -36,7 +36,7 @@ bool DeclarationContainer::registerDeclaration(Declaration& _declaration, bool _ return true; } -Declaration* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const +Declaration const* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const { auto result = m_declarations.find(_name); if (result != m_declarations.end()) diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/DeclarationContainer.h index e1b363e04..c0a0b42c7 100644 --- a/libsolidity/DeclarationContainer.h +++ b/libsolidity/DeclarationContainer.h @@ -39,18 +39,19 @@ namespace solidity class DeclarationContainer { public: - explicit DeclarationContainer(Declaration* _enclosingDeclaration = nullptr, DeclarationContainer* _enclosingContainer = nullptr): + explicit DeclarationContainer(Declaration const* _enclosingDeclaration = nullptr, + DeclarationContainer const* _enclosingContainer = nullptr): m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} /// Registers the declaration in the scope unless its name is already declared. Returns true iff /// it was not yet declared. - bool registerDeclaration(Declaration& _declaration, bool _update = false); - Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; - Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; } + bool registerDeclaration(Declaration const& _declaration, bool _update = false); + Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const; + Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } private: - Declaration* m_enclosingDeclaration; - DeclarationContainer* m_enclosingContainer; - std::map m_declarations; + Declaration const* m_enclosingDeclaration; + DeclarationContainer const* m_enclosingContainer; + std::map m_declarations; }; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index f1086c143..a0b0a54a8 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -33,7 +33,7 @@ using namespace std; namespace dev { namespace solidity { -void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression& _expression) +void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression const& _expression) { ExpressionCompiler compiler(_context); _expression.accept(compiler); @@ -46,7 +46,7 @@ void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, compiler.appendTypeConversion(_typeOnStack, _targetType); } -bool ExpressionCompiler::visit(Assignment& _assignment) +bool ExpressionCompiler::visit(Assignment const& _assignment) { _assignment.getRightHandSide().accept(*this); appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType()); @@ -68,7 +68,7 @@ bool ExpressionCompiler::visit(Assignment& _assignment) return false; } -void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) +void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation) { //@todo type checking and creating code for an operator should be in the same place: // the operator should know how to convert itself and to which types it applies, so @@ -129,10 +129,10 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) } } -bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) +bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) { - Expression& leftExpression = _binaryOperation.getLeftExpression(); - Expression& rightExpression = _binaryOperation.getRightExpression(); + Expression const& leftExpression = _binaryOperation.getLeftExpression(); + Expression const& rightExpression = _binaryOperation.getRightExpression(); Type const& commonType = _binaryOperation.getCommonType(); Token::Value const op = _binaryOperation.getOperator(); @@ -159,7 +159,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) return false; } -bool ExpressionCompiler::visit(FunctionCall& _functionCall) +bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { using Location = FunctionType::Location; if (_functionCall.isTypeConversion()) @@ -167,7 +167,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) //@todo struct construction if (asserts(_functionCall.getArguments().size() == 1)) BOOST_THROW_EXCEPTION(InternalCompilerError()); - Expression& firstArgument = *_functionCall.getArguments().front(); + Expression const& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); if (firstArgument.getType()->getCategory() == Type::Category::CONTRACT && _functionCall.getType()->getCategory() == Type::Category::INTEGER) @@ -180,7 +180,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) else { FunctionType const& function = dynamic_cast(*_functionCall.getExpression().getType()); - std::vector> const& arguments = _functionCall.getArguments(); + std::vector> arguments = _functionCall.getArguments(); if (asserts(arguments.size() == function.getParameterTypes().size())) BOOST_THROW_EXCEPTION(InternalCompilerError()); @@ -299,7 +299,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) return false; } -void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) +void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) { ASTString const& member = _memberAccess.getMemberName(); switch (_memberAccess.getExpression().getType()->getCategory()) @@ -365,7 +365,7 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) } } -bool ExpressionCompiler::visit(IndexAccess& _indexAccess) +bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) { _indexAccess.getBaseExpression().accept(*this); _indexAccess.getIndexExpression().accept(*this); @@ -382,30 +382,30 @@ bool ExpressionCompiler::visit(IndexAccess& _indexAccess) return false; } -void ExpressionCompiler::endVisit(Identifier& _identifier) +void ExpressionCompiler::endVisit(Identifier const& _identifier) { - Declaration* declaration = _identifier.getReferencedDeclaration(); - if (MagicVariableDeclaration* magicVar = dynamic_cast(declaration)) + Declaration const* declaration = _identifier.getReferencedDeclaration(); + if (MagicVariableDeclaration const* magicVar = dynamic_cast(declaration)) { if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this" m_context << eth::Instruction::ADDRESS; return; } - if (FunctionDefinition* functionDef = dynamic_cast(declaration)) + if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) { m_context << m_context.getFunctionEntryLabel(*functionDef).pushTag(); return; } - if (/*VariableDeclaration* varDef = */dynamic_cast(declaration)) + if (dynamic_cast(declaration)) { - m_currentLValue.fromIdentifier(_identifier, *_identifier.getReferencedDeclaration()); + m_currentLValue.fromIdentifier(_identifier, *declaration); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); return; } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context.")); } -void ExpressionCompiler::endVisit(Literal& _literal) +void ExpressionCompiler::endVisit(Literal const& _literal) { switch (_literal.getType()->getCategory()) { @@ -418,7 +418,7 @@ void ExpressionCompiler::endVisit(Literal& _literal) } } -void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) +void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation) { Token::Value const op = _binaryOperation.getOperator(); if (asserts(op == Token::OR || op == Token::AND)) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 966be30e2..41cb66763 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -41,11 +41,11 @@ class IntegerType; * of EVM instructions. It needs a compiler context that is the same for the whole compilation * unit. */ -class ExpressionCompiler: private ASTVisitor +class ExpressionCompiler: private ASTConstVisitor { public: /// Compile the given @a _expression into the @a _context. - static void compileExpression(CompilerContext& _context, Expression& _expression); + static void compileExpression(CompilerContext& _context, Expression const& _expression); /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); @@ -54,18 +54,18 @@ private: ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext), m_currentLValue(m_context) {} - virtual bool visit(Assignment& _assignment) override; - virtual void endVisit(UnaryOperation& _unaryOperation) override; - virtual bool visit(BinaryOperation& _binaryOperation) override; - virtual bool visit(FunctionCall& _functionCall) override; - virtual void endVisit(MemberAccess& _memberAccess) override; - virtual bool visit(IndexAccess& _indexAccess) override; - virtual void endVisit(Identifier& _identifier) override; - virtual void endVisit(Literal& _literal) override; + virtual bool visit(Assignment const& _assignment) override; + virtual void endVisit(UnaryOperation const& _unaryOperation) override; + virtual bool visit(BinaryOperation const& _binaryOperation) override; + virtual bool visit(FunctionCall const& _functionCall) override; + virtual void endVisit(MemberAccess const& _memberAccess) override; + virtual bool visit(IndexAccess const& _indexAccess) override; + virtual void endVisit(Identifier const& _identifier) override; + virtual void endVisit(Literal const& _literal) override; ///@{ ///@name Append code for various operator types - void appendAndOrOperatorCode(BinaryOperation& _binaryOperation); + void appendAndOrOperatorCode(BinaryOperation const& _binaryOperation); void appendCompareOperatorCode(Token::Value _operator, Type const& _type); void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); @@ -134,10 +134,6 @@ private: CompilerContext& m_context; LValue m_currentLValue; - /// If a "virtual" function (i.e. a bulit-in function without jump tag) is encountered, the - /// actual function is stored here. @todo prevent assignment or store it with assignment - enum class SpecialFunction { NONE, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 }; - SpecialFunction m_currentSpecialFunction; }; diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 2d384a15d..f4805b1f7 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -33,7 +33,7 @@ namespace solidity { GlobalContext::GlobalContext(): -m_magicVariables(vector>{make_shared("block", make_shared(MagicType::Kind::BLOCK)), +m_magicVariables(vector>{make_shared("block", make_shared(MagicType::Kind::BLOCK)), make_shared("msg", make_shared(MagicType::Kind::MSG)), make_shared("tx", make_shared(MagicType::Kind::TX)), make_shared("suicide", @@ -68,16 +68,16 @@ void GlobalContext::setCurrentContract(ContractDefinition const& _contract) m_currentContract = &_contract; } -vector GlobalContext::getDeclarations() const +vector GlobalContext::getDeclarations() const { - vector declarations; + vector declarations; declarations.reserve(m_magicVariables.size() + 1); - for (ASTPointer const& variable: m_magicVariables) + for (ASTPointer const& variable: m_magicVariables) declarations.push_back(variable.get()); return declarations; } -MagicVariableDeclaration* GlobalContext::getCurrentThis() const +MagicVariableDeclaration const* GlobalContext::getCurrentThis() const { if (!m_thisPointer[m_currentContract]) m_thisPointer[m_currentContract] = make_shared( diff --git a/libsolidity/GlobalContext.h b/libsolidity/GlobalContext.h index ddbd049c2..50a21f702 100644 --- a/libsolidity/GlobalContext.h +++ b/libsolidity/GlobalContext.h @@ -47,17 +47,17 @@ class GlobalContext: private boost::noncopyable public: GlobalContext(); void setCurrentContract(ContractDefinition const& _contract); - MagicVariableDeclaration* getCurrentThis() const; + MagicVariableDeclaration const* getCurrentThis() const; /// @returns all magic variables. std::vector getMagicVariables() const; /// @returns a vector of all implicit global declarations excluding "this". - std::vector getDeclarations() const; + std::vector getDeclarations() const; private: - std::vector> m_magicVariables; + std::vector> m_magicVariables; ContractDefinition const* m_currentContract; - std::map> mutable m_thisPointer; + std::map> mutable m_thisPointer; }; } diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index c3e62cad0..f26088afa 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -75,7 +75,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi if (strPtr) { resetUser(); - parseDocString(*strPtr); + parseDocString(*strPtr, CommentOwner::FUNCTION); if (!m_notice.empty()) {// since @notice is the only user tag if missing function should not appear user["notice"] = Json::Value(m_notice); @@ -95,6 +95,20 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin Json::Value doc; Json::Value methods(Json::objectValue); + auto contractDoc = _contractDef.getDocumentation(); + if (contractDoc) + { + m_contractAuthor.clear(); + m_title.clear(); + parseDocString(*contractDoc, CommentOwner::CONTRACT); + + if (!m_contractAuthor.empty()) + doc["author"] = m_contractAuthor; + + if (!m_title.empty()) + doc["title"] = m_title; + } + for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions()) { Json::Value method; @@ -102,16 +116,21 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin if (strPtr) { resetDev(); - parseDocString(*strPtr); + parseDocString(*strPtr, CommentOwner::FUNCTION); if (!m_dev.empty()) method["details"] = Json::Value(m_dev); + + if (!m_author.empty()) + method["author"] = m_author; + Json::Value params(Json::objectValue); for (auto const& pair: m_params) params[pair.first] = pair.second; if (!m_params.empty()) method["params"] = params; + if (!m_return.empty()) method["return"] = m_return; @@ -133,6 +152,7 @@ void InterfaceHandler::resetUser() void InterfaceHandler::resetDev() { m_dev.clear(); + m_author.clear(); m_return.clear(); m_params.clear(); } @@ -193,10 +213,12 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos, std::string::const_iterator _end, - std::string const& _tag) + std::string const& _tag, + CommentOwner _owner) { // LTODO: need to check for @(start of a tag) between here and the end of line - // for all cases + // for all cases. Also somehow automate list of acceptable tags for each + // language construct since current way does not scale well. if (m_lastTag == DocTagType::NONE || _tag != "") { if (_tag == "dev") @@ -205,37 +227,77 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE); else if (_tag == "return") return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN); + else if (_tag == "author") + { + if (_owner == CommentOwner::CONTRACT) + return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR); + else if (_owner == CommentOwner::FUNCTION) + return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR); + else + // LTODO: for now this else makes no sense but later comments will go to more language constructs + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts")); + } + else if (_tag == "title") + { + if (_owner == CommentOwner::CONTRACT) + return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE); + else + // LTODO: Unknown tag, throw some form of warning and not just an exception + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts")); + } else if (_tag == "param") return parseDocTagParam(_pos, _end); else - { // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered")); - } } else - return appendDocTag(_pos, _end); + return appendDocTag(_pos, _end, _owner); } std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end) + std::string::const_iterator _end, + CommentOwner _owner) { switch (m_lastTag) { - case DocTagType::DEV: - m_dev += " "; - return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV); - case DocTagType::NOTICE: - m_notice += " "; - return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE); - case DocTagType::RETURN: - m_return += " "; - return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN); - case DocTagType::PARAM: - return appendDocTagParam(_pos, _end); - default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); - break; + case DocTagType::DEV: + m_dev += " "; + return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV); + case DocTagType::NOTICE: + m_notice += " "; + return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE); + case DocTagType::RETURN: + m_return += " "; + return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN); + case DocTagType::AUTHOR: + if (_owner == CommentOwner::CONTRACT) + { + m_contractAuthor += " "; + return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR); + } + else if (_owner == CommentOwner::FUNCTION) + { + m_author += " "; + return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR); + } + else + // LTODO: Unknown tag, throw some form of warning and not just an exception + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment")); + case DocTagType::TITLE: + if (_owner == CommentOwner::CONTRACT) + { + m_title += " "; + return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE); + } + else + // LTODO: Unknown tag, throw some form of warning and not just an exception + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment")); + case DocTagType::PARAM: + return appendDocTagParam(_pos, _end); + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); + break; } } @@ -247,7 +309,7 @@ static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_i return (spacePos < nlPos) ? spacePos : nlPos; } -void InterfaceHandler::parseDocString(std::string const& _string) +void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner) { auto currPos = _string.begin(); auto end = _string.end(); @@ -265,10 +327,10 @@ void InterfaceHandler::parseDocString(std::string const& _string) BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); - currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos)); + currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner); } else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag - currPos = appendDocTag(currPos + 1, end); + currPos = appendDocTag(currPos + 1, end, _owner); else if (currPos != end) // skip the line if a newline was found currPos = nlPos + 1; } diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 4fa63fcda..b1cd4b562 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -45,7 +45,15 @@ enum class DocTagType: uint8_t DEV, NOTICE, PARAM, - RETURN + RETURN, + AUTHOR, + TITLE +}; + +enum class CommentOwner +{ + CONTRACT, + FUNCTION }; class InterfaceHandler @@ -89,12 +97,14 @@ private: std::string::const_iterator _end); std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, std::string::const_iterator _end); - void parseDocString(std::string const& _string); + void parseDocString(std::string const& _string, CommentOwner _owner); std::string::const_iterator appendDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end); + std::string::const_iterator _end, + CommentOwner _owner); std::string::const_iterator parseDocTag(std::string::const_iterator _pos, std::string::const_iterator _end, - std::string const& _tag); + std::string const& _tag, + CommentOwner _owner); Json::StyledWriter m_writer; @@ -103,6 +113,9 @@ private: std::string m_notice; std::string m_dev; std::string m_return; + std::string m_contractAuthor; + std::string m_author; + std::string m_title; std::vector> m_params; }; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 3715df6ad..540b066eb 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -32,9 +32,9 @@ namespace solidity { -NameAndTypeResolver::NameAndTypeResolver(std::vector const& _globals) +NameAndTypeResolver::NameAndTypeResolver(std::vector const& _globals) { - for (Declaration* declaration: _globals) + for (Declaration const* declaration: _globals) m_scopes[nullptr].registerDeclaration(*declaration); } @@ -70,13 +70,14 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[nullptr]; } -void NameAndTypeResolver::updateDeclaration(Declaration& _declaration) +void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) { m_scopes[nullptr].registerDeclaration(_declaration, true); - _declaration.setScope(nullptr); + if (asserts(_declaration.getScope() == nullptr)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Updated declaration outside global scope.")); } -Declaration* NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const +Declaration const* NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const { auto iterator = m_scopes.find(_scope); if (iterator == end(m_scopes)) @@ -84,7 +85,7 @@ Declaration* NameAndTypeResolver::resolveName(ASTString const& _name, Declaratio return iterator->second.resolveName(_name, false); } -Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) +Declaration const* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) { return m_currentScope->resolveName(_name, _recursive); } @@ -146,7 +147,7 @@ bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) return true; } -void DeclarationRegistrationHelper::enterNewSubScope(Declaration& _declaration) +void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration) { map::iterator iter; bool newlyAdded; @@ -204,15 +205,14 @@ bool ReferencesResolver::visit(Return& _return) return true; } -bool ReferencesResolver::visit(Mapping& _mapping) +bool ReferencesResolver::visit(Mapping&) { - (void)_mapping; return true; } bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { - Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); + Declaration const* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) << errinfo_comment("Undeclared identifier.")); @@ -222,7 +222,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) bool ReferencesResolver::visit(Identifier& _identifier) { - Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); + Declaration const* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Undeclared identifier.")); diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 816d8006f..1ff9febf0 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -41,27 +41,25 @@ namespace solidity class NameAndTypeResolver: private boost::noncopyable { public: - explicit NameAndTypeResolver(std::vector const& _globals); + explicit NameAndTypeResolver(std::vector const& _globals); /// Registers all declarations found in the source unit. void registerDeclarations(SourceUnit& _sourceUnit); /// Resolves all names and types referenced from the given contract. void resolveNamesAndTypes(ContractDefinition& _contract); /// Updates the given global declaration (used for "this"). Not to be used with declarations /// that create their own scope. - void updateDeclaration(Declaration& _declaration); + void updateDeclaration(Declaration const& _declaration); /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, /// the global scope is used (i.e. the one containing only the contract). /// @returns a pointer to the declaration on success or nullptr on failure. - Declaration* resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + Declaration const* resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; /// Resolves a name in the "current" scope. Should only be called during the initial /// resolving phase. - Declaration* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); + Declaration const* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); private: - /// Throws if @a _struct contains a recursive loop. Note that recursion via mappings is fine. - void checkForRecursion(StructDefinition const& _struct); void reset(); /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration, @@ -91,12 +89,12 @@ private: void endVisit(VariableDefinition& _variableDefinition); bool visit(VariableDeclaration& _declaration); - void enterNewSubScope(Declaration& _declaration); + void enterNewSubScope(Declaration const& _declaration); void closeCurrentScope(); void registerDeclaration(Declaration& _declaration, bool _opensScope); std::map& m_scopes; - Declaration* m_currentScope; + Declaration const* m_currentScope; FunctionDefinition* m_currentFunction; }; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index ddab489b6..b678b2fc0 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -112,6 +112,9 @@ ASTPointer Parser::parseImportDirective() ASTPointer Parser::parseContractDefinition() { ASTNodeFactory nodeFactory(*this); + ASTPointer docstring; + if (m_scanner->getCurrentCommentLiteral() != "") + docstring = make_shared(m_scanner->getCurrentCommentLiteral()); expectToken(Token::CONTRACT); ASTPointer name = expectIdentifierToken(); expectToken(Token::LBRACE); @@ -146,7 +149,7 @@ ASTPointer Parser::parseContractDefinition() } nodeFactory.markEndPosition(); expectToken(Token::RBRACE); - return nodeFactory.createNode(name, structs, stateVariables, functions); + return nodeFactory.createNode(name, docstring, structs, stateVariables, functions); } ASTPointer Parser::parseFunctionDefinition(bool _isPublic) diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index 1a7d12a95..c61f9b685 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -61,7 +61,7 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream, void SourceReferenceFormatter::printExceptionInformation(ostream& _stream, Exception const& _exception, string const& _name, - CompilerStack& _compiler) + CompilerStack const& _compiler) { Location const* location = boost::get_error_info(_exception); Scanner const* scanner; diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h index 9b5567045..8e3f126f0 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/libsolidity/SourceReferenceFormatter.h @@ -41,7 +41,7 @@ struct SourceReferenceFormatter public: static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner); static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, - std::string const& _name, CompilerStack& _compiler); + std::string const& _name, CompilerStack const& _compiler); }; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 3829016f5..d14311a26 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -32,7 +32,7 @@ namespace dev namespace solidity { -shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) +shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) { if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError()); @@ -44,33 +44,33 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) if (bytes == 0) bytes = 32; int modifier = offset / 33; - return make_shared(bytes * 8, + return make_shared(bytes * 8, modifier == 0 ? IntegerType::Modifier::SIGNED : modifier == 1 ? IntegerType::Modifier::UNSIGNED : IntegerType::Modifier::HASH); } else if (_typeToken == Token::ADDRESS) - return make_shared(0, IntegerType::Modifier::ADDRESS); + return make_shared(0, IntegerType::Modifier::ADDRESS); else if (_typeToken == Token::BOOL) - return make_shared(); + return shared_ptr(); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); } -shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) +shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) { Declaration const* declaration = _typeName.getReferencedDeclaration(); if (StructDefinition const* structDef = dynamic_cast(declaration)) - return make_shared(*structDef); + return make_shared(*structDef); else if (FunctionDefinition const* function = dynamic_cast(declaration)) - return make_shared(*function); + return make_shared(*function); else if (ContractDefinition const* contract = dynamic_cast(declaration)) - return make_shared(*contract); - return shared_ptr(); + return make_shared(*contract); + return shared_ptr(); } -shared_ptr Type::fromMapping(Mapping const& _typeName) +shared_ptr Type::fromMapping(Mapping const& _typeName) { shared_ptr keyType = _typeName.getKeyType().toType(); if (!keyType) @@ -78,28 +78,28 @@ shared_ptr Type::fromMapping(Mapping const& _typeName) shared_ptr valueType = _typeName.getValueType().toType(); if (!valueType) BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name")); - return make_shared(keyType, valueType); + return make_shared(keyType, valueType); } -shared_ptr Type::forLiteral(Literal const& _literal) +shared_ptr Type::forLiteral(Literal const& _literal) { switch (_literal.getToken()) { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: - return make_shared(); + return shared_ptr(); case Token::NUMBER: return IntegerType::smallestTypeForLiteral(_literal.getValue()); case Token::STRING_LITERAL: - return shared_ptr(); // @todo add string literals + return shared_ptr(); // @todo add string literals default: - return shared_ptr(); + return shared_ptr(); } } const MemberList Type::EmptyMemberList = MemberList(); -shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) +shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) { bigint value(_literal); bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-'); @@ -108,8 +108,8 @@ shared_ptr IntegerType::smallestTypeForLiteral(string const& _liter value = ((-value) - 1) << 1; unsigned bytes = max(bytesRequired(value), 1u); if (bytes > 32) - return shared_ptr(); - return make_shared(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED); + return shared_ptr(); + return make_shared(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED); } IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 8e2f4803b..887a1ee16 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -80,15 +80,15 @@ public: ///@{ ///@name Factory functions /// Factory functions that convert an AST @ref TypeName to a Type. - static std::shared_ptr fromElementaryTypeName(Token::Value _typeToken); - static std::shared_ptr fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); - static std::shared_ptr fromMapping(Mapping const& _typeName); - static std::shared_ptr fromFunction(FunctionDefinition const& _function); + static std::shared_ptr fromElementaryTypeName(Token::Value _typeToken); + static std::shared_ptr fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); + static std::shared_ptr fromMapping(Mapping const& _typeName); + static std::shared_ptr fromFunction(FunctionDefinition const& _function); /// @} /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does /// not fit any type. - static std::shared_ptr forLiteral(Literal const& _literal); + static std::shared_ptr forLiteral(Literal const& _literal); virtual Category getCategory() const = 0; virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } @@ -148,7 +148,7 @@ public: /// @returns the smallest integer type for the given literal or an empty pointer /// if no type fits. - static std::shared_ptr smallestTypeForLiteral(std::string const& _literal); + static std::shared_ptr smallestTypeForLiteral(std::string const& _literal); explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); @@ -286,7 +286,7 @@ public: virtual bool canLiveOutsideStorage() const override { return false; } virtual unsigned getSizeOnStack() const override; - Location getLocation() const { return m_location; } + Location const& getLocation() const { return m_location; } private: TypePointers m_parameterTypes; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index d3dd39459..6ace332f7 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -255,7 +255,22 @@ bool CommandLineInterface::processInput() } else for (string const& infile: m_args["input-file"].as>()) + { + auto path = boost::filesystem::path(infile); + if (!boost::filesystem::exists(path)) + { + cout << "Skipping non existant input file \"" << infile << "\"" << endl; + continue; + } + + if (!boost::filesystem::is_regular_file(path)) + { + cout << "\"" << infile << "\" is not a valid file. Skipping" << endl; + continue; + } + m_sourceCodes[infile] = asString(dev::contents(infile)); + } try { diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index d66d1294f..2c3ded08d 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -21,8 +21,9 @@ */ #include -#include #include +#include +#include #include namespace dev @@ -393,6 +394,93 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) checkNatspec(sourceCode, natspec, false); } +BOOST_AUTO_TEST_CASE(dev_contract_no_doc) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Mul function\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + " \"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Mul function\"\n" + " }\n" + " }\n" + "}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_contract_doc) +{ + char const* sourceCode = " /// @author Lefteris\n" + " /// @title Just a test contract\n" + "contract test {\n" + " /// @dev Mul function\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + " \"author\": \"Lefteris\"," + " \"title\": \"Just a test contract\"," + " \"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Mul function\"\n" + " }\n" + " }\n" + "}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_author_at_function) +{ + char const* sourceCode = " /// @author Lefteris\n" + " /// @title Just a test contract\n" + "contract test {\n" + " /// @dev Mul function\n" + " /// @author John Doe\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + " \"author\": \"Lefteris\"," + " \"title\": \"Just a test contract\"," + " \"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Mul function\",\n" + " \"author\": \"John Doe\",\n" + " }\n" + " }\n" + "}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_title_at_function_error) +{ + char const* sourceCode = " /// @author Lefteris\n" + " /// @title Just a test contract\n" + "contract test {\n" + " /// @dev Mul function\n" + " /// @title I really should not be here\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + " \"author\": \"Lefteris\"," + " \"title\": \"Just a test contract\"," + " \"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Mul function\"\n" + " }\n" + " }\n" + "}"; + + BOOST_CHECK_THROW(checkNatspec(sourceCode, natspec, false), DocstringParsingError); +} + BOOST_AUTO_TEST_SUITE_END() }