From 54eb34d6fd4c6d47b23dd7084a7470f1f405ac37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 23 Feb 2021 10:21:13 +0100 Subject: [PATCH] Move call graphs from CompilerStack to ContractDefinitionAnnotation --- libsolidity/ast/ASTAnnotations.h | 6 +++ libsolidity/interface/CompilerStack.cpp | 37 ++++++++----------- libsolidity/interface/CompilerStack.h | 8 ---- .../analysis/FunctionCallGraph.cpp | 4 +- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index e6ef18c3a..f2c2d5812 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -49,6 +49,8 @@ class Type; using TypePointer = Type const*; using namespace util; +struct CallGraph; + struct ASTAnnotation { ASTAnnotation() = default; @@ -162,6 +164,10 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocu /// Mapping containing the nodes that define the arguments for base constructors. /// These can either be inheritance specifiers or modifier invocations. std::map baseConstructorArguments; + /// A graph with edges representing calls between functions that may happen during contract construction. + SetOnce> creationCallGraph; + /// A graph with edges representing calls between functions that may happen in a deployed contract. + SetOnce> deployedCallGraph; }; struct CallableDeclarationAnnotation: DeclarationAnnotation diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index f897b01d2..297c07411 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -407,8 +407,18 @@ bool CompilerStack::analyze() if (auto const* contractDefinition = dynamic_cast(node.get())) { Contract& contractState = m_contracts.at(contractDefinition->fullyQualifiedName()); - contractState.creationCallGraph.emplace(FunctionCallGraphBuilder::buildCreationGraph(*contractDefinition)); - contractState.deployedCallGraph.emplace(FunctionCallGraphBuilder::buildDeployedGraph(*contractDefinition, *contractState.creationCallGraph)); + + contractState.contract->annotation().creationCallGraph = make_unique( + FunctionCallGraphBuilder::buildCreationGraph( + *contractDefinition + ) + ); + contractState.contract->annotation().deployedCallGraph = make_unique( + FunctionCallGraphBuilder::buildDeployedGraph( + *contractDefinition, + **contractState.contract->annotation().creationCallGraph + ) + ); } } @@ -950,24 +960,6 @@ string const& CompilerStack::metadata(Contract const& _contract) const return _contract.metadata.init([&]{ return createMetadata(_contract); }); } -CallGraph const& CompilerStack::creationCallGraph(string const& _contractName) const -{ - if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); - - solAssert(contract(_contractName).creationCallGraph.has_value(), ""); - return contract(_contractName).creationCallGraph.value(); -} - -CallGraph const& CompilerStack::deployedCallGraph(string const& _contractName) const -{ - if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); - - solAssert(contract(_contractName).deployedCallGraph.has_value(), ""); - return contract(_contractName).deployedCallGraph.value(); -} - Scanner const& CompilerStack::scanner(string const& _sourceName) const { if (m_stackState < SourcesSet) @@ -1307,7 +1299,10 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources); - generator.verifyCallGraphs(compiledContract.creationCallGraph.value(), compiledContract.deployedCallGraph.value()); + generator.verifyCallGraphs( + **compiledContract.contract->annotation().creationCallGraph, + **compiledContract.contract->annotation().deployedCallGraph + ); } void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 604a20960..a7861d221 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -347,12 +347,6 @@ public: /// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions Json::Value gasEstimates(std::string const& _contractName) const; - /// @returns a graph with edges representing calls between functions that may happen during contract construction. - CallGraph const& creationCallGraph(std::string const& _contractName) const; - - /// @returns a graph with edges representing calls between functions that may happen in a deployed contract. - CallGraph const& deployedCallGraph(std::string const& _contractName) const; - /// Changes the format of the metadata appended at the end of the bytecode. /// This is mostly a workaround to avoid bytecode and gas differences between compiler builds /// caused by differences in metadata. Should only be used for testing. @@ -394,8 +388,6 @@ private: util::LazyInit runtimeGeneratedSources; mutable std::optional sourceMapping; mutable std::optional runtimeSourceMapping; - std::optional creationCallGraph; - std::optional deployedCallGraph; }; /// Loads the missing sources from @a _ast (named @a _path) using the callback diff --git a/test/libsolidity/analysis/FunctionCallGraph.cpp b/test/libsolidity/analysis/FunctionCallGraph.cpp index 17a6c0c76..057e30653 100644 --- a/test/libsolidity/analysis/FunctionCallGraph.cpp +++ b/test/libsolidity/analysis/FunctionCallGraph.cpp @@ -116,8 +116,8 @@ tuple collectGraphs(CompilerStack const& _compilerSt soltestAssert(fullyQualifiedContractName.size() > 0 && fullyQualifiedContractName[0] == ':', ""); string contractName = fullyQualifiedContractName.substr(1); - get<0>(graphs).emplace(contractName, &_compilerStack.creationCallGraph(fullyQualifiedContractName)); - get<1>(graphs).emplace(contractName, &_compilerStack.deployedCallGraph(fullyQualifiedContractName)); + get<0>(graphs).emplace(contractName, _compilerStack.contractDefinition(fullyQualifiedContractName).annotation().creationCallGraph->get()); + get<1>(graphs).emplace(contractName, _compilerStack.contractDefinition(fullyQualifiedContractName).annotation().deployedCallGraph->get()); } return graphs;