diff options
-rw-r--r-- | libsolidity/AST.cpp | 78 | ||||
-rw-r--r-- | libsolidity/AST.h | 29 | ||||
-rw-r--r-- | libsolidity/ASTAnnotations.h | 97 | ||||
-rw-r--r-- | libsolidity/ExpressionCompiler.cpp | 4 | ||||
-rw-r--r-- | libsolidity/LValue.cpp | 4 | ||||
-rw-r--r-- | libsolidity/LValue.h | 5 | ||||
-rw-r--r-- | libsolidity/ReferencesResolver.cpp | 6 | ||||
-rw-r--r-- | libsolidity/TypeChecker.cpp | 8 |
8 files changed, 186 insertions, 45 deletions
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 4cd6cc0f..00b51c42 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -41,6 +41,14 @@ ASTNode::ASTNode(SourceLocation const& _location): ASTNode::~ASTNode() { + delete m_annotation; +} + +ASTAnnotation& ASTNode::annotation() const +{ + if (!m_annotation) + m_annotation = new ASTAnnotation(); + return *m_annotation; } TypeError ASTNode::createTypeError(string const& _description) const @@ -188,6 +196,20 @@ TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract return make_shared<TypeType>(make_shared<ContractType>(*this), m_currentContract); } +ContractDefinitionAnnotation& ContractDefinition::annotation() const +{ + if (!m_annotation) + m_annotation = new ContractDefinitionAnnotation(); + return static_cast<ContractDefinitionAnnotation&>(*m_annotation); +} + +TypeNameAnnotation& TypeName::annotation() const +{ + if (!m_annotation) + m_annotation = new TypeNameAnnotation(); + return static_cast<TypeNameAnnotation&>(*m_annotation); +} + TypePointer StructDefinition::type(ContractDefinition const*) const { return make_shared<TypeType>(make_shared<StructType>(*this)); @@ -225,6 +247,13 @@ TypePointer EventDefinition::type(ContractDefinition const*) const return make_shared<FunctionType>(*this); } +UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const +{ + if (!m_annotation) + m_annotation = new UserDefinedTypeNameAnnotation(); + return static_cast<UserDefinedTypeNameAnnotation&>(*m_annotation); +} + bool VariableDeclaration::isLValue() const { // External function parameters and constant declared variables are Read-Only @@ -267,3 +296,52 @@ TypePointer VariableDeclaration::type(ContractDefinition const*) const { return annotation().type; } + +VariableDeclarationAnnotation& VariableDeclaration::annotation() const +{ + if (!m_annotation) + m_annotation = new VariableDeclarationAnnotation(); + return static_cast<VariableDeclarationAnnotation&>(*m_annotation); +} + +ReturnAnnotation& Return::annotation() const +{ + if (!m_annotation) + m_annotation = new ReturnAnnotation(); + return static_cast<ReturnAnnotation&>(*m_annotation); +} + +ExpressionAnnotation& Expression::annotation() const +{ + if (!m_annotation) + m_annotation = new ExpressionAnnotation(); + return static_cast<ExpressionAnnotation&>(*m_annotation); +} + +MemberAccessAnnotation& MemberAccess::annotation() const +{ + if (!m_annotation) + m_annotation = new MemberAccessAnnotation(); + return static_cast<MemberAccessAnnotation&>(*m_annotation); +} + +BinaryOperationAnnotation& BinaryOperation::annotation() const +{ + if (!m_annotation) + m_annotation = new BinaryOperationAnnotation(); + return static_cast<BinaryOperationAnnotation&>(*m_annotation); +} + +FunctionCallAnnotation& FunctionCall::annotation() const +{ + if (!m_annotation) + m_annotation = new FunctionCallAnnotation(); + return static_cast<FunctionCallAnnotation&>(*m_annotation); +} + +IdentifierAnnotation& Identifier::annotation() const +{ + if (!m_annotation) + m_annotation = new IdentifierAnnotation(); + return static_cast<IdentifierAnnotation&>(*m_annotation); +} diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 08d26b70..4e299743 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -42,7 +42,6 @@ namespace solidity class ASTVisitor; class ASTConstVisitor; -struct ASTAnnotation; /** @@ -79,7 +78,7 @@ public: TypeError createTypeError(std::string const& _description) const; ///@todo make this const-safe by providing a different way to access the annotation - ASTAnnotation& annotation() const { return const_cast<ASTAnnotation&>(m_annotation); } + virtual ASTAnnotation& annotation() const; ///@{ ///@name equality operators @@ -88,10 +87,12 @@ public: bool operator!=(ASTNode const& _other) const { return !operator==(_other); } ///@} +protected: + /// Annotation - is specialised in derived classes, is created upon request (because of polymorphism). + mutable ASTAnnotation* m_annotation = nullptr; + private: SourceLocation m_location; - - ASTAnnotation m_annotation; }; /** @@ -288,6 +289,8 @@ public: virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual ContractDefinitionAnnotation& annotation() const override; + private: std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts; std::vector<ASTPointer<StructDefinition>> m_definedStructs; @@ -538,6 +541,8 @@ public: virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual VariableDeclarationAnnotation& annotation() const override; + protected: Visibility defaultVisibility() const override { return Visibility::Internal; } @@ -666,6 +671,8 @@ public: explicit TypeName(SourceLocation const& _location): ASTNode(_location) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; + + virtual TypeNameAnnotation& annotation() const override; }; /** @@ -702,6 +709,8 @@ public: ASTString const& name() const { return *m_name; } + virtual UserDefinedTypeNameAnnotation& annotation() const override; + private: ASTPointer<ASTString> m_name; }; @@ -904,6 +913,8 @@ public: Expression const* expression() const { return m_expression.get(); } + virtual ReturnAnnotation& annotation() const override; + private: ASTPointer<Expression> m_expression; ///< value to return, optional }; @@ -970,6 +981,8 @@ class Expression: public ASTNode { public: Expression(SourceLocation const& _location): ASTNode(_location) {} + + ExpressionAnnotation& annotation() const override; }; /// Assignment, can also be a compound assignment. @@ -1050,6 +1063,8 @@ public: Expression const& rightExpression() const { return *m_right; } Token::Value getOperator() const { return m_operator; } + BinaryOperationAnnotation& annotation() const override; + private: ASTPointer<Expression> m_left; Token::Value m_operator; @@ -1072,6 +1087,8 @@ public: std::vector<ASTPointer<Expression const>> arguments() const { return {m_arguments.begin(), m_arguments.end()}; } std::vector<ASTPointer<ASTString>> const& names() const { return m_names; } + virtual FunctionCallAnnotation& annotation() const override; + private: ASTPointer<Expression> m_expression; std::vector<ASTPointer<Expression>> m_arguments; @@ -1109,6 +1126,8 @@ public: Expression const& expression() const { return *m_expression; } ASTString const& memberName() const { return *m_memberName; } + virtual MemberAccessAnnotation& annotation() const override; + private: ASTPointer<Expression> m_expression; ASTPointer<ASTString> m_memberName; @@ -1157,6 +1176,8 @@ public: ASTString const& name() const { return *m_name; } + virtual IdentifierAnnotation& annotation() const override; + private: ASTPointer<ASTString> m_name; }; diff --git a/libsolidity/ASTAnnotations.h b/libsolidity/ASTAnnotations.h index 9564d2d0..195f11c8 100644 --- a/libsolidity/ASTAnnotations.h +++ b/libsolidity/ASTAnnotations.h @@ -25,53 +25,98 @@ #include <map> #include <memory> #include <vector> +#include <libsolidity/ASTForward.h> namespace dev { namespace solidity { -class ASTNode; -class ContractDefinition; -class Declaration; -class ParameterList; class Type; using TypePointer = std::shared_ptr<Type const>; struct ASTAnnotation { - ///@TODO save space here - we do not need all members for all types. + virtual ~ASTAnnotation() {} +}; + +struct ContractDefinitionAnnotation: ASTAnnotation +{ + /// Whether all functions are implemented. + bool isFullyImplemented = true; + /// List of all (direct and indirect) base contracts in order from derived to + /// base, including the contract itself. + std::vector<ContractDefinition const*> linearizedBaseContracts; +}; + +struct VariableDeclarationAnnotation: ASTAnnotation +{ + /// Type of variable (type of identifier referencing this variable). + TypePointer type; +}; + +struct ReturnAnnotation: ASTAnnotation +{ + /// Reference to the return parameters of the function. + ParameterList const* functionReturnParameters = nullptr; +}; + +struct TypeNameAnnotation: ASTAnnotation +{ + /// Type declared by this type name, i.e. type of a variable where this type name is used. + /// Set during reference resolution stage. + TypePointer type; +}; + +struct UserDefinedTypeNameAnnotation: TypeNameAnnotation +{ + /// Referenced declaration, set during reference resolution stage. + Declaration const* referencedDeclaration = nullptr; +}; - /// For expression: Inferred type. - For type declaration: Declared type. - For variable declaration: Type of variable. +struct ExpressionAnnotation: ASTAnnotation +{ + /// Inferred type of the expression. TypePointer type; - /// For expression: Whether it is an LValue (i.e. something that can be assigned to). + /// Whether it is an LValue (i.e. something that can be assigned to). bool isLValue = false; - /// For expression: Whether the expression is used in a context where the LValue is actually required. + /// Whether the expression is used in a context where the LValue is actually required. bool lValueRequested = false; - /// For expressions: Types of arguments if the expression is a function that is called - used + /// Types of arguments if the expression is a function that is called - used /// for overload resolution. std::shared_ptr<std::vector<TypePointer>> argumentTypes; - /// For contract: Whether all functions are implemented. - bool isFullyImplemented = true; - /// For contract: List of all (direct and indirect) base contracts in order from derived to - /// base, including the contract itself. - std::vector<ContractDefinition const*> linearizedBaseContracts; - /// For member access and Identifer: Referenced declaration, set during overload resolution stage. +}; + +struct IdentifierAnnotation: ExpressionAnnotation +{ + /// Stores a reference to the current contract. + /// This is needed because types of base contracts change depending on the context. + ContractDefinition const* contractScope = nullptr; + /// Referenced declaration, set at latest during overload resolution stage. Declaration const* referencedDeclaration = nullptr; - /// For Identifier: List of possible declarations it could refer to. + /// List of possible declarations it could refer to. std::vector<Declaration const*> overloadedDeclarations; - /// For function call: Whether this is an explicit type conversion. +}; + +struct MemberAccessAnnotation: ExpressionAnnotation +{ + /// Referenced declaration, set at latest during overload resolution stage. + Declaration const* referencedDeclaration = nullptr; +}; + +struct BinaryOperationAnnotation: ExpressionAnnotation +{ + /// The common type that is used for the operation, not necessarily the result type (which + /// e.g. for comparisons is bool). + TypePointer commonType; +}; + +struct FunctionCallAnnotation: ExpressionAnnotation +{ + /// Whether this is an explicit type conversion. bool isTypeConversion = false; - /// For function call: Whether this is a struct constructor call. + /// Whether this is a struct constructor call. bool isStructConstructorCall = false; - /// For Return statement: Reference to the return parameters of the function. - ParameterList const* functionReturnParameters = nullptr; - /// For Identifier: Stores a reference to the current contract. - /// This is needed because types of base contracts change depending on the context. - ContractDefinition const* contractScope = nullptr; - /// For BinaryOperation: The common type that is used for the operation, not necessarily the result type (e.g. for - /// comparisons, this is always bool). - TypePointer commonType; }; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 1fa70797..81ef6690 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1274,9 +1274,9 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) { if (m_context.isLocalVariable(&_declaration)) - setLValue<StackVariable>(_expression, _declaration); + setLValue<StackVariable>(_expression, dynamic_cast<VariableDeclaration const&>(_declaration)); else if (m_context.isStateVariable(&_declaration)) - setLValue<StorageItem>(_expression, _declaration); + setLValue<StorageItem>(_expression, dynamic_cast<VariableDeclaration const&>(_declaration)); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.location()) diff --git a/libsolidity/LValue.cpp b/libsolidity/LValue.cpp index 4bd38b49..81aaeb4d 100644 --- a/libsolidity/LValue.cpp +++ b/libsolidity/LValue.cpp @@ -31,7 +31,7 @@ using namespace dev; using namespace solidity; -StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration): +StackVariable::StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration): LValue(_compilerContext, *_declaration.annotation().type), m_baseStackOffset(m_context.baseStackOffsetOfVariable(_declaration)), m_size(m_dataType.sizeOnStack()) @@ -131,7 +131,7 @@ void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const m_context << eth::Instruction::POP; } -StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration): +StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration): StorageItem(_compilerContext, *_declaration.annotation().type) { auto const& location = m_context.storageLocationOfVariable(_declaration); diff --git a/libsolidity/LValue.h b/libsolidity/LValue.h index f02d8ad1..cbbfb102 100644 --- a/libsolidity/LValue.h +++ b/libsolidity/LValue.h @@ -35,6 +35,7 @@ class Declaration; class Type; class ArrayType; class CompilerContext; +class VariableDeclaration; /** * Abstract class used to retrieve, delete and store data in lvalues/variables. @@ -76,7 +77,7 @@ protected: class StackVariable: public LValue { public: - StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration); + StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration); virtual unsigned sizeOnStack() const override { return 0; } virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; @@ -129,7 +130,7 @@ class StorageItem: public LValue { public: /// Constructs the LValue and pushes the location of @a _declaration onto the stack. - StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration); + StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration); /// Constructs the LValue and assumes that the storage reference is already on the stack. StorageItem(CompilerContext& _compilerContext, Type const& _type); virtual unsigned sizeOnStack() const override { return 2; } diff --git a/libsolidity/ReferencesResolver.cpp b/libsolidity/ReferencesResolver.cpp index b2cdacc4..623ac8f7 100644 --- a/libsolidity/ReferencesResolver.cpp +++ b/libsolidity/ReferencesResolver.cpp @@ -173,9 +173,9 @@ TypePointer ReferencesResolver::typeFor(TypeName const& _typeName) TypePointer type; if (auto elemTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName)) type = Type::fromElementaryTypeName(elemTypeName->typeName()); - else if (dynamic_cast<UserDefinedTypeName const*>(&_typeName)) + else if (auto typeName = dynamic_cast<UserDefinedTypeName const*>(&_typeName)) { - Declaration const* declaration = _typeName.annotation().referencedDeclaration; + Declaration const* declaration = typeName->annotation().referencedDeclaration; solAssert(!!declaration, ""); if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration)) @@ -185,7 +185,7 @@ TypePointer ReferencesResolver::typeFor(TypeName const& _typeName) else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration)) type = make_shared<ContractType>(*contract); else - BOOST_THROW_EXCEPTION(_typeName.createTypeError( + BOOST_THROW_EXCEPTION(typeName->createTypeError( "Name has to refer to a struct, enum or contract." )); } diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/TypeChecker.cpp index 1bb1381b..a886a2ab 100644 --- a/libsolidity/TypeChecker.cpp +++ b/libsolidity/TypeChecker.cpp @@ -402,7 +402,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) visitManually( *modifier, _function.isConstructor() ? - _function.scope()->annotation().linearizedBaseContracts : + dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts : vector<ContractDefinition const*>() ); if (_function.isImplemented()) @@ -484,12 +484,8 @@ void TypeChecker::visitManually( ) { std::vector<ASTPointer<Expression>> const& arguments = _modifier.arguments(); - _modifier.annotation().argumentTypes = make_shared<TypePointers>(); for (ASTPointer<Expression> const& argument: arguments) - { argument->accept(*this); - _modifier.annotation().argumentTypes->push_back(type(*argument)); - } _modifier.name()->accept(*this); auto const* declaration = &dereference(*_modifier.name()); @@ -1049,7 +1045,7 @@ bool TypeChecker::visit(IndexAccess const& _access) bool TypeChecker::visit(Identifier const& _identifier) { - ASTAnnotation& annotation = _identifier.annotation(); + IdentifierAnnotation& annotation = _identifier.annotation(); if (!annotation.referencedDeclaration) { if (!annotation.argumentTypes) |