solidity/libsolidity/ast/AST.cpp

394 lines
11 KiB
C++
Raw Normal View History

/*
2014-10-16 12:08:54 +00:00
This file is part of cpp-ethereum.
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-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-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/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity abstract syntax tree.
*/
2014-10-13 16:22:15 +00:00
#include <algorithm>
#include <functional>
2015-10-20 22:21:52 +00:00
#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>
2014-10-24 17:06:30 +00:00
using namespace std;
using namespace dev;
using namespace dev::solidity;
2014-10-24 17:06: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
}
ASTNode::~ASTNode()
{
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;
}
Error ASTNode::createTypeError(string const& _description) const
{
return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
}
2015-08-31 16:44:29 +00:00
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
{
2015-08-31 16:44:29 +00:00
auto exportedFunctionList = interfaceFunctionList();
map<FixedHash<4>, FunctionTypePointer> exportedFunctions;
for (auto const& it: exportedFunctionList)
exportedFunctions.insert(it);
2015-09-10 08:17:17 +00:00
solAssert(
exportedFunctionList.size() == exportedFunctions.size(),
"Hash collision at Function Definition Hash calculation"
);
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)
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
{
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
{
if (!m_interfaceEvents)
{
set<string> eventsSeen;
2015-05-04 15:18:01 +00:00
m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>());
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-08-31 16:44:29 +00:00
eventsSeen.insert(e->name());
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
{
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>>());
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
{
vector<FunctionTypePointer> functions;
2015-08-31 16:44:29 +00:00
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)
2015-03-01 03:34:39 +00:00
{
if (!fun->interfaceFunctionType())
// Fails hopefully because we already registered the error
continue;
string functionSignature = fun->externalSignature();
if (signaturesSeen.count(functionSignature) == 0)
{
2015-03-01 03:34:39 +00:00
signaturesSeen.insert(functionSignature);
FixedHash<4> hash(dev::sha3(functionSignature));
m_interfaceFunctionList->push_back(make_pair(hash, fun));
}
2015-03-01 03:34:39 +00:00
}
}
}
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;
}
2015-08-31 16:44:29 +00:00
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)
{
2015-08-31 16:44:29 +00:00
if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts())
{
2015-08-31 16:44:29 +00:00
memberSeen.insert(_decl->name());
m_inheritableMembers->push_back(_decl);
}
};
2015-08-31 16:44:29 +00:00
for (ASTPointer<FunctionDefinition> const& f: definedFunctions())
addInheritableMember(f.get());
2015-08-31 16:44:29 +00:00
for (ASTPointer<VariableDeclaration> const& v: stateVariables())
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())
addInheritableMember(s.get());
}
return *m_inheritableMembers;
}
TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const
2015-02-10 12:40:21 +00:00
{
return make_shared<TypeType>(make_shared<ContractType>(*this), m_currentContract);
}
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
{
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
2014-12-03 06:46:55 +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
{
return make_shared<TypeType>(make_shared<EnumType>(*this));
2015-02-09 17:08:56 +00:00
}
TypeDeclarationAnnotation& EnumDefinition::annotation() const
{
if (!m_annotation)
m_annotation = new TypeDeclarationAnnotation();
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
}
2015-08-31 16:44:29 +00:00
TypePointer FunctionDefinition::type(ContractDefinition const*) const
{
return make_shared<FunctionType>(*this);
}
string FunctionDefinition::externalSignature() const
{
return FunctionType(*this).externalSignature();
}
2015-10-26 14:13:36 +00:00
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
{
if (!m_annotation)
m_annotation = new FunctionDefinitionAnnotation();
return static_cast<FunctionDefinitionAnnotation&>(*m_annotation);
}
TypePointer ModifierDefinition::type(ContractDefinition const*) const
{
return make_shared<ModifierType>(*this);
}
2015-10-26 14:13:36 +00:00
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
{
if (!m_annotation)
m_annotation = new ModifierDefinitionAnnotation();
return static_cast<ModifierDefinitionAnnotation&>(*m_annotation);
}
TypePointer EventDefinition::type(ContractDefinition const*) const
{
return make_shared<FunctionType>(*this);
}
2015-03-08 22:26:36 +00:00
2015-10-26 14:13:36 +00:00
EventDefinitionAnnotation& EventDefinition::annotation() const
{
if (!m_annotation)
m_annotation = new EventDefinitionAnnotation();
return static_cast<EventDefinitionAnnotation&>(*m_annotation);
}
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);
}
bool VariableDeclaration::isLValue() const
{
// External function parameters and constant declared variables are Read-Only
return !isExternalCallableParameter() && !m_isConstant;
}
bool VariableDeclaration::isCallableParameter() const
{
2015-08-31 16:44:29 +00:00
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
if (!callable)
return false;
2015-08-31 16:44:29 +00:00
for (auto const& variable: callable->parameters())
if (variable.get() == this)
return true;
2015-08-31 16:44:29 +00:00
if (callable->returnParameterList())
for (auto const& variable: callable->returnParameterList()->parameters())
if (variable.get() == this)
return true;
return false;
}
bool VariableDeclaration::isExternalCallableParameter() const
{
2015-08-31 16:44:29 +00:00
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
if (!callable || callable->visibility() != Declaration::Visibility::External)
return false;
2015-08-31 16:44:29 +00:00
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());
2014-10-13 16:22:15 +00:00
}
TypePointer VariableDeclaration::type(ContractDefinition const*) const
2014-10-13 16:22:15 +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);
}
2015-10-26 16:20:29 +00:00
StatementAnnotation& Statement::annotation() const
{
if (!m_annotation)
m_annotation = new StatementAnnotation();
return static_cast<StatementAnnotation&>(*m_annotation);
}
2015-09-21 16:55:58 +00:00
ReturnAnnotation& Return::annotation() const
{
if (!m_annotation)
m_annotation = new ReturnAnnotation();
return static_cast<ReturnAnnotation&>(*m_annotation);
}
2015-10-09 18:44:56 +00:00
VariableDeclarationStatementAnnotation& VariableDeclarationStatement::annotation() const
{
if (!m_annotation)
m_annotation = new VariableDeclarationStatementAnnotation();
return static_cast<VariableDeclarationStatementAnnotation&>(*m_annotation);
}
2015-09-21 16:55:58 +00:00
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);
}