2014-10-07 16:25:04 +00:00
|
|
|
/*
|
2014-10-16 12:08:54 +00:00
|
|
|
This file is part of cpp-ethereum.
|
2014-10-07 16:25:04 +00:00
|
|
|
|
2014-10-16 12:08:54 +00:00
|
|
|
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.
|
2014-10-07 16:25:04 +00:00
|
|
|
|
2014-10-16 12:08:54 +00:00
|
|
|
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.
|
2014-10-07 16:25:04 +00:00
|
|
|
|
2014-10-16 12:08:54 +00:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2014-10-07 16:25:04 +00:00
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @author Christian <c@ethdev.com>
|
|
|
|
* @date 2014
|
|
|
|
* Solidity abstract syntax tree.
|
|
|
|
*/
|
|
|
|
|
2014-10-13 16:22:15 +00:00
|
|
|
#include <algorithm>
|
2015-06-18 14:35:25 +00:00
|
|
|
#include <functional>
|
2014-12-17 15:23:18 +00:00
|
|
|
#include <libsolidity/Utils.h>
|
2014-10-07 16:25:04 +00:00
|
|
|
#include <libsolidity/AST.h>
|
2014-10-10 14:37:54 +00:00
|
|
|
#include <libsolidity/ASTVisitor.h>
|
2014-10-15 12:45:51 +00:00
|
|
|
#include <libsolidity/Exceptions.h>
|
2014-12-08 12:33:13 +00:00
|
|
|
#include <libsolidity/AST_accept.h>
|
2014-10-10 14:37:54 +00:00
|
|
|
|
2015-05-19 17:51:38 +00:00
|
|
|
#include <libdevcore/SHA3.h>
|
2015-01-07 15:39:21 +00:00
|
|
|
|
2014-10-24 17:06:30 +00:00
|
|
|
using namespace std;
|
2015-09-16 14:56:30 +00:00
|
|
|
using namespace dev;
|
|
|
|
using namespace dev::solidity;
|
2014-10-24 17:06:30 +00:00
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
ASTNode::ASTNode(SourceLocation const& _location):
|
|
|
|
m_location(_location)
|
2014-10-16 12:08:54 +00:00
|
|
|
{
|
2014-10-23 17:22:30 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
ASTNode::~ASTNode()
|
2015-01-22 00:02:38 +00:00
|
|
|
{
|
2015-09-21 16:55:58 +00:00
|
|
|
delete m_annotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTAnnotation& ASTNode::annotation() const
|
|
|
|
{
|
|
|
|
if (!m_annotation)
|
|
|
|
m_annotation = new ASTAnnotation();
|
|
|
|
return *m_annotation;
|
2015-01-22 00:02:38 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
TypeError ASTNode::createTypeError(string const& _description) const
|
2014-12-15 15:09:50 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
return TypeError() << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
2014-12-15 15:09:50 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
2014-11-11 16:41:48 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
auto exportedFunctionList = interfaceFunctionList();
|
2015-01-23 15:37:06 +00:00
|
|
|
|
2015-01-29 15:48:39 +00:00
|
|
|
map<FixedHash<4>, FunctionTypePointer> exportedFunctions;
|
2015-01-23 15:37:06 +00:00
|
|
|
for (auto const& it: exportedFunctionList)
|
2015-01-29 15:39:30 +00:00
|
|
|
exportedFunctions.insert(it);
|
2015-01-22 16:40:22 +00:00
|
|
|
|
2015-09-10 08:17:17 +00:00
|
|
|
solAssert(
|
|
|
|
exportedFunctionList.size() == exportedFunctions.size(),
|
2015-09-08 12:30:21 +00:00
|
|
|
"Hash collision at Function Definition Hash calculation"
|
|
|
|
);
|
2014-11-11 16:41:48 +00:00
|
|
|
|
|
|
|
return exportedFunctions;
|
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
FunctionDefinition const* ContractDefinition::constructor() const
|
2014-12-12 15:49:26 +00:00
|
|
|
{
|
|
|
|
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
|
2015-01-20 14:58:04 +00:00
|
|
|
if (f->isConstructor())
|
2014-12-12 15:49:26 +00:00
|
|
|
return f.get();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
FunctionDefinition const* ContractDefinition::fallbackFunction() const
|
2015-01-29 21:50:20 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
|
|
|
|
if (f->name().empty())
|
2015-01-29 21:50:20 +00:00
|
|
|
return f.get();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const
|
2015-01-31 13:41:11 +00:00
|
|
|
{
|
|
|
|
if (!m_interfaceEvents)
|
|
|
|
{
|
|
|
|
set<string> eventsSeen;
|
2015-05-04 15:18:01 +00:00
|
|
|
m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>());
|
2015-09-16 14:56:30 +00:00
|
|
|
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<EventDefinition> const& e: contract->events())
|
|
|
|
if (eventsSeen.count(e->name()) == 0)
|
2015-01-31 13:41:11 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
eventsSeen.insert(e->name());
|
2015-01-31 13:41:11 +00:00
|
|
|
m_interfaceEvents->push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *m_interfaceEvents;
|
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList() const
|
2015-01-16 16:50:10 +00:00
|
|
|
{
|
|
|
|
if (!m_interfaceFunctionList)
|
|
|
|
{
|
|
|
|
set<string> functionsSeen;
|
2015-03-01 03:34:39 +00:00
|
|
|
set<string> signaturesSeen;
|
2015-01-29 16:28:14 +00:00
|
|
|
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
|
2015-09-16 14:56:30 +00:00
|
|
|
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
2015-01-22 16:40:22 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
|
2015-03-01 03:34:39 +00:00
|
|
|
{
|
2015-06-26 14:52:30 +00:00
|
|
|
if (!f->isPartOfExternalInterface())
|
|
|
|
continue;
|
2015-04-07 15:08:49 +00:00
|
|
|
string functionSignature = f->externalSignature();
|
2015-06-26 14:52:30 +00:00
|
|
|
if (signaturesSeen.count(functionSignature) == 0)
|
2015-01-16 16:50:10 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
functionsSeen.insert(f->name());
|
2015-03-01 03:34:39 +00:00
|
|
|
signaturesSeen.insert(functionSignature);
|
|
|
|
FixedHash<4> hash(dev::sha3(functionSignature));
|
2015-01-29 15:39:30 +00:00
|
|
|
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*f, false)));
|
2015-01-16 16:50:10 +00:00
|
|
|
}
|
2015-03-01 03:34:39 +00:00
|
|
|
}
|
2015-01-22 16:40:22 +00:00
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<VariableDeclaration> const& v: contract->stateVariables())
|
|
|
|
if (functionsSeen.count(v->name()) == 0 && v->isPartOfExternalInterface())
|
2015-01-22 16:40:22 +00:00
|
|
|
{
|
|
|
|
FunctionType ftype(*v);
|
2015-09-16 14:56:30 +00:00
|
|
|
solAssert(!!v->annotation().type.get(), "");
|
2015-08-31 16:44:29 +00:00
|
|
|
functionsSeen.insert(v->name());
|
|
|
|
FixedHash<4> hash(dev::sha3(ftype.externalSignature(v->name())));
|
2015-01-29 15:39:30 +00:00
|
|
|
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*v)));
|
2015-01-22 16:40:22 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-16 16:50:10 +00:00
|
|
|
}
|
|
|
|
return *m_interfaceFunctionList;
|
2015-01-14 09:16:58 +00:00
|
|
|
}
|
|
|
|
|
2015-06-19 13:40:09 +00:00
|
|
|
string const& ContractDefinition::devDocumentation() const
|
2015-06-15 13:21:23 +00:00
|
|
|
{
|
2015-06-19 13:40:09 +00:00
|
|
|
return m_devDocumentation;
|
2015-06-15 13:21:23 +00:00
|
|
|
}
|
|
|
|
|
2015-06-19 13:40:09 +00:00
|
|
|
string const& ContractDefinition::userDocumentation() const
|
2015-06-15 13:21:23 +00:00
|
|
|
{
|
2015-06-19 13:40:09 +00:00
|
|
|
return m_userDocumentation;
|
2015-06-15 13:21:23 +00:00
|
|
|
}
|
|
|
|
|
2015-06-19 13:40:09 +00:00
|
|
|
void ContractDefinition::setDevDocumentation(string const& _devDocumentation)
|
2015-06-15 13:21:23 +00:00
|
|
|
{
|
2015-06-19 13:40:09 +00:00
|
|
|
m_devDocumentation = _devDocumentation;
|
2015-06-15 13:21:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ContractDefinition::setUserDocumentation(string const& _userDocumentation)
|
|
|
|
{
|
|
|
|
m_userDocumentation = _userDocumentation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
|
2015-02-25 19:35:55 +00:00
|
|
|
{
|
|
|
|
if (!m_inheritableMembers)
|
|
|
|
{
|
|
|
|
set<string> memberSeen;
|
2015-03-02 11:08:32 +00:00
|
|
|
m_inheritableMembers.reset(new vector<Declaration const*>());
|
|
|
|
auto addInheritableMember = [&](Declaration const* _decl)
|
2015-02-25 19:35:55 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts())
|
2015-02-27 10:35:25 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
memberSeen.insert(_decl->name());
|
2015-02-28 17:30:33 +00:00
|
|
|
m_inheritableMembers->push_back(_decl);
|
|
|
|
}
|
|
|
|
};
|
2015-02-27 10:35:25 +00:00
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<FunctionDefinition> const& f: definedFunctions())
|
2015-03-02 11:08:32 +00:00
|
|
|
addInheritableMember(f.get());
|
2015-02-25 19:35:55 +00:00
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<VariableDeclaration> const& v: stateVariables())
|
2015-03-02 11:08:32 +00:00
|
|
|
addInheritableMember(v.get());
|
2015-02-26 11:11:54 +00:00
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
for (ASTPointer<StructDefinition> const& s: definedStructs())
|
2015-03-02 11:08:32 +00:00
|
|
|
addInheritableMember(s.get());
|
2015-02-25 19:35:55 +00:00
|
|
|
}
|
|
|
|
return *m_inheritableMembers;
|
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const
|
2015-02-10 12:40:21 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
return make_shared<TypeType>(make_shared<ContractType>(*this), m_currentContract);
|
2015-01-19 20:05:47 +00:00
|
|
|
}
|
|
|
|
|
2015-09-21 16:55:58 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
TypePointer StructDefinition::type(ContractDefinition const*) const
|
2015-01-22 00:02:38 +00:00
|
|
|
{
|
|
|
|
return make_shared<TypeType>(make_shared<StructType>(*this));
|
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
TypePointer EnumValue::type(ContractDefinition const*) const
|
2014-12-03 06:46:55 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
|
|
|
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
|
|
|
|
return make_shared<EnumType>(*parentDef);
|
2014-12-03 06:46:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
TypePointer EnumDefinition::type(ContractDefinition const*) const
|
2015-02-09 17:08:56 +00:00
|
|
|
{
|
2015-02-11 15:37:46 +00:00
|
|
|
return make_shared<TypeType>(make_shared<EnumType>(*this));
|
2015-02-09 17:08:56 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 16:44:29 +00:00
|
|
|
TypePointer FunctionDefinition::type(ContractDefinition const*) const
|
2015-01-22 00:02:38 +00:00
|
|
|
{
|
|
|
|
return make_shared<FunctionType>(*this);
|
|
|
|
}
|
|
|
|
|
2015-03-27 12:28:32 +00:00
|
|
|
string FunctionDefinition::externalSignature() const
|
2015-01-06 16:42:38 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
return FunctionType(*this).externalSignature(name());
|
2015-01-06 16:42:38 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
TypePointer ModifierDefinition::type(ContractDefinition const*) const
|
2015-01-22 00:02:38 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
return make_shared<ModifierType>(*this);
|
2015-02-14 00:22:44 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
TypePointer EventDefinition::type(ContractDefinition const*) const
|
2015-02-17 15:21:38 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
return make_shared<FunctionType>(*this);
|
|
|
|
}
|
2015-03-08 22:26:36 +00:00
|
|
|
|
2015-09-21 16:55:58 +00:00
|
|
|
UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const
|
|
|
|
{
|
|
|
|
if (!m_annotation)
|
|
|
|
m_annotation = new UserDefinedTypeNameAnnotation();
|
|
|
|
return static_cast<UserDefinedTypeNameAnnotation&>(*m_annotation);
|
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
bool VariableDeclaration::isLValue() const
|
|
|
|
{
|
|
|
|
// External function parameters and constant declared variables are Read-Only
|
|
|
|
return !isExternalCallableParameter() && !m_isConstant;
|
2015-02-17 15:21:38 +00:00
|
|
|
}
|
|
|
|
|
2015-06-09 12:26:08 +00:00
|
|
|
bool VariableDeclaration::isCallableParameter() const
|
2015-06-05 09:07:50 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
|
2015-06-09 12:26:08 +00:00
|
|
|
if (!callable)
|
2015-06-05 09:07:50 +00:00
|
|
|
return false;
|
2015-08-31 16:44:29 +00:00
|
|
|
for (auto const& variable: callable->parameters())
|
2015-06-05 09:07:50 +00:00
|
|
|
if (variable.get() == this)
|
|
|
|
return true;
|
2015-08-31 16:44:29 +00:00
|
|
|
if (callable->returnParameterList())
|
|
|
|
for (auto const& variable: callable->returnParameterList()->parameters())
|
2015-06-09 12:26:08 +00:00
|
|
|
if (variable.get() == this)
|
|
|
|
return true;
|
2015-06-05 09:07:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-09 12:26:08 +00:00
|
|
|
bool VariableDeclaration::isExternalCallableParameter() const
|
2015-02-14 00:22:44 +00:00
|
|
|
{
|
2015-08-31 16:44:29 +00:00
|
|
|
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
|
|
|
|
if (!callable || callable->visibility() != Declaration::Visibility::External)
|
2015-02-14 00:22:44 +00:00
|
|
|
return false;
|
2015-08-31 16:44:29 +00:00
|
|
|
for (auto const& variable: callable->parameters())
|
2015-02-14 00:22:44 +00:00
|
|
|
if (variable.get() == this)
|
|
|
|
return true;
|
|
|
|
return false;
|
2015-01-22 00:02:38 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
bool VariableDeclaration::canHaveAutoType() const
|
2015-01-22 00:02:38 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
|
|
|
|
return (!!callable && !isCallableParameter());
|
2014-10-13 16:22:15 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 14:56:30 +00:00
|
|
|
TypePointer VariableDeclaration::type(ContractDefinition const*) const
|
2014-10-13 16:22:15 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
return annotation().type;
|
2014-10-16 12:08:54 +00:00
|
|
|
}
|
2015-09-21 16:55:58 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|