rdg 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -2
- data/Gemfile +1 -1
- data/RELEASES.md +10 -0
- data/TODO.md +68 -0
- data/bin/ast +5 -4
- data/bin/cfg +5 -4
- data/lib/rdg/analysis/analyser.rb +30 -0
- data/lib/rdg/analysis/composite.rb +23 -0
- data/lib/rdg/analysis/context.rb +17 -0
- data/lib/rdg/analysis/equivalences.rb +25 -0
- data/lib/rdg/analysis/propagater.rb +51 -0
- data/lib/rdg/analysis/registry.rb +35 -0
- data/lib/rdg/cfg.rb +12 -41
- data/lib/rdg/control/begin.rb +6 -4
- data/lib/rdg/control/break.rb +19 -0
- data/lib/rdg/control/case.rb +25 -0
- data/lib/rdg/control/{while.rb → conditional_loop.rb} +8 -7
- data/lib/rdg/control/def.rb +21 -7
- data/lib/rdg/control/ensure.rb +30 -0
- data/lib/rdg/control/for.rb +29 -0
- data/lib/rdg/control/handler.rb +25 -0
- data/lib/rdg/control/if.rb +7 -6
- data/lib/rdg/control/jump.rb +33 -0
- data/lib/rdg/control/jump_to_start.rb +11 -0
- data/lib/rdg/control/next.rb +9 -0
- data/lib/rdg/control/none.rb +5 -3
- data/lib/rdg/control/redo.rb +9 -0
- data/lib/rdg/control/rescue.rb +31 -0
- data/lib/rdg/control/rescue_body.rb +29 -0
- data/lib/rdg/control/retry.rb +13 -0
- data/lib/rdg/control/return.rb +5 -6
- data/lib/rdg/control/when.rb +27 -0
- data/lib/rdg/graph/bidirected_adjacency_graph.rb +19 -0
- data/lib/rdg/graph/rgl/allow_duplicates.rb +45 -0
- data/lib/rdg/tree/ast.rb +15 -4
- data/lib/rdg/version.rb +1 -1
- data/rdg.gemspec +3 -2
- data/spec/integration/cfg/conditionals/case_spec.rb +66 -0
- data/spec/integration/cfg/{if_spec.rb → conditionals/if_spec.rb} +24 -9
- data/spec/integration/cfg/conditionals/unless_spec.rb +53 -0
- data/spec/integration/cfg/exceptions_spec.rb +131 -0
- data/spec/integration/cfg/loops/loop_control_spec.rb +90 -0
- data/spec/integration/cfg/loops/loop_spec.rb +70 -0
- data/spec/integration/cfg/sequence_spec.rb +7 -1
- data/spec/support/doubles/fake_ast.rb +15 -0
- data/spec/support/matchers/flow_between_matcher.rb +1 -1
- data/spec/unit/analysis/composite_spec.rb +47 -0
- data/spec/unit/analysis/equivalences_spec.rb +29 -0
- data/spec/unit/{control/analyser_spec.rb → analysis/propagater_spec.rb} +23 -12
- data/spec/unit/analysis/registry_spec.rb +61 -0
- data/spec/unit/control/begin_spec.rb +3 -6
- data/spec/unit/control/break_spec.rb +26 -0
- data/spec/unit/control/case_spec.rb +66 -0
- data/spec/unit/control/conditional_loop_spec.rb +22 -0
- data/spec/unit/control/ensure_spec.rb +33 -0
- data/spec/unit/control/for_spec.rb +26 -0
- data/spec/unit/control/handler_spec.rb +27 -0
- data/spec/unit/control/if_spec.rb +26 -18
- data/spec/unit/control/jump_spec.rb +43 -0
- data/spec/unit/control/jump_to_start_spec.rb +22 -0
- data/spec/unit/control/rescue_body_spec.rb +26 -0
- data/spec/unit/control/rescue_spec.rb +62 -0
- data/spec/unit/control/return_spec.rb +1 -10
- data/spec/unit/control/when_spec.rb +59 -0
- data/spec/unit/graph/bidirected_adjacency_graph_spec.rb +49 -0
- metadata +91 -18
- data/lib/rdg/control/analyser.rb +0 -44
- data/spec/integration/cfg/methods_spec.rb +0 -39
- data/spec/unit/control/def_spec.rb +0 -28
- data/spec/unit/control/while_spec.rb +0 -25
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "jump"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class Break < Jump
|
6
|
+
register_analyser :break
|
7
|
+
|
8
|
+
def new_successors
|
9
|
+
graph
|
10
|
+
.each_successor(test)
|
11
|
+
.reject { |s| s.ancestors.include?(block) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test
|
15
|
+
equivalences.first(block.children.first)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class Case < Analysis::Propagater
|
6
|
+
register_analyser :case
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@expression, *@consequences = nodes
|
10
|
+
end
|
11
|
+
|
12
|
+
def internal_flow_edges
|
13
|
+
nodes.each_cons(2).to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_node
|
17
|
+
@expression
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_nodes
|
21
|
+
@consequences
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
|
-
|
1
|
+
require "rdg/analysis/propagater"
|
2
2
|
|
3
3
|
module RDG
|
4
4
|
module Control
|
5
|
-
class
|
6
|
-
|
7
|
-
|
5
|
+
class ConditionalLoop < Analysis::Propagater
|
6
|
+
register_analyser :while, :until
|
7
|
+
|
8
|
+
def prepare
|
8
9
|
@predicate, @body = children
|
9
10
|
end
|
10
11
|
|
@@ -12,12 +13,12 @@ module RDG
|
|
12
13
|
[[@predicate, @body], [@body, @predicate]]
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
-
|
16
|
+
def start_node
|
17
|
+
@predicate
|
17
18
|
end
|
18
19
|
|
19
20
|
def end_nodes
|
20
|
-
[@
|
21
|
+
[@predicate]
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
data/lib/rdg/control/def.rb
CHANGED
@@ -1,14 +1,28 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
|
1
3
|
module RDG
|
2
4
|
module Control
|
3
|
-
class Def
|
4
|
-
def
|
5
|
-
|
6
|
-
|
5
|
+
class Def < Analysis::Propagater
|
6
|
+
register_analyser :def
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
_name, _args, @body = children
|
10
|
+
end
|
11
|
+
|
12
|
+
def internal_flow_edges
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_node
|
17
|
+
@body
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_nodes
|
21
|
+
[@body]
|
7
22
|
end
|
8
23
|
|
9
|
-
def
|
10
|
-
@
|
11
|
-
@graph.add_edge(@name, @body)
|
24
|
+
def nodes
|
25
|
+
[@body]
|
12
26
|
end
|
13
27
|
end
|
14
28
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class Ensure < Analysis::Propagater
|
6
|
+
register_analyser :ensure
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@body, @finaliser = nodes
|
10
|
+
end
|
11
|
+
|
12
|
+
def analyse
|
13
|
+
super
|
14
|
+
registry.prepend_for(@finaliser, Handler)
|
15
|
+
end
|
16
|
+
|
17
|
+
def internal_flow_edges
|
18
|
+
[[@body, @finaliser]]
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_node
|
22
|
+
@body
|
23
|
+
end
|
24
|
+
|
25
|
+
def end_nodes
|
26
|
+
[@finaliser]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class For < Analysis::Propagater
|
6
|
+
register_analyser :for
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
_, @iterable, @body = children
|
10
|
+
end
|
11
|
+
|
12
|
+
def internal_flow_edges
|
13
|
+
[[@iterable, @body], [@body, @iterable]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_node
|
17
|
+
@iterable
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_nodes
|
21
|
+
[@iterable]
|
22
|
+
end
|
23
|
+
|
24
|
+
def nodes
|
25
|
+
[@iterable, @body]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rdg/analysis/analyser"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class Handler < Analysis::Analyser
|
6
|
+
def analyse
|
7
|
+
add_an_edge_from_every_main_node_to_the_handler
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def add_an_edge_from_every_main_node_to_the_handler
|
13
|
+
main.each { |m| graph.add_edge(m, @ast_node) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def main
|
17
|
+
equivalences.all(block.children.first)
|
18
|
+
end
|
19
|
+
|
20
|
+
def block
|
21
|
+
@ast_node.parent
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/rdg/control/if.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
|
1
|
+
require "rdg/analysis/propagater"
|
2
2
|
|
3
3
|
module RDG
|
4
4
|
module Control
|
5
|
-
class If <
|
6
|
-
|
7
|
-
|
5
|
+
class If < Analysis::Propagater
|
6
|
+
register_analyser :if
|
7
|
+
|
8
|
+
def prepare
|
8
9
|
@predicate, *@consequences = children.reject(&:empty?)
|
9
10
|
end
|
10
11
|
|
@@ -12,8 +13,8 @@ module RDG
|
|
12
13
|
@consequences.map { |consequence| [@predicate, consequence] }
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
-
|
16
|
+
def start_node
|
17
|
+
@predicate
|
17
18
|
end
|
18
19
|
|
19
20
|
def end_nodes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "rdg/analysis/analyser"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class Jump < Analysis::Analyser
|
6
|
+
def analyse
|
7
|
+
return unless block
|
8
|
+
remove_all_successors
|
9
|
+
add_new_successors
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def block_types
|
15
|
+
%i(while until for)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def remove_all_successors
|
21
|
+
graph.each_successor(@ast_node) { |s| graph.remove_edge(@ast_node, s) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_new_successors
|
25
|
+
new_successors.each { |s| graph.add_edge(@ast_node, s) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def block
|
29
|
+
@ast_node.ancestors.detect { |a| block_types.include?(a.type) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/rdg/control/none.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
require_relative "handler"
|
3
|
+
|
4
|
+
module RDG
|
5
|
+
module Control
|
6
|
+
class Rescue < Analysis::Propagater
|
7
|
+
register_analyser :rescue
|
8
|
+
|
9
|
+
def prepare
|
10
|
+
@main, *@handlers, @alternative = children
|
11
|
+
end
|
12
|
+
|
13
|
+
def analyse
|
14
|
+
super
|
15
|
+
@handlers.each { |h| registry.prepend_for(h, Handler) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def internal_flow_edges
|
19
|
+
@alternative.empty? ? [] : [[@main, @alternative]]
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_node
|
23
|
+
@main
|
24
|
+
end
|
25
|
+
|
26
|
+
def end_nodes
|
27
|
+
@alternative.empty? ? nodes : @handlers.push(@alternative)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class RescueBody < Analysis::Propagater
|
6
|
+
register_analyser :resbody
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
_exception_types, _variable_name, *@statements = children
|
10
|
+
end
|
11
|
+
|
12
|
+
def internal_flow_edges
|
13
|
+
@statements.each_cons(2).to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_node
|
17
|
+
@statements.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_nodes
|
21
|
+
@statements.last(1)
|
22
|
+
end
|
23
|
+
|
24
|
+
def nodes
|
25
|
+
@statements
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/rdg/control/return.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
+
require "rdg/analysis/analyser"
|
2
|
+
|
1
3
|
module RDG
|
2
4
|
module Control
|
3
|
-
class Return
|
4
|
-
|
5
|
-
@graph, @ast_node, @state = graph, ast_node, state
|
6
|
-
end
|
5
|
+
class Return < Analysis::Analyser
|
6
|
+
register_analyser :return
|
7
7
|
|
8
8
|
def analyse
|
9
|
-
|
10
|
-
@graph.each_successor(@ast_node) { |s| @graph.remove_edge(@ast_node, s) }
|
9
|
+
graph.each_successor(@ast_node) { |s| graph.remove_edge(@ast_node, s) }
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "rdg/analysis/propagater"
|
2
|
+
|
3
|
+
module RDG
|
4
|
+
module Control
|
5
|
+
class When < Analysis::Propagater
|
6
|
+
register_analyser :when
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@test, @action = children
|
10
|
+
end
|
11
|
+
|
12
|
+
def internal_flow_edges
|
13
|
+
[[@test, @action]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_node
|
17
|
+
@test
|
18
|
+
end
|
19
|
+
|
20
|
+
def propogate_outgoing_flow
|
21
|
+
successors = graph.each_successor(@ast_node).to_a
|
22
|
+
graph.add_edge(@test, successors.first)
|
23
|
+
graph.add_edge(@action, successors.last)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rgl/adjacency"
|
2
|
+
require "rgl/dot"
|
3
|
+
require_relative "rgl/allow_duplicates"
|
4
|
+
|
5
|
+
module RDG
|
6
|
+
module Graph
|
7
|
+
class BidirectedAdjacencyGraph < ::RGL::DirectedAdjacencyGraph
|
8
|
+
include RGL::AllowDuplicates
|
9
|
+
|
10
|
+
def each_predecessor(vertex, &block)
|
11
|
+
each_vertex.select { |v| each_adjacent(v).include?(vertex) }.each(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def each_successor(vertex, &block)
|
15
|
+
each_adjacent(vertex, &block) if has_vertex?(vertex)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|