Add creationCode/runtimeCode contract creation detection to call graph

This commit is contained in:
Mathias Baumann 2021-03-11 15:22:33 +01:00
parent 8c583784c0
commit bccedf791b
3 changed files with 19 additions and 7 deletions

View File

@ -165,6 +165,18 @@ bool FunctionCallGraphBuilder::visit(Identifier const& _identifier)
bool FunctionCallGraphBuilder::visit(MemberAccess const& _memberAccess) bool FunctionCallGraphBuilder::visit(MemberAccess const& _memberAccess)
{ {
TypePointer exprType = _memberAccess.expression().annotation().type;
ASTString const& memberName = _memberAccess.memberName();
if (auto magicType = dynamic_cast<MagicType const*>(exprType))
if (magicType->kind() == MagicType::Kind::MetaType && (
memberName == "creationCode" || memberName == "runtimeCode"
))
{
ContractType const& accessedContractType = dynamic_cast<ContractType const&>(*magicType->typeArgument());
m_graph.bytecodeDependency.emplace(&accessedContractType.contractDefinition(), &_memberAccess);
}
auto functionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type); auto functionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
auto functionDef = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration); auto functionDef = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration);
if (!functionType || !functionDef || functionType->kind() != FunctionType::Kind::Internal) if (!functionType || !functionDef || functionType->kind() != FunctionType::Kind::Internal)
@ -173,7 +185,7 @@ bool FunctionCallGraphBuilder::visit(MemberAccess const& _memberAccess)
// Super functions // Super functions
if (*_memberAccess.annotation().requiredLookup == VirtualLookup::Super) if (*_memberAccess.annotation().requiredLookup == VirtualLookup::Super)
{ {
if (auto const* typeType = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type)) if (auto const* typeType = dynamic_cast<TypeType const*>(exprType))
if (auto const contractType = dynamic_cast<ContractType const*>(typeType->actualType())) if (auto const contractType = dynamic_cast<ContractType const*>(typeType->actualType()))
{ {
solAssert(contractType->isSuper(), ""); solAssert(contractType->isSuper(), "");
@ -187,7 +199,6 @@ bool FunctionCallGraphBuilder::visit(MemberAccess const& _memberAccess)
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
functionReferenced(*functionDef, _memberAccess.annotation().calledDirectly); functionReferenced(*functionDef, _memberAccess.annotation().calledDirectly);
return true; return true;
} }
@ -212,7 +223,7 @@ bool FunctionCallGraphBuilder::visit(ModifierInvocation const& _modifierInvocati
bool FunctionCallGraphBuilder::visit(NewExpression const& _newExpression) bool FunctionCallGraphBuilder::visit(NewExpression const& _newExpression)
{ {
if (ContractType const* contractType = dynamic_cast<ContractType const*>(_newExpression.typeName().annotation().type)) if (ContractType const* contractType = dynamic_cast<ContractType const*>(_newExpression.typeName().annotation().type))
m_graph.createdContracts.emplace(&contractType->contractDefinition()); m_graph.bytecodeDependency.emplace(&contractType->contractDefinition(), &_newExpression);
return true; return true;
} }

View File

@ -61,8 +61,9 @@ struct CallGraph
/// any calls. /// any calls.
std::map<Node, std::set<Node, CompareByID>, CompareByID> edges; std::map<Node, std::set<Node, CompareByID>, CompareByID> edges;
/// Contracts that may get created with `new` by functions present in the graph. /// Contracts that need to be compiled before this one can be compiled.
std::set<ContractDefinition const*, ASTNode::CompareByID> createdContracts; /// The value is the ast node that created the dependency.
std::map<ContractDefinition const*, ASTNode const*, ASTNode::CompareByID> bytecodeDependency;
/// Events that may get emitted by functions present in the graph. /// Events that may get emitted by functions present in the graph.
std::set<EventDefinition const*, ASTNode::CompareByID> emittedEvents; std::set<EventDefinition const*, ASTNode::CompareByID> emittedEvents;

View File

@ -159,8 +159,8 @@ void checkCallGraphExpectations(
CallGraph const& callGraph = *_callGraphs.at(contractName); CallGraph const& callGraph = *_callGraphs.at(contractName);
edges[contractName] = edgeNames(callGraph.edges); edges[contractName] = edgeNames(callGraph.edges);
if (!callGraph.createdContracts.empty()) if (!callGraph.bytecodeDependency.empty())
createdContractSets[contractName] = callGraph.createdContracts | views::transform(getContractName) | to<set<string>>(); createdContractSets[contractName] = callGraph.bytecodeDependency | views::keys | views::transform(getContractName) | to<set<string>>();
if (!callGraph.emittedEvents.empty()) if (!callGraph.emittedEvents.empty())
emittedEventSets[contractName] = callGraph.emittedEvents | views::transform(eventToString) | to<set<string>>(); emittedEventSets[contractName] = callGraph.emittedEvents | views::transform(eventToString) | to<set<string>>();
} }