aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis/ReferencesResolver.cpp
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-10-21 06:21:52 +0800
committerchriseth <c@ethdev.com>2015-10-21 06:46:01 +0800
commite3dffb611fe1736e3ffa170e6d8dc4dee17366bd (patch)
treeb2df13e7c4c16c01b6cdc7cd5c15932031185d95 /libsolidity/analysis/ReferencesResolver.cpp
parentd41f8b7ce702c3b25c48d27e2e895ccdcd04e4e0 (diff)
downloaddexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.tar
dexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.tar.gz
dexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.tar.bz2
dexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.tar.lz
dexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.tar.xz
dexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.tar.zst
dexon-solidity-e3dffb611fe1736e3ffa170e6d8dc4dee17366bd.zip
File reorganisation.
Diffstat (limited to 'libsolidity/analysis/ReferencesResolver.cpp')
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
new file mode 100644
index 00000000..fb7cdb3e
--- /dev/null
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -0,0 +1,234 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Component that resolves type names to types and annotates the AST accordingly.
+ */
+
+#include <libsolidity/analysis/ReferencesResolver.h>
+#include <libsolidity/ast/AST.h>
+#include <libsolidity/analysis/NameAndTypeResolver.h>
+#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/analysis/ConstantEvaluator.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+
+ReferencesResolver::ReferencesResolver(
+ ASTNode& _root,
+ NameAndTypeResolver& _resolver,
+ ContractDefinition const* _currentContract,
+ ParameterList const* _returnParameters,
+ bool _resolveInsideCode
+):
+ m_resolver(_resolver),
+ m_currentContract(_currentContract),
+ m_returnParameters(_returnParameters),
+ m_resolveInsideCode(_resolveInsideCode)
+{
+ _root.accept(*this);
+}
+
+bool ReferencesResolver::visit(Return const& _return)
+{
+ _return.annotation().functionReturnParameters = m_returnParameters;
+ return true;
+}
+
+bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
+{
+ Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
+ if (!declaration)
+ BOOST_THROW_EXCEPTION(
+ Error(Error::Type::DeclarationError) <<
+ errinfo_sourceLocation(_typeName.location()) <<
+ errinfo_comment("Identifier not found or not unique.")
+ );
+ _typeName.annotation().referencedDeclaration = declaration;
+ return true;
+}
+
+bool ReferencesResolver::visit(Identifier const& _identifier)
+{
+ auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
+ if (declarations.empty())
+ BOOST_THROW_EXCEPTION(
+ Error(Error::Type::DeclarationError) <<
+ errinfo_sourceLocation(_identifier.location()) <<
+ errinfo_comment("Undeclared identifier.")
+ );
+ else if (declarations.size() == 1)
+ {
+ _identifier.annotation().referencedDeclaration = declarations.front();
+ _identifier.annotation().contractScope = m_currentContract;
+ }
+ else
+ _identifier.annotation().overloadedDeclarations =
+ m_resolver.cleanedDeclarations(_identifier, declarations);
+ return false;
+}
+
+void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
+{
+ if (_variable.annotation().type)
+ return;
+
+ TypePointer type;
+ if (_variable.typeName())
+ {
+ type = typeFor(*_variable.typeName());
+ using Location = VariableDeclaration::Location;
+ Location loc = _variable.referenceLocation();
+ // 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()))
+ {
+ if (_variable.isExternalCallableParameter())
+ {
+ auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
+ if (contract.isLibrary())
+ {
+ if (loc == Location::Memory)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be calldata or storage for external "
+ "library functions (remove the \"memory\" keyword)."
+ ));
+ }
+ else
+ {
+ // force location of external function parameters (not return) to calldata
+ if (loc != Location::Default)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be calldata for external functions "
+ "(remove the \"memory\" or \"storage\" keyword)."
+ ));
+ }
+ if (loc == Location::Default)
+ type = ref->copyForLocation(DataLocation::CallData, true);
+ }
+ 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())
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "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);
+ }
+ else
+ {
+ if (_variable.isConstant())
+ {
+ if (loc != Location::Default && loc != Location::Memory)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Storage location has to be \"memory\" (or unspecified) for constants."
+ ));
+ loc = Location::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 (loc != Location::Default && !ref)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Storage location can only be given for array or struct types."
+ ));
+
+ if (!type)
+ BOOST_THROW_EXCEPTION(_variable.typeName()->createTypeError("Invalid type name."));
+
+ }
+ else if (!_variable.canHaveAutoType())
+ BOOST_THROW_EXCEPTION(_variable.createTypeError("Explicit type needed."));
+ // otherwise we have a "var"-declaration whose type is resolved by the first assignment
+
+ _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
+ BOOST_THROW_EXCEPTION(typeName->createTypeError(
+ "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)
+ BOOST_THROW_EXCEPTION(arrayType->baseType().createTypeError(
+ "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)
+ BOOST_THROW_EXCEPTION(length->createTypeError("Invalid array length."));
+ type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
+ }
+ else
+ type = make_shared<ArrayType>(DataLocation::Storage, baseType);
+ }
+
+ return _typeName.annotation().type = move(type);
+}
+