mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			421 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			421 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    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);
 | 
						|
}
 | 
						|
 | 
						|
SourceUnitAnnotation& SourceUnit::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new SourceUnitAnnotation();
 | 
						|
	return static_cast<SourceUnitAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
ImportAnnotation& ImportDirective::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new ImportAnnotation();
 | 
						|
	return static_cast<ImportAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
TypePointer ImportDirective::type() const
 | 
						|
{
 | 
						|
	solAssert(!!annotation().sourceUnit, "");
 | 
						|
	return make_shared<ModuleType>(*annotation().sourceUnit);
 | 
						|
}
 | 
						|
 | 
						|
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 (FunctionDefinition const* f: definedFunctions())
 | 
						|
		if (f->isConstructor())
 | 
						|
			return f;
 | 
						|
	return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
FunctionDefinition const* ContractDefinition::fallbackFunction() const
 | 
						|
{
 | 
						|
	for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
 | 
						|
		for (FunctionDefinition const* f: contract->definedFunctions())
 | 
						|
			if (f->name().empty())
 | 
						|
				return f;
 | 
						|
	return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() const
 | 
						|
{
 | 
						|
	if (!m_interfaceEvents)
 | 
						|
	{
 | 
						|
		set<string> eventsSeen;
 | 
						|
		m_interfaceEvents.reset(new vector<EventDefinition const*>());
 | 
						|
		for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
 | 
						|
			for (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 (FunctionDefinition const* f: contract->definedFunctions())
 | 
						|
				if (f->isPartOfExternalInterface())
 | 
						|
					functions.push_back(make_shared<FunctionType>(*f, false));
 | 
						|
			for (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 (FunctionDefinition const* f: definedFunctions())
 | 
						|
			addInheritableMember(f);
 | 
						|
 | 
						|
		for (VariableDeclaration const* v: stateVariables())
 | 
						|
			addInheritableMember(v);
 | 
						|
 | 
						|
		for (StructDefinition const* s: definedStructs())
 | 
						|
			addInheritableMember(s);
 | 
						|
	}
 | 
						|
	return *m_inheritableMembers;
 | 
						|
}
 | 
						|
 | 
						|
TypePointer ContractDefinition::type() const
 | 
						|
{
 | 
						|
	return make_shared<TypeType>(make_shared<ContractType>(*this));
 | 
						|
}
 | 
						|
 | 
						|
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() 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() 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() 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() const
 | 
						|
{
 | 
						|
	return make_shared<FunctionType>(*this);
 | 
						|
}
 | 
						|
 | 
						|
string FunctionDefinition::externalSignature() const
 | 
						|
{
 | 
						|
	return FunctionType(*this).externalSignature();
 | 
						|
}
 | 
						|
 | 
						|
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new FunctionDefinitionAnnotation();
 | 
						|
	return static_cast<FunctionDefinitionAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
TypePointer ModifierDefinition::type() const
 | 
						|
{
 | 
						|
	return make_shared<ModifierType>(*this);
 | 
						|
}
 | 
						|
 | 
						|
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new ModifierDefinitionAnnotation();
 | 
						|
	return static_cast<ModifierDefinitionAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
TypePointer EventDefinition::type() const
 | 
						|
{
 | 
						|
	return make_shared<FunctionType>(*this);
 | 
						|
}
 | 
						|
 | 
						|
EventDefinitionAnnotation& EventDefinition::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new EventDefinitionAnnotation();
 | 
						|
	return static_cast<EventDefinitionAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
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() const
 | 
						|
{
 | 
						|
	return annotation().type;
 | 
						|
}
 | 
						|
 | 
						|
VariableDeclarationAnnotation& VariableDeclaration::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new VariableDeclarationAnnotation();
 | 
						|
	return static_cast<VariableDeclarationAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
StatementAnnotation& Statement::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new StatementAnnotation();
 | 
						|
	return static_cast<StatementAnnotation&>(*m_annotation);
 | 
						|
}
 | 
						|
 | 
						|
InlineAssemblyAnnotation& InlineAssembly::annotation() const
 | 
						|
{
 | 
						|
	if (!m_annotation)
 | 
						|
		m_annotation = new InlineAssemblyAnnotation();
 | 
						|
	return static_cast<InlineAssemblyAnnotation&>(*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);
 | 
						|
}
 |