mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11014 from ethereum/fixConstantsCallGraph
Fix call graph with respect to constants.
This commit is contained in:
commit
44493ad428
@ -41,7 +41,8 @@ CallGraph FunctionCallGraphBuilder::buildCreationGraph(ContractDefinition const&
|
||||
// an edge from Entry
|
||||
builder.m_currentNode = CallGraph::SpecialNode::Entry;
|
||||
for (auto const* stateVar: base->stateVariables())
|
||||
stateVar->accept(builder);
|
||||
if (!stateVar->isConstant())
|
||||
stateVar->accept(builder);
|
||||
|
||||
if (base->constructor())
|
||||
{
|
||||
@ -140,7 +141,15 @@ bool FunctionCallGraphBuilder::visit(EmitStatement const& _emitStatement)
|
||||
|
||||
bool FunctionCallGraphBuilder::visit(Identifier const& _identifier)
|
||||
{
|
||||
if (auto const* callable = dynamic_cast<CallableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
{
|
||||
if (variable->isConstant())
|
||||
{
|
||||
solAssert(variable->isStateVariable() || variable->isFileLevelVariable(), "");
|
||||
variable->accept(*this);
|
||||
}
|
||||
}
|
||||
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
{
|
||||
solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, "");
|
||||
|
||||
|
@ -66,7 +66,7 @@ void verifyCallGraph(
|
||||
{
|
||||
solAssert(
|
||||
_generatedFunctions.count(expectedFunction) == 1 || expectedFunction->isConstructor(),
|
||||
"No code generated for function " + expectedFunction->name() + "even though it is not a constructor."
|
||||
"No code generated for function " + expectedFunction->name() + " even though it is not a constructor."
|
||||
);
|
||||
_generatedFunctions.erase(expectedFunction);
|
||||
}
|
||||
|
@ -2000,6 +2000,163 @@ BOOST_AUTO_TEST_CASE(conversions_and_struct_array_constructors)
|
||||
checkCallGraphExpectations(get<1>(graphs), expectedDeployedEdges);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(immutable_initialization)
|
||||
{
|
||||
unique_ptr<CompilerStack> compilerStack = parseAndAnalyzeContracts(R"(
|
||||
function free() pure returns (uint) { return 42; }
|
||||
|
||||
contract Base {
|
||||
function ext() external pure returns (uint) { free(); }
|
||||
function inr() internal pure returns (uint) { free(); }
|
||||
}
|
||||
|
||||
contract C is Base {
|
||||
uint immutable extImmutable = this.ext();
|
||||
uint immutable inrImmutable = inr();
|
||||
}
|
||||
|
||||
contract D is Base {
|
||||
uint immutable extImmutable;
|
||||
uint immutable inrImmutable;
|
||||
|
||||
constructor () {
|
||||
extImmutable = this.ext();
|
||||
inrImmutable = inr();
|
||||
}
|
||||
}
|
||||
)"s);
|
||||
tuple<CallGraphMap, CallGraphMap> graphs = collectGraphs(*compilerStack);
|
||||
|
||||
map<string, EdgeNames> expectedCreationEdges = {
|
||||
{"Base", {}},
|
||||
{"C", {
|
||||
{"Entry", "function Base.inr()"},
|
||||
{"function Base.inr()", "function free()"},
|
||||
}},
|
||||
{"D", {
|
||||
{"Entry", "constructor of D"},
|
||||
{"constructor of D", "function Base.inr()"},
|
||||
{"function Base.inr()", "function free()"},
|
||||
}},
|
||||
};
|
||||
|
||||
map<string, EdgeNames> expectedDeployedEdges = {
|
||||
{"Base", {
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
}},
|
||||
{"C", {
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
}},
|
||||
{"D", {
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
}},
|
||||
};
|
||||
|
||||
checkCallGraphExpectations(get<0>(graphs), expectedCreationEdges);
|
||||
checkCallGraphExpectations(get<1>(graphs), expectedDeployedEdges);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_selector_access)
|
||||
{
|
||||
unique_ptr<CompilerStack> compilerStack = parseAndAnalyzeContracts(R"(
|
||||
function free() pure {}
|
||||
|
||||
bytes4 constant extFreeConst = Base.ext.selector;
|
||||
bytes4 constant pubFreeConst = Base.pub.selector;
|
||||
|
||||
contract Base {
|
||||
function ext() external pure { free(); extFreeConst; }
|
||||
function pub() public pure { free(); pubFreeConst; }
|
||||
}
|
||||
|
||||
contract C is Base {
|
||||
bytes4 constant extConst = Base.ext.selector;
|
||||
bytes4 constant pubConst = Base.pub.selector;
|
||||
}
|
||||
|
||||
contract D is Base {
|
||||
bytes4 immutable extImmutable = Base.ext.selector;
|
||||
bytes4 immutable pubImmutable = Base.pub.selector;
|
||||
}
|
||||
|
||||
contract E is Base {
|
||||
bytes4 extVar = Base.ext.selector;
|
||||
bytes4 pubVar = Base.pub.selector;
|
||||
}
|
||||
|
||||
contract F is Base {
|
||||
function f() public pure returns (bytes4, bytes4) {
|
||||
return (Base.ext.selector, Base.pub.selector);
|
||||
}
|
||||
}
|
||||
|
||||
library L {
|
||||
bytes4 constant extConst = Base.ext.selector;
|
||||
bytes4 constant pubConst = Base.pub.selector;
|
||||
}
|
||||
)"s);
|
||||
tuple<CallGraphMap, CallGraphMap> graphs = collectGraphs(*compilerStack);
|
||||
|
||||
map<string, EdgeNames> expectedCreationEdges = {
|
||||
{"Base", {}},
|
||||
{"C", {}},
|
||||
{"D", {
|
||||
{"InternalDispatch", "function Base.pub()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"E", {
|
||||
{"InternalDispatch", "function Base.pub()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"F", {}},
|
||||
{"L", {}},
|
||||
};
|
||||
|
||||
map<string, EdgeNames> expectedDeployedEdges = {
|
||||
{"Base", {
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"Entry", "function Base.pub()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"C", {
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"Entry", "function Base.pub()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"D", {
|
||||
{"InternalDispatch", "function Base.pub()"},
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"Entry", "function Base.pub()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"E", {
|
||||
{"InternalDispatch", "function Base.pub()"},
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"Entry", "function Base.pub()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"F", {
|
||||
{"InternalDispatch", "function Base.pub()"},
|
||||
{"Entry", "function Base.ext()"},
|
||||
{"Entry", "function Base.pub()"},
|
||||
{"Entry", "function F.f()"},
|
||||
{"function Base.ext()", "function free()"},
|
||||
{"function Base.pub()", "function free()"},
|
||||
}},
|
||||
{"L", {}},
|
||||
};
|
||||
|
||||
checkCallGraphExpectations(get<0>(graphs), expectedCreationEdges);
|
||||
checkCallGraphExpectations(get<1>(graphs), expectedDeployedEdges);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace solidity::frontend::test
|
||||
|
Loading…
Reference in New Issue
Block a user