mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Call constructors of base classes.
This commit is contained in:
parent
af92f98d86
commit
ddf5e20d10
@ -31,13 +31,9 @@ namespace dev
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
void CallGraph::addFunction(FunctionDefinition const& _function)
|
||||
void CallGraph::addNode(ASTNode const& _node)
|
||||
{
|
||||
if (!m_functionsSeen.count(&_function))
|
||||
{
|
||||
m_functionsSeen.insert(&_function);
|
||||
m_workQueue.push(&_function);
|
||||
}
|
||||
_node.accept(*this);
|
||||
}
|
||||
|
||||
set<FunctionDefinition const*> const& CallGraph::getCalls()
|
||||
@ -63,5 +59,41 @@ bool CallGraph::visit(Identifier const& _identifier)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallGraph::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
addFunction(_function);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallGraph::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
// used for "BaseContract.baseContractFunction"
|
||||
if (_memberAccess.getExpression().getType()->getCategory() == Type::Category::TYPE)
|
||||
{
|
||||
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.getExpression().getType());
|
||||
if (type.getMembers().getMemberType(_memberAccess.getMemberName()))
|
||||
{
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*type.getActualType())
|
||||
.getContractDefinition();
|
||||
for (ASTPointer<FunctionDefinition> const& function: contract.getDefinedFunctions())
|
||||
if (function->getName() == _memberAccess.getMemberName())
|
||||
{
|
||||
addFunction(*function);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallGraph::addFunction(FunctionDefinition const& _function)
|
||||
{
|
||||
if (!m_functionsSeen.count(&_function))
|
||||
{
|
||||
m_functionsSeen.insert(&_function);
|
||||
m_workQueue.push(&_function);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -38,14 +38,17 @@ namespace solidity
|
||||
class CallGraph: private ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
void addFunction(FunctionDefinition const& _function);
|
||||
void addNode(ASTNode const& _node);
|
||||
void computeCallGraph();
|
||||
|
||||
std::set<FunctionDefinition const*> const& getCalls();
|
||||
|
||||
private:
|
||||
void addFunctionToQueue(FunctionDefinition const& _function);
|
||||
virtual bool visit(FunctionDefinition const& _function) override;
|
||||
virtual bool visit(Identifier const& _identifier) override;
|
||||
virtual bool visit(MemberAccess const& _memberAccess) override;
|
||||
|
||||
void addFunction(FunctionDefinition const& _function);
|
||||
|
||||
std::set<FunctionDefinition const*> m_functionsSeen;
|
||||
std::queue<FunctionDefinition const*> m_workQueue;
|
||||
|
71
Compiler.cpp
71
Compiler.cpp
@ -67,19 +67,52 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
|
||||
|
||||
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
|
||||
{
|
||||
// arguments for base constructors, filled in derived-to-base order
|
||||
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
|
||||
set<FunctionDefinition const*> neededFunctions;
|
||||
// TODO constructors of base classes
|
||||
FunctionDefinition const* constructor = _contract.getConstructor();
|
||||
if (constructor)
|
||||
neededFunctions = getFunctionsNeededByConstructor(*constructor);
|
||||
set<ASTNode const*> nodesUsedInConstructors;
|
||||
|
||||
// Determine the arguments that are used for the base constructors and also which functions
|
||||
// are needed at compile time.
|
||||
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
|
||||
for (ContractDefinition const* contract: bases)
|
||||
{
|
||||
if (FunctionDefinition const* constructor = contract->getConstructor())
|
||||
nodesUsedInConstructors.insert(constructor);
|
||||
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
|
||||
{
|
||||
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
|
||||
base->getName()->getReferencedDeclaration());
|
||||
solAssert(baseContract, "");
|
||||
if (baseArguments.count(baseContract) == 0)
|
||||
{
|
||||
baseArguments[baseContract] = &base->getArguments();
|
||||
for (ASTPointer<Expression> const& arg: base->getArguments())
|
||||
nodesUsedInConstructors.insert(arg.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@TODO add virtual functions
|
||||
neededFunctions = getFunctionsCalled(nodesUsedInConstructors);
|
||||
|
||||
// TODO we should add the overridden functions
|
||||
for (FunctionDefinition const* fun: neededFunctions)
|
||||
m_context.addFunction(*fun);
|
||||
|
||||
// we have many of them now
|
||||
if (constructor)
|
||||
appendConstructorCall(*constructor);
|
||||
// Call constructors in base-to-derived order.
|
||||
// The Constructor for the most derived contract is called later.
|
||||
for (unsigned i = 1; i < bases.size(); i++)
|
||||
{
|
||||
ContractDefinition const* base = bases[bases.size() - i];
|
||||
solAssert(base, "");
|
||||
FunctionDefinition const* baseConstructor = base->getConstructor();
|
||||
if (!baseConstructor)
|
||||
continue;
|
||||
solAssert(baseArguments[base], "");
|
||||
appendBaseConstructorCall(*baseConstructor, *baseArguments[base]);
|
||||
}
|
||||
if (_contract.getConstructor())
|
||||
appendConstructorCall(*_contract.getConstructor());
|
||||
|
||||
eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly());
|
||||
// stack contains sub size
|
||||
@ -92,6 +125,21 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
|
||||
fun->accept(*this);
|
||||
}
|
||||
|
||||
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor,
|
||||
vector<ASTPointer<Expression>> const& _arguments)
|
||||
{
|
||||
FunctionType constructorType(_constructor);
|
||||
eth::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||
for (unsigned i = 0; i < _arguments.size(); ++i)
|
||||
{
|
||||
compileExpression(*_arguments[i]);
|
||||
ExpressionCompiler::appendTypeConversion(m_context, *_arguments[i]->getType(),
|
||||
*constructorType.getParameterTypes()[i]);
|
||||
}
|
||||
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor));
|
||||
m_context << returnLabel;
|
||||
}
|
||||
|
||||
void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
|
||||
{
|
||||
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
||||
@ -111,11 +159,12 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
|
||||
m_context << returnTag;
|
||||
}
|
||||
|
||||
set<FunctionDefinition const*> Compiler::getFunctionsNeededByConstructor(FunctionDefinition const& _constructor)
|
||||
set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes)
|
||||
{
|
||||
// TODO this does not add virtual functions
|
||||
CallGraph callgraph;
|
||||
callgraph.addFunction(_constructor);
|
||||
callgraph.computeCallGraph();
|
||||
for (ASTNode const* node: _nodes)
|
||||
callgraph.addNode(*node);
|
||||
return callgraph.getCalls();
|
||||
}
|
||||
|
||||
|
@ -43,12 +43,13 @@ private:
|
||||
void initializeContext(ContractDefinition const& _contract,
|
||||
std::map<ContractDefinition const*, bytes const*> const& _contracts);
|
||||
/// Adds the code that is run at creation time. Should be run after exchanging the run-time context
|
||||
/// with a new and initialized context.
|
||||
/// adds the constructor code.
|
||||
/// with a new and initialized context. Adds the constructor code.
|
||||
void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext);
|
||||
void appendBaseConstructorCall(FunctionDefinition const& _constructor,
|
||||
std::vector<ASTPointer<Expression>> const& _arguments);
|
||||
void appendConstructorCall(FunctionDefinition const& _constructor);
|
||||
/// Recursively searches the call graph and returns all functions needed by the constructor (including itself).
|
||||
std::set<FunctionDefinition const*> getFunctionsNeededByConstructor(FunctionDefinition const& _constructor);
|
||||
/// Recursively searches the call graph and returns all functions referenced inside _nodes.
|
||||
std::set<FunctionDefinition const*> getFunctionsCalled(std::set<ASTNode const*> const& _nodes);
|
||||
void appendFunctionSelector(ContractDefinition const& _contract);
|
||||
/// Creates code that unpacks the arguments for the given function, from memory if
|
||||
/// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
|
||||
|
@ -31,7 +31,6 @@ namespace dev
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
|
||||
NameAndTypeResolver::NameAndTypeResolver(std::vector<Declaration const*> const& _globals)
|
||||
{
|
||||
for (Declaration const* declaration: _globals)
|
||||
|
Loading…
Reference in New Issue
Block a user