diff options
Diffstat (limited to 'libsolidity/ast/AST.cpp')
-rw-r--r-- | libsolidity/ast/AST.cpp | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp new file mode 100644 index 00000000..71d80a36 --- /dev/null +++ b/libsolidity/ast/AST.cpp @@ -0,0 +1,365 @@ +/* + 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 2014 + * Solidity abstract syntax tree. + */ + +#include <algorithm> +#include <functional> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/ast/AST_accept.h> + +#include <libdevcore/SHA3.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +ASTNode::ASTNode(SourceLocation const& _location): + m_location(_location) +{ +} + +ASTNode::~ASTNode() +{ + delete m_annotation; +} + +ASTAnnotation& ASTNode::annotation() const +{ + if (!m_annotation) + m_annotation = new ASTAnnotation(); + return *m_annotation; +} + +Error ASTNode::createTypeError(string const& _description) const +{ + return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description); +} + +map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const +{ + auto exportedFunctionList = interfaceFunctionList(); + + map<FixedHash<4>, FunctionTypePointer> exportedFunctions; + for (auto const& it: exportedFunctionList) + exportedFunctions.insert(it); + + solAssert( + exportedFunctionList.size() == exportedFunctions.size(), + "Hash collision at Function Definition Hash calculation" + ); + + return exportedFunctions; +} + +FunctionDefinition const* ContractDefinition::constructor() const +{ + for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions) + if (f->isConstructor()) + return f.get(); + return nullptr; +} + +FunctionDefinition const* ContractDefinition::fallbackFunction() const +{ + for (ContractDefinition const* contract: annotation().linearizedBaseContracts) + for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions()) + if (f->name().empty()) + return f.get(); + return nullptr; +} + +vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const +{ + if (!m_interfaceEvents) + { + set<string> eventsSeen; + m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>()); + for (ContractDefinition const* contract: annotation().linearizedBaseContracts) + for (ASTPointer<EventDefinition> const& e: contract->events()) + if (eventsSeen.count(e->name()) == 0) + { + eventsSeen.insert(e->name()); + m_interfaceEvents->push_back(e); + } + } + return *m_interfaceEvents; +} + +vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList() const +{ + if (!m_interfaceFunctionList) + { + set<string> functionsSeen; + set<string> signaturesSeen; + m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>()); + for (ContractDefinition const* contract: annotation().linearizedBaseContracts) + { + vector<FunctionTypePointer> functions; + for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions()) + if (f->isPartOfExternalInterface()) + functions.push_back(make_shared<FunctionType>(*f, false)); + for (ASTPointer<VariableDeclaration> const& v: contract->stateVariables()) + if (v->isPartOfExternalInterface()) + functions.push_back(make_shared<FunctionType>(*v)); + for (FunctionTypePointer const& fun: functions) + { + if (!fun->interfaceFunctionType()) + // Fails hopefully because we already registered the error + continue; + string functionSignature = fun->externalSignature(); + if (signaturesSeen.count(functionSignature) == 0) + { + signaturesSeen.insert(functionSignature); + FixedHash<4> hash(dev::sha3(functionSignature)); + m_interfaceFunctionList->push_back(make_pair(hash, fun)); + } + } + } + } + return *m_interfaceFunctionList; +} + +string const& ContractDefinition::devDocumentation() const +{ + return m_devDocumentation; +} + +string const& ContractDefinition::userDocumentation() const +{ + return m_userDocumentation; +} + +void ContractDefinition::setDevDocumentation(string const& _devDocumentation) +{ + m_devDocumentation = _devDocumentation; +} + +void ContractDefinition::setUserDocumentation(string const& _userDocumentation) +{ + m_userDocumentation = _userDocumentation; +} + + +vector<Declaration const*> const& ContractDefinition::inheritableMembers() const +{ + if (!m_inheritableMembers) + { + set<string> memberSeen; + m_inheritableMembers.reset(new vector<Declaration const*>()); + auto addInheritableMember = [&](Declaration const* _decl) + { + if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts()) + { + memberSeen.insert(_decl->name()); + m_inheritableMembers->push_back(_decl); + } + }; + + for (ASTPointer<FunctionDefinition> const& f: definedFunctions()) + addInheritableMember(f.get()); + + for (ASTPointer<VariableDeclaration> const& v: stateVariables()) + addInheritableMember(v.get()); + + for (ASTPointer<StructDefinition> const& s: definedStructs()) + addInheritableMember(s.get()); + } + return *m_inheritableMembers; +} + +TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const +{ + 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)); +} + +TypeDeclarationAnnotation& StructDefinition::annotation() const +{ + if (!m_annotation) + m_annotation = new TypeDeclarationAnnotation(); + return static_cast<TypeDeclarationAnnotation&>(*m_annotation); +} + +TypePointer EnumValue::type(ContractDefinition const*) const +{ + auto parentDef = dynamic_cast<EnumDefinition const*>(scope()); + solAssert(parentDef, "Enclosing Scope of EnumValue was not set"); + return make_shared<EnumType>(*parentDef); +} + +TypePointer EnumDefinition::type(ContractDefinition const*) const +{ + return make_shared<TypeType>(make_shared<EnumType>(*this)); +} + +TypeDeclarationAnnotation& EnumDefinition::annotation() const +{ + if (!m_annotation) + m_annotation = new TypeDeclarationAnnotation(); + return static_cast<TypeDeclarationAnnotation&>(*m_annotation); +} + +TypePointer FunctionDefinition::type(ContractDefinition const*) const +{ + return make_shared<FunctionType>(*this); +} + +string FunctionDefinition::externalSignature() const +{ + return FunctionType(*this).externalSignature(); +} + +TypePointer ModifierDefinition::type(ContractDefinition const*) const +{ + return make_shared<ModifierType>(*this); +} + +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 + return !isExternalCallableParameter() && !m_isConstant; +} + +bool VariableDeclaration::isCallableParameter() const +{ + auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()); + if (!callable) + return false; + for (auto const& variable: callable->parameters()) + if (variable.get() == this) + return true; + if (callable->returnParameterList()) + for (auto const& variable: callable->returnParameterList()->parameters()) + if (variable.get() == this) + return true; + return false; +} + +bool VariableDeclaration::isExternalCallableParameter() const +{ + auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()); + if (!callable || callable->visibility() != Declaration::Visibility::External) + return false; + for (auto const& variable: callable->parameters()) + if (variable.get() == this) + return true; + return false; +} + +bool VariableDeclaration::canHaveAutoType() const +{ + auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()); + return (!!callable && !isCallableParameter()); +} + +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); +} + +VariableDeclarationStatementAnnotation& VariableDeclarationStatement::annotation() const +{ + if (!m_annotation) + m_annotation = new VariableDeclarationStatementAnnotation(); + return static_cast<VariableDeclarationStatementAnnotation&>(*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); +} |