aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/AST.cpp78
-rw-r--r--libsolidity/AST.h29
-rw-r--r--libsolidity/ASTAnnotations.h97
-rw-r--r--libsolidity/ExpressionCompiler.cpp4
-rw-r--r--libsolidity/LValue.cpp4
-rw-r--r--libsolidity/LValue.h5
-rw-r--r--libsolidity/ReferencesResolver.cpp6
-rw-r--r--libsolidity/TypeChecker.cpp8
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)