Skip to content

Commit c1670de

Browse files
nikola-maticcameel
authored andcommitted
Merge pull request #14575 from ethereum/syntactic-call-graph
Function dependency graph
2 parents 41221c5 + e36b89f commit c1670de

15 files changed

+470
-23
lines changed

Diff for: libsolidity/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ set(sources
188188
experimental/analysis/Analysis.h
189189
experimental/analysis/DebugWarner.cpp
190190
experimental/analysis/DebugWarner.h
191+
experimental/analysis/FunctionDependencyAnalysis.cpp
192+
experimental/analysis/FunctionDependencyAnalysis.h
191193
experimental/analysis/TypeClassRegistration.cpp
192194
experimental/analysis/TypeClassRegistration.h
193195
experimental/analysis/TypeInference.cpp
@@ -196,6 +198,7 @@ set(sources
196198
experimental/analysis/TypeRegistration.h
197199
experimental/analysis/SyntaxRestrictor.cpp
198200
experimental/analysis/SyntaxRestrictor.h
201+
experimental/ast/FunctionCallGraph.h
199202
experimental/ast/Type.cpp
200203
experimental/ast/Type.h
201204
experimental/ast/TypeSystem.cpp

Diff for: libsolidity/experimental/analysis/Analysis.cpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// SPDX-License-Identifier: GPL-3.0
1818
#include <libsolidity/experimental/analysis/Analysis.h>
1919
#include <libsolidity/experimental/analysis/DebugWarner.h>
20+
#include <libsolidity/experimental/analysis/FunctionDependencyAnalysis.h>
2021
#include <libsolidity/experimental/analysis/SyntaxRestrictor.h>
2122
#include <libsolidity/experimental/analysis/TypeClassRegistration.h>
2223
#include <libsolidity/experimental/analysis/TypeInference.h>
@@ -35,6 +36,7 @@ struct Analysis::AnnotationContainer
3536

3637
struct Analysis::GlobalAnnotationContainer
3738
{
39+
FunctionDependencyAnalysis::GlobalAnnotation functionDependencyGraphAnnotation;
3840
TypeClassRegistration::GlobalAnnotation typeClassRegistrationAnnotation;
3941
TypeRegistration::GlobalAnnotation typeRegistrationAnnotation;
4042
TypeInference::GlobalAnnotation typeInferenceAnnotation;
@@ -52,7 +54,6 @@ TypeClassRegistration::GlobalAnnotation const& solidity::frontend::experimental:
5254
return analysis.annotationContainer().typeClassRegistrationAnnotation;
5355
}
5456

55-
5657
template<>
5758
TypeClassRegistration::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeClassRegistration>::get()
5859
{
@@ -65,6 +66,18 @@ TypeClassRegistration::Annotation const& solidity::frontend::experimental::detai
6566
return analysis.annotationContainer(_node).typeClassRegistrationAnnotation;
6667
}
6768

69+
template<>
70+
FunctionDependencyAnalysis::GlobalAnnotation const& solidity::frontend::experimental::detail::ConstAnnotationFetcher<FunctionDependencyAnalysis>::get() const
71+
{
72+
return analysis.annotationContainer().functionDependencyGraphAnnotation;
73+
}
74+
75+
template<>
76+
FunctionDependencyAnalysis::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<FunctionDependencyAnalysis>::get()
77+
{
78+
return analysis.annotationContainer().functionDependencyGraphAnnotation;
79+
}
80+
6881
template<>
6982
TypeRegistration::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get(ASTNode const& _node)
7083
{
@@ -77,7 +90,6 @@ TypeRegistration::GlobalAnnotation const& solidity::frontend::experimental::deta
7790
return analysis.annotationContainer().typeRegistrationAnnotation;
7891
}
7992

80-
8193
template<>
8294
TypeRegistration::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get()
8395
{
@@ -108,7 +120,6 @@ TypeInference::GlobalAnnotation const& solidity::frontend::experimental::detail:
108120
return analysis.annotationContainer().typeInferenceAnnotation;
109121
}
110122

111-
112123
template<>
113124
TypeInference::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeInference>::get()
114125
{
@@ -153,6 +164,8 @@ bool Analysis::check(std::vector<std::shared_ptr<SourceUnit const>> const& _sour
153164
SyntaxRestrictor,
154165
TypeClassRegistration,
155166
TypeRegistration,
167+
// TODO move after step introduced in https://github.com/ethereum/solidity/pull/14578, but before TypeInference
168+
FunctionDependencyAnalysis,
156169
TypeInference,
157170
DebugWarner
158171
>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
// SPDX-License-Identifier: GPL-3.0
18+
19+
#include <libsolidity/experimental/analysis/Analysis.h>
20+
#include <libsolidity/experimental/analysis/FunctionDependencyAnalysis.h>
21+
22+
using namespace solidity::frontend::experimental;
23+
using namespace solidity::util;
24+
25+
FunctionDependencyAnalysis::FunctionDependencyAnalysis(Analysis& _analysis):
26+
m_analysis(_analysis),
27+
m_errorReporter(_analysis.errorReporter())
28+
{
29+
}
30+
31+
bool FunctionDependencyAnalysis::analyze(SourceUnit const& _sourceUnit)
32+
{
33+
_sourceUnit.accept(*this);
34+
return !m_errorReporter.hasErrors();
35+
}
36+
37+
bool FunctionDependencyAnalysis::visit(FunctionDefinition const& _functionDefinition)
38+
{
39+
solAssert(!m_currentFunction);
40+
m_currentFunction = &_functionDefinition;
41+
// Insert a function definition pointer that maps to an empty set; the pointed to set will later be
42+
// populated in ``endVisit(Identifier const& _identifier)`` if ``m_currentFunction`` references another.
43+
auto [_, inserted] = annotation().functionCallGraph.edges.try_emplace(
44+
m_currentFunction, std::set<FunctionDefinition const*, ASTCompareByID<FunctionDefinition>>{}
45+
);
46+
solAssert(inserted);
47+
return true;
48+
}
49+
50+
void FunctionDependencyAnalysis::endVisit(FunctionDefinition const&)
51+
{
52+
m_currentFunction = nullptr;
53+
}
54+
55+
void FunctionDependencyAnalysis::endVisit(Identifier const& _identifier)
56+
{
57+
auto const* callee = dynamic_cast<FunctionDefinition const*>(_identifier.annotation().referencedDeclaration);
58+
// Check that the identifier is within a function body and is a function, and add it to the graph
59+
// as an ``m_currentFunction`` -> ``callee`` edge.
60+
if (m_currentFunction && callee)
61+
addEdge(m_currentFunction, callee);
62+
}
63+
64+
void FunctionDependencyAnalysis::addEdge(FunctionDefinition const* _caller, FunctionDefinition const* _callee)
65+
{
66+
annotation().functionCallGraph.edges[_caller].insert(_callee);
67+
}
68+
69+
FunctionDependencyAnalysis::GlobalAnnotation& FunctionDependencyAnalysis::annotation()
70+
{
71+
return m_analysis.annotation<FunctionDependencyAnalysis>();
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
// SPDX-License-Identifier: GPL-3.0
18+
19+
#pragma once
20+
21+
#include <liblangutil/ErrorReporter.h>
22+
#include <libsolidity/ast/ASTForward.h>
23+
#include <libsolidity/ast/ASTVisitor.h>
24+
#include <libsolidity/experimental/ast/FunctionCallGraph.h>
25+
26+
#include <memory>
27+
28+
namespace solidity::frontend::experimental
29+
{
30+
31+
class Analysis;
32+
33+
class FunctionDependencyAnalysis: private ASTConstVisitor
34+
{
35+
public:
36+
FunctionDependencyAnalysis(Analysis& _analysis);
37+
bool analyze(SourceUnit const& _sourceUnit);
38+
39+
struct Annotation {};
40+
struct GlobalAnnotation
41+
{
42+
FunctionDependencyGraph functionCallGraph;
43+
};
44+
45+
private:
46+
bool visit(FunctionDefinition const& _functionDefinition) override;
47+
void endVisit(FunctionDefinition const&) override;
48+
void endVisit(Identifier const& _identifier) override;
49+
void addEdge(FunctionDefinition const* _caller, FunctionDefinition const* _callee);
50+
GlobalAnnotation& annotation();
51+
52+
Analysis& m_analysis;
53+
langutil::ErrorReporter& m_errorReporter;
54+
FunctionDefinition const* m_currentFunction = nullptr;
55+
};
56+
57+
}

Diff for: libsolidity/experimental/ast/FunctionCallGraph.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
// SPDX-License-Identifier: GPL-3.0
18+
19+
/// Data structure representing a function dependency graph.
20+
21+
#pragma once
22+
23+
#include <libsolidity/ast/AST.h>
24+
25+
#include <map>
26+
#include <set>
27+
#include <ostream>
28+
29+
namespace solidity::frontend::experimental
30+
{
31+
32+
struct FunctionDependencyGraph
33+
{
34+
/// Graph edges. Edges are directed and lead from the caller to the callee.
35+
/// The map contains a key for every function, even if does not actually perform
36+
/// any calls.
37+
std::map<FunctionDefinition const*, std::set<FunctionDefinition const*, ASTCompareByID<FunctionDefinition>>, ASTCompareByID<FunctionDefinition>> edges;
38+
};
39+
40+
}

Diff for: libsolidity/interface/CompilerStack.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <libsolidity/parsing/Parser.h>
5858

5959
#include <libsolidity/experimental/analysis/Analysis.h>
60+
#include <libsolidity/experimental/analysis/FunctionDependencyAnalysis.h>
6061
#include <libsolidity/experimental/codegen/IRGenerator.h>
6162

6263
#include <libsolidity/codegen/ir/Common.h>
@@ -2003,3 +2004,9 @@ bool CompilerStack::isExperimentalSolidity() const
20032004
ranges::all_of(m_sourceOrder, [](auto const* _source) { return _source->ast->experimentalSolidity(); } )
20042005
;
20052006
}
2007+
2008+
experimental::Analysis const& CompilerStack::experimentalAnalysis() const
2009+
{
2010+
solAssert(!!m_experimentalAnalysis);
2011+
return *m_experimentalAnalysis;
2012+
}

Diff for: libsolidity/interface/CompilerStack.h

+2
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
357357

358358
bool isExperimentalSolidity() const;
359359

360+
experimental::Analysis const& experimentalAnalysis() const;
361+
360362
static MetadataFormat defaultMetadataFormat()
361363
{
362364
return VersionIsRelease ? MetadataFormat::WithReleaseVersionTag : MetadataFormat::WithPrereleaseVersionTag;

Diff for: test/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ set(libsolidity_sources
7373
libsolidity/ASTJSONTest.h
7474
libsolidity/ErrorCheck.cpp
7575
libsolidity/ErrorCheck.h
76+
libsolidity/FunctionDependencyGraphTest.cpp
77+
libsolidity/FunctionDependencyGraphTest.h
7678
libsolidity/GasCosts.cpp
7779
libsolidity/GasMeter.cpp
7880
libsolidity/GasTest.cpp

Diff for: test/InteractiveTests.h

+22-20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <test/libsolidity/ABIJsonTest.h>
2323
#include <test/libsolidity/ASTJSONTest.h>
2424
#include <test/libsolidity/ASTPropertyTest.h>
25+
#include <libsolidity/FunctionDependencyGraphTest.h>
2526
#include <test/libsolidity/GasTest.h>
2627
#include <test/libsolidity/MemoryGuardTest.h>
2728
#include <test/libsolidity/NatspecJSONTest.h>
@@ -60,26 +61,27 @@ struct Testsuite
6061
/// Array of testsuits that can be run interactively as well as automatically
6162
Testsuite const g_interactiveTestsuites[] = {
6263
/*
63-
Title Path Subpath SMT NeedsVM Creator function */
64-
{"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create},
65-
{"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create},
66-
{"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},
67-
{"Yul Control Flow Graph", "libyul", "yulControlFlowGraph", false, false, &yul::test::ControlFlowGraphTest::create},
68-
{"Yul Stack Layout", "libyul", "yulStackLayout", false, false, &yul::test::StackLayoutGeneratorTest::create},
69-
{"Yul Stack Shuffling", "libyul", "yulStackShuffling", false, false, &yul::test::StackShufflingTest::create},
70-
{"Control Flow Side Effects","libyul", "controlFlowSideEffects",false, false, &yul::test::ControlFlowSideEffectsTest::create},
71-
{"Function Side Effects", "libyul", "functionSideEffects", false, false, &yul::test::FunctionSideEffects::create},
72-
{"Yul Syntax", "libyul", "yulSyntaxTests", false, false, &yul::test::SyntaxTest::create},
73-
{"EVM Code Transform", "libyul", "evmCodeTransform", false, false, &yul::test::EVMCodeTransformTest::create, {"nooptions"}},
74-
{"Syntax", "libsolidity", "syntaxTests", false, false, &SyntaxTest::create},
75-
{"Semantic", "libsolidity", "semanticTests", false, true, &SemanticTest::create},
76-
{"JSON AST", "libsolidity", "ASTJSON", false, false, &ASTJSONTest::create},
77-
{"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create},
78-
{"JSON Natspec", "libsolidity", "natspecJSON", false, false, &NatspecJSONTest::create},
79-
{"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create},
80-
{"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create},
81-
{"Memory Guard", "libsolidity", "memoryGuardTests", false, false, &MemoryGuardTest::create},
82-
{"AST Properties", "libsolidity", "astPropertyTests", false, false, &ASTPropertyTest::create},
64+
Title Path Subpath SMT NeedsVM Creator function */
65+
{"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create},
66+
{"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create},
67+
{"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},
68+
{"Yul Control Flow Graph", "libyul", "yulControlFlowGraph", false, false, &yul::test::ControlFlowGraphTest::create},
69+
{"Yul Stack Layout", "libyul", "yulStackLayout", false, false, &yul::test::StackLayoutGeneratorTest::create},
70+
{"Yul Stack Shuffling", "libyul", "yulStackShuffling", false, false, &yul::test::StackShufflingTest::create},
71+
{"Control Flow Side Effects", "libyul", "controlFlowSideEffects", false, false, &yul::test::ControlFlowSideEffectsTest::create},
72+
{"Function Side Effects", "libyul", "functionSideEffects", false, false, &yul::test::FunctionSideEffects::create},
73+
{"Yul Syntax", "libyul", "yulSyntaxTests", false, false, &yul::test::SyntaxTest::create},
74+
{"EVM Code Transform", "libyul", "evmCodeTransform", false, false, &yul::test::EVMCodeTransformTest::create, {"nooptions"}},
75+
{"Syntax", "libsolidity", "syntaxTests", false, false, &SyntaxTest::create},
76+
{"Semantic", "libsolidity", "semanticTests", false, true, &SemanticTest::create},
77+
{"JSON AST", "libsolidity", "ASTJSON", false, false, &ASTJSONTest::create},
78+
{"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create},
79+
{"JSON Natspec", "libsolidity", "natspecJSON", false, false, &NatspecJSONTest::create},
80+
{"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create},
81+
{"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create},
82+
{"Memory Guard", "libsolidity", "memoryGuardTests", false, false, &MemoryGuardTest::create},
83+
{"AST Properties", "libsolidity", "astPropertyTests", false, false, &ASTPropertyTest::create},
84+
{"Function Dependency Graph", "libsolidity", "functionDependencyGraphTests", false, false, &FunctionDependencyGraphTest::create},
8385
};
8486

8587
}

0 commit comments

Comments
 (0)