/*
	This file is part of solidity.
	solidity 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.
	solidity 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 solidity.  If not, see .
*/
/**
 * @author Christian 
 * @date 2014
 * Solidity abstract syntax tree.
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
using namespace solidity;
using namespace solidity::frontend;
ASTNode::ASTNode(int64_t _id, SourceLocation const& _location):
	m_id(_id),
	m_location(_location)
{
}
ASTAnnotation& ASTNode::annotation() const
{
	if (!m_annotation)
		m_annotation = make_unique();
	return *m_annotation;
}
SourceUnitAnnotation& SourceUnit::annotation() const
{
	return initAnnotation();
}
set SourceUnit::referencedSourceUnits(bool _recurse, set _skipList) const
{
	set sourceUnits;
	for (ImportDirective const* importDirective: filteredNodes(nodes()))
	{
		auto const& sourceUnit = importDirective->annotation().sourceUnit;
		if (!_skipList.count(sourceUnit))
		{
			_skipList.insert(sourceUnit);
			sourceUnits.insert(sourceUnit);
			if (_recurse)
				sourceUnits += sourceUnit->referencedSourceUnits(true, _skipList);
		}
	}
	return sourceUnits;
}
ImportAnnotation& ImportDirective::annotation() const
{
	return initAnnotation();
}
TypePointer ImportDirective::type() const
{
	solAssert(!!annotation().sourceUnit, "");
	return TypeProvider::module(*annotation().sourceUnit);
}
vector ContractDefinition::stateVariablesIncludingInherited() const
{
	vector stateVars;
	for (auto const& contract: annotation().linearizedBaseContracts)
		for (auto var: contract->stateVariables())
			if (*contract == *this || var->isVisibleInDerivedContracts())
				stateVars.push_back(var);
	return stateVars;
}
map, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
{
	auto exportedFunctionList = interfaceFunctionList();
	map, 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;
}
bool ContractDefinition::constructorIsPublic() const
{
	FunctionDefinition const* f = constructor();
	return !f || f->isPublic();
}
bool ContractDefinition::canBeDeployed() const
{
	return constructorIsPublic() && !abstract() && !isInterface();
}
FunctionDefinition const* ContractDefinition::fallbackFunction() const
{
	for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
		for (FunctionDefinition const* f: contract->definedFunctions())
			if (f->isFallback())
				return f;
	return nullptr;
}
FunctionDefinition const* ContractDefinition::receiveFunction() const
{
	for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
		for (FunctionDefinition const* f: contract->definedFunctions())
			if (f->isReceive())
				return f;
	return nullptr;
}
vector const& ContractDefinition::interfaceEvents() const
{
	if (!m_interfaceEvents)
	{
		set eventsSeen;
		m_interfaceEvents = make_unique>();
		for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
			for (EventDefinition const* e: contract->events())
			{
				/// NOTE: this requires the "internal" version of an Event,
				///       though here internal strictly refers to visibility,
				///       and not to function encoding (jump vs. call)
				auto const& function = e->functionType(true);
				solAssert(function, "");
				string eventSignature = function->externalSignature();
				if (eventsSeen.count(eventSignature) == 0)
				{
					eventsSeen.insert(eventSignature);
					m_interfaceEvents->push_back(e);
				}
			}
	}
	return *m_interfaceEvents;
}
vector, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList() const
{
	if (!m_interfaceFunctionList)
	{
		set signaturesSeen;
		m_interfaceFunctionList = make_unique, FunctionTypePointer>>>();
		for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
		{
			vector functions;
			for (FunctionDefinition const* f: contract->definedFunctions())
				if (f->isPartOfExternalInterface())
					functions.push_back(TypeProvider::function(*f, FunctionType::Kind::External));
			for (VariableDeclaration const* v: contract->stateVariables())
				if (v->isPartOfExternalInterface())
					functions.push_back(TypeProvider::function(*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);
					util::FixedHash<4> hash(util::keccak256(functionSignature));
					m_interfaceFunctionList->emplace_back(hash, fun);
				}
			}
		}
	}
	return *m_interfaceFunctionList;
}
vector const& ContractDefinition::inheritableMembers() const
{
	if (!m_inheritableMembers)
	{
		m_inheritableMembers = make_unique>();
		auto addInheritableMember = [&](Declaration const* _decl)
		{
			solAssert(_decl, "addInheritableMember got a nullpointer.");
			if (_decl->isVisibleInDerivedContracts())
				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);
		for (EnumDefinition const* e: definedEnums())
			addInheritableMember(e);
		for (EventDefinition const* e: events())
			addInheritableMember(e);
	}
	return *m_inheritableMembers;
}
TypePointer ContractDefinition::type() const
{
	return TypeProvider::typeType(TypeProvider::contract(*this));
}
ContractDefinitionAnnotation& ContractDefinition::annotation() const
{
	return initAnnotation();
}
TypeNameAnnotation& TypeName::annotation() const
{
	return initAnnotation();
}
TypePointer StructDefinition::type() const
{
	return TypeProvider::typeType(TypeProvider::structType(*this, DataLocation::Storage));
}
TypeDeclarationAnnotation& StructDefinition::annotation() const
{
	return initAnnotation();
}
TypePointer EnumValue::type() const
{
	auto parentDef = dynamic_cast(scope());
	solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
	return TypeProvider::enumType(*parentDef);
}
TypePointer EnumDefinition::type() const
{
	return TypeProvider::typeType(TypeProvider::enumType(*this));
}
TypeDeclarationAnnotation& EnumDefinition::annotation() const
{
	return initAnnotation();
}
ContractKind FunctionDefinition::inContractKind() const
{
	auto contractDef = dynamic_cast(scope());
	solAssert(contractDef, "Enclosing Scope of FunctionDefinition was not set.");
	return contractDef->contractKind();
}
FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
{
	if (_internal)
	{
		switch (visibility())
		{
		case Visibility::Default:
			solAssert(false, "visibility() should not return Default");
		case Visibility::Private:
		case Visibility::Internal:
		case Visibility::Public:
			return TypeProvider::function(*this, FunctionType::Kind::Internal);
		case Visibility::External:
			return {};
		}
	}
	else
	{
		switch (visibility())
		{
		case Visibility::Default:
			solAssert(false, "visibility() should not return Default");
		case Visibility::Private:
		case Visibility::Internal:
			return {};
		case Visibility::Public:
		case Visibility::External:
			return TypeProvider::function(*this, FunctionType::Kind::External);
		}
	}
	// To make the compiler happy
	return {};
}
TypePointer FunctionDefinition::type() const
{
	solAssert(visibility() != Visibility::External, "");
	return TypeProvider::function(*this, FunctionType::Kind::Internal);
}
string FunctionDefinition::externalSignature() const
{
	return TypeProvider::function(*this)->externalSignature();
}
string FunctionDefinition::externalIdentifierHex() const
{
	return TypeProvider::function(*this)->externalIdentifierHex();
}
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
{
	return initAnnotation();
}
TypePointer ModifierDefinition::type() const
{
	return TypeProvider::modifier(*this);
}
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
{
	return initAnnotation();
}
TypePointer EventDefinition::type() const
{
	return TypeProvider::function(*this);
}
FunctionTypePointer EventDefinition::functionType(bool _internal) const
{
	if (_internal)
		return TypeProvider::function(*this);
	else
		return nullptr;
}
EventDefinitionAnnotation& EventDefinition::annotation() const
{
	return initAnnotation();
}
UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const
{
	return initAnnotation();
}
SourceUnit const& Scopable::sourceUnit() const
{
	ASTNode const* s = scope();
	solAssert(s, "");
	// will not always be a declaration
	while (dynamic_cast(s) && dynamic_cast(s)->scope())
		s = dynamic_cast(s)->scope();
	return dynamic_cast(*s);
}
CallableDeclaration const* Scopable::functionOrModifierDefinition() const
{
	ASTNode const* s = scope();
	solAssert(s, "");
	while (dynamic_cast(s))
	{
		if (auto funDef = dynamic_cast(s))
			return funDef;
		if (auto modDef = dynamic_cast(s))
			return modDef;
		s = dynamic_cast(s)->scope();
	}
	return nullptr;
}
string Scopable::sourceUnitName() const
{
	return sourceUnit().annotation().path;
}
DeclarationAnnotation& Declaration::annotation() const
{
	return initAnnotation();
}
bool VariableDeclaration::isLValue() const
{
	// Constant declared variables are Read-Only
	if (m_isConstant)
		return false;
	// External function arguments of reference type are Read-Only
	if (isExternalCallableParameter() && dynamic_cast(type()))
		return false;
	return true;
}
bool VariableDeclaration::isLocalVariable() const
{
	auto s = scope();
	return
		dynamic_cast(s) ||
		dynamic_cast(s) ||
		dynamic_cast(s) ||
		dynamic_cast(s) ||
		dynamic_cast(s);
}
bool VariableDeclaration::isCallableOrCatchParameter() const
{
	if (isReturnParameter() || isTryCatchParameter())
		return true;
	vector> const* parameters = nullptr;
	if (auto const* funTypeName = dynamic_cast(scope()))
		parameters = &funTypeName->parameterTypes();
	else if (auto const* callable = dynamic_cast(scope()))
		parameters = &callable->parameters();
	if (parameters)
		for (auto const& variable: *parameters)
			if (variable.get() == this)
				return true;
	return false;
}
bool VariableDeclaration::isLocalOrReturn() const
{
	return isReturnParameter() || (isLocalVariable() && !isCallableOrCatchParameter());
}
bool VariableDeclaration::isReturnParameter() const
{
	vector> const* returnParameters = nullptr;
	if (auto const* funTypeName = dynamic_cast(scope()))
		returnParameters = &funTypeName->returnParameterTypes();
	else if (auto const* callable = dynamic_cast(scope()))
		if (callable->returnParameterList())
			returnParameters = &callable->returnParameterList()->parameters();
	if (returnParameters)
		for (auto const& variable: *returnParameters)
			if (variable.get() == this)
				return true;
	return false;
}
bool VariableDeclaration::isTryCatchParameter() const
{
	return dynamic_cast(scope());
}
bool VariableDeclaration::isExternalCallableParameter() const
{
	if (!isCallableOrCatchParameter())
		return false;
	if (auto const* callable = dynamic_cast(scope()))
		if (callable->visibility() == Visibility::External)
			return !isReturnParameter();
	return false;
}
bool VariableDeclaration::isInternalCallableParameter() const
{
	if (!isCallableOrCatchParameter())
		return false;
	if (auto const* funTypeName = dynamic_cast(scope()))
		return funTypeName->visibility() == Visibility::Internal;
	else if (auto const* callable = dynamic_cast(scope()))
		return callable->visibility() <= Visibility::Internal;
	return false;
}
bool VariableDeclaration::isLibraryFunctionParameter() const
{
	if (!isCallableOrCatchParameter())
		return false;
	if (auto const* funDef = dynamic_cast(scope()))
		return dynamic_cast(*funDef->scope()).isLibrary();
	else
		return false;
}
bool VariableDeclaration::isEventParameter() const
{
	return dynamic_cast(scope()) != nullptr;
}
bool VariableDeclaration::hasReferenceOrMappingType() const
{
	solAssert(typeName(), "");
	solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
	Type const* type = typeName()->annotation().type;
	return type->category() == Type::Category::Mapping || dynamic_cast(type);
}
set VariableDeclaration::allowedDataLocations() const
{
	using Location = VariableDeclaration::Location;
	if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
		return set{ Location::Unspecified };
	else if (isStateVariable() && isConstant())
		return set{ Location::Memory };
	else if (isExternalCallableParameter())
	{
		set locations{ Location::CallData };
		if (isLibraryFunctionParameter())
			locations.insert(Location::Storage);
		return locations;
	}
	else if (isCallableOrCatchParameter())
	{
		set locations{ Location::Memory };
		if (isInternalCallableParameter() || isLibraryFunctionParameter() || isTryCatchParameter())
			locations.insert(Location::Storage);
		return locations;
	}
	else if (isLocalVariable())
	{
		solAssert(typeName(), "");
		solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
		if (typeName()->annotation().type->category() == Type::Category::Mapping)
			return set{ Location::Storage };
		else
			//  TODO: add Location::Calldata once implemented for local variables.
			return set{ Location::Memory, Location::Storage };
	}
	else
		// Struct members etc.
		return set{ Location::Unspecified };
}
string VariableDeclaration::externalIdentifierHex() const
{
	solAssert(isStateVariable() && isPublic(), "Can only be called for public state variables");
	return TypeProvider::function(*this)->externalIdentifierHex();
}
TypePointer VariableDeclaration::type() const
{
	return annotation().type;
}
FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
{
	if (_internal)
		return nullptr;
	switch (visibility())
	{
	case Visibility::Default:
		solAssert(false, "visibility() should not return Default");
	case Visibility::Private:
	case Visibility::Internal:
		return nullptr;
	case Visibility::Public:
	case Visibility::External:
		return TypeProvider::function(*this);
	}
	// To make the compiler happy
	return nullptr;
}
VariableDeclarationAnnotation& VariableDeclaration::annotation() const
{
	return initAnnotation();
}
StatementAnnotation& Statement::annotation() const
{
	return initAnnotation();
}
InlineAssemblyAnnotation& InlineAssembly::annotation() const
{
	return initAnnotation();
}
BlockAnnotation& Block::annotation() const
{
	return initAnnotation();
}
TryCatchClauseAnnotation& TryCatchClause::annotation() const
{
	return initAnnotation();
}
ForStatementAnnotation& ForStatement::annotation() const
{
	return initAnnotation();
}
ReturnAnnotation& Return::annotation() const
{
	return initAnnotation();
}
ExpressionAnnotation& Expression::annotation() const
{
	return initAnnotation();
}
MemberAccessAnnotation& MemberAccess::annotation() const
{
	return initAnnotation();
}
BinaryOperationAnnotation& BinaryOperation::annotation() const
{
	return initAnnotation();
}
FunctionCallAnnotation& FunctionCall::annotation() const
{
	return initAnnotation();
}
IdentifierAnnotation& Identifier::annotation() const
{
	return initAnnotation();
}
ASTString Literal::valueWithoutUnderscores() const
{
	return boost::erase_all_copy(value(), "_");
}
bool Literal::isHexNumber() const
{
	if (token() != Token::Number)
		return false;
	return boost::starts_with(value(), "0x");
}
bool Literal::looksLikeAddress() const
{
	if (subDenomination() != SubDenomination::None)
		return false;
	if (!isHexNumber())
		return false;
	return abs(int(valueWithoutUnderscores().length()) - 42) <= 1;
}
bool Literal::passesAddressChecksum() const
{
	solAssert(isHexNumber(), "Expected hex number");
	return util::passesAddressChecksum(valueWithoutUnderscores(), true);
}
string Literal::getChecksummedAddress() const
{
	solAssert(isHexNumber(), "Expected hex number");
	/// Pad literal to be a proper hex address.
	string address = valueWithoutUnderscores().substr(2);
	if (address.length() > 40)
		return string();
	address.insert(address.begin(), 40 - address.size(), '0');
	return util::getChecksummedAddress(address);
}