aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis/ReferencesResolver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/analysis/ReferencesResolver.cpp')
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp184
1 files changed, 86 insertions, 98 deletions
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index e5b1c52b..2fe53e8b 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -31,28 +31,6 @@ using namespace dev;
using namespace dev::solidity;
-bool ReferencesResolver::visit(Return const& _return)
-{
- _return.annotation().functionReturnParameters = m_returnParameters;
- return true;
-}
-
-void ReferencesResolver::endVisit(NewExpression const& _new)
-{
- typeFor(_new.typeName());
-}
-
-bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
-{
- Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
- if (!declaration)
- fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
-
- _typeName.annotation().referencedDeclaration = declaration;
-
- return true;
-}
-
bool ReferencesResolver::resolve(ASTNode const& _root)
{
try
@@ -79,6 +57,67 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
return false;
}
+bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
+{
+ _typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
+ return true;
+}
+
+void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
+{
+ Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
+ if (!declaration)
+ fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
+
+ _typeName.annotation().referencedDeclaration = declaration;
+
+ if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
+ _typeName.annotation().type = make_shared<StructType>(*structDef);
+ else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
+ _typeName.annotation().type = make_shared<EnumType>(*enumDef);
+ else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
+ _typeName.annotation().type = make_shared<ContractType>(*contract);
+ else
+ fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
+}
+
+void ReferencesResolver::endVisit(Mapping const& _typeName)
+{
+ TypePointer keyType = _typeName.keyType().annotation().type;
+ TypePointer valueType = _typeName.valueType().annotation().type;
+ // Convert key type to memory.
+ keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
+ // Convert value type to storage reference.
+ valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
+ _typeName.annotation().type = make_shared<MappingType>(keyType, valueType);
+}
+
+void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
+{
+ TypePointer baseType = _typeName.baseType().annotation().type;
+ if (baseType->storageBytes() == 0)
+ fatalTypeError(_typeName.baseType().location(), "Illegal base type of storage size zero for array.");
+ if (Expression const* length = _typeName.length())
+ {
+ if (!length->annotation().type)
+ ConstantEvaluator e(*length);
+
+ auto const* lengthType = dynamic_cast<IntegerConstantType const*>(length->annotation().type.get());
+ if (!lengthType)
+ fatalTypeError(length->location(), "Invalid array length.");
+ else
+ _typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
+ }
+ else
+ _typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType);
+}
+
+bool ReferencesResolver::visit(Return const& _return)
+{
+ _return.annotation().functionReturnParameters = m_returnParameters;
+ return true;
+}
+
void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
{
if (_variable.annotation().type)
@@ -87,21 +126,23 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
TypePointer type;
if (_variable.typeName())
{
- type = typeFor(*_variable.typeName());
+ type = _variable.typeName()->annotation().type;
using Location = VariableDeclaration::Location;
- Location loc = _variable.referenceLocation();
+ Location varLoc = _variable.referenceLocation();
+ DataLocation typeLoc = DataLocation::Memory;
// References are forced to calldata for external function parameters (not return)
// and memory for parameters (also return) of publicly visible functions.
// They default to memory for function parameters and storage for local variables.
// As an exception, "storage" is allowed for library functions.
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
{
+ bool isPointer = true;
if (_variable.isExternalCallableParameter())
{
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
if (contract.isLibrary())
{
- if (loc == Location::Memory)
+ if (varLoc == Location::Memory)
fatalTypeError(_variable.location(),
"Location has to be calldata or storage for external "
"library functions (remove the \"memory\" keyword)."
@@ -110,50 +151,52 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
else
{
// force location of external function parameters (not return) to calldata
- if (loc != Location::Default)
+ if (varLoc != Location::Default)
fatalTypeError(_variable.location(),
"Location has to be calldata for external functions "
"(remove the \"memory\" or \"storage\" keyword)."
);
}
- if (loc == Location::Default)
- type = ref->copyForLocation(DataLocation::CallData, true);
+ if (varLoc == Location::Default)
+ typeLoc = DataLocation::CallData;
+ else
+ typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
{
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
// force locations of public or external function (return) parameters to memory
- if (loc == Location::Storage && !contract.isLibrary())
+ if (varLoc == Location::Storage && !contract.isLibrary())
fatalTypeError(_variable.location(),
"Location has to be memory for publicly visible functions "
"(remove the \"storage\" keyword)."
);
- if (loc == Location::Default || !contract.isLibrary())
- type = ref->copyForLocation(DataLocation::Memory, true);
+ if (varLoc == Location::Default || !contract.isLibrary())
+ typeLoc = DataLocation::Memory;
+ else
+ typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
else
{
if (_variable.isConstant())
{
- if (loc != Location::Default && loc != Location::Memory)
+ if (varLoc != Location::Default && varLoc != Location::Memory)
fatalTypeError(
_variable.location(),
"Storage location has to be \"memory\" (or unspecified) for constants."
);
- loc = Location::Memory;
+ typeLoc = DataLocation::Memory;
}
- if (loc == Location::Default)
- loc = _variable.isCallableParameter() ? Location::Memory : Location::Storage;
- bool isPointer = !_variable.isStateVariable();
- type = ref->copyForLocation(
- loc == Location::Memory ?
- DataLocation::Memory :
- DataLocation::Storage,
- isPointer
- );
+ else if (varLoc == Location::Default)
+ typeLoc = _variable.isCallableParameter() ? DataLocation::Memory : DataLocation::Storage;
+ else
+ typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
+ isPointer = !_variable.isStateVariable();
}
+
+ type = ref->copyForLocation(typeLoc, isPointer);
}
- else if (loc != Location::Default && !ref)
+ else if (varLoc != Location::Default && !ref)
fatalTypeError(_variable.location(), "Storage location can only be given for array or struct types.");
if (!type)
@@ -167,61 +210,6 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
_variable.annotation().type = type;
}
-TypePointer ReferencesResolver::typeFor(TypeName const& _typeName)
-{
- if (_typeName.annotation().type)
- return _typeName.annotation().type;
-
- TypePointer type;
- if (auto elemTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
- type = Type::fromElementaryTypeName(elemTypeName->typeName());
- else if (auto typeName = dynamic_cast<UserDefinedTypeName const*>(&_typeName))
- {
- Declaration const* declaration = typeName->annotation().referencedDeclaration;
- solAssert(!!declaration, "");
-
- if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
- type = make_shared<StructType>(*structDef);
- else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
- type = make_shared<EnumType>(*enumDef);
- else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
- type = make_shared<ContractType>(*contract);
- else
- fatalTypeError(typeName->location(), "Name has to refer to a struct, enum or contract.");
- }
- else if (auto mapping = dynamic_cast<Mapping const*>(&_typeName))
- {
- TypePointer keyType = typeFor(mapping->keyType());
- TypePointer valueType = typeFor(mapping->valueType());
- // Convert key type to memory.
- keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
- // Convert value type to storage reference.
- valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
- type = make_shared<MappingType>(keyType, valueType);
- }
- else if (auto arrayType = dynamic_cast<ArrayTypeName const*>(&_typeName))
- {
- TypePointer baseType = typeFor(arrayType->baseType());
- if (baseType->storageBytes() == 0)
- fatalTypeError(arrayType->baseType().location(), "Illegal base type of storage size zero for array.");
- if (Expression const* length = arrayType->length())
- {
- if (!length->annotation().type)
- ConstantEvaluator e(*length);
-
- auto const* lengthType = dynamic_cast<IntegerConstantType const*>(length->annotation().type.get());
- if (!lengthType)
- fatalTypeError(length->location(), "Invalid array length.");
- else
- type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
- }
- else
- type = make_shared<ArrayType>(DataLocation::Storage, baseType);
- }
-
- return _typeName.annotation().type = move(type);
-}
-
void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description)
{
auto err = make_shared<Error>(Error::Type::TypeError);