rdg 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +2 -2
  5. data/Gemfile +1 -1
  6. data/RELEASES.md +10 -0
  7. data/TODO.md +68 -0
  8. data/bin/ast +5 -4
  9. data/bin/cfg +5 -4
  10. data/lib/rdg/analysis/analyser.rb +30 -0
  11. data/lib/rdg/analysis/composite.rb +23 -0
  12. data/lib/rdg/analysis/context.rb +17 -0
  13. data/lib/rdg/analysis/equivalences.rb +25 -0
  14. data/lib/rdg/analysis/propagater.rb +51 -0
  15. data/lib/rdg/analysis/registry.rb +35 -0
  16. data/lib/rdg/cfg.rb +12 -41
  17. data/lib/rdg/control/begin.rb +6 -4
  18. data/lib/rdg/control/break.rb +19 -0
  19. data/lib/rdg/control/case.rb +25 -0
  20. data/lib/rdg/control/{while.rb → conditional_loop.rb} +8 -7
  21. data/lib/rdg/control/def.rb +21 -7
  22. data/lib/rdg/control/ensure.rb +30 -0
  23. data/lib/rdg/control/for.rb +29 -0
  24. data/lib/rdg/control/handler.rb +25 -0
  25. data/lib/rdg/control/if.rb +7 -6
  26. data/lib/rdg/control/jump.rb +33 -0
  27. data/lib/rdg/control/jump_to_start.rb +11 -0
  28. data/lib/rdg/control/next.rb +9 -0
  29. data/lib/rdg/control/none.rb +5 -3
  30. data/lib/rdg/control/redo.rb +9 -0
  31. data/lib/rdg/control/rescue.rb +31 -0
  32. data/lib/rdg/control/rescue_body.rb +29 -0
  33. data/lib/rdg/control/retry.rb +13 -0
  34. data/lib/rdg/control/return.rb +5 -6
  35. data/lib/rdg/control/when.rb +27 -0
  36. data/lib/rdg/graph/bidirected_adjacency_graph.rb +19 -0
  37. data/lib/rdg/graph/rgl/allow_duplicates.rb +45 -0
  38. data/lib/rdg/tree/ast.rb +15 -4
  39. data/lib/rdg/version.rb +1 -1
  40. data/rdg.gemspec +3 -2
  41. data/spec/integration/cfg/conditionals/case_spec.rb +66 -0
  42. data/spec/integration/cfg/{if_spec.rb → conditionals/if_spec.rb} +24 -9
  43. data/spec/integration/cfg/conditionals/unless_spec.rb +53 -0
  44. data/spec/integration/cfg/exceptions_spec.rb +131 -0
  45. data/spec/integration/cfg/loops/loop_control_spec.rb +90 -0
  46. data/spec/integration/cfg/loops/loop_spec.rb +70 -0
  47. data/spec/integration/cfg/sequence_spec.rb +7 -1
  48. data/spec/support/doubles/fake_ast.rb +15 -0
  49. data/spec/support/matchers/flow_between_matcher.rb +1 -1
  50. data/spec/unit/analysis/composite_spec.rb +47 -0
  51. data/spec/unit/analysis/equivalences_spec.rb +29 -0
  52. data/spec/unit/{control/analyser_spec.rb → analysis/propagater_spec.rb} +23 -12
  53. data/spec/unit/analysis/registry_spec.rb +61 -0
  54. data/spec/unit/control/begin_spec.rb +3 -6
  55. data/spec/unit/control/break_spec.rb +26 -0
  56. data/spec/unit/control/case_spec.rb +66 -0
  57. data/spec/unit/control/conditional_loop_spec.rb +22 -0
  58. data/spec/unit/control/ensure_spec.rb +33 -0
  59. data/spec/unit/control/for_spec.rb +26 -0
  60. data/spec/unit/control/handler_spec.rb +27 -0
  61. data/spec/unit/control/if_spec.rb +26 -18
  62. data/spec/unit/control/jump_spec.rb +43 -0
  63. data/spec/unit/control/jump_to_start_spec.rb +22 -0
  64. data/spec/unit/control/rescue_body_spec.rb +26 -0
  65. data/spec/unit/control/rescue_spec.rb +62 -0
  66. data/spec/unit/control/return_spec.rb +1 -10
  67. data/spec/unit/control/when_spec.rb +59 -0
  68. data/spec/unit/graph/bidirected_adjacency_graph_spec.rb +49 -0
  69. metadata +91 -18
  70. data/lib/rdg/control/analyser.rb +0 -44
  71. data/spec/integration/cfg/methods_spec.rb +0 -39
  72. data/spec/unit/control/def_spec.rb +0 -28
  73. 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
- require_relative "analyser"
1
+ require "rdg/analysis/propagater"
2
2
 
3
3
  module RDG
4
4
  module Control
5
- class While < Analyser
6
- def initialize(ast_node, graph, state)
7
- super(ast_node, graph, state)
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 start_nodes
16
- [@predicate]
16
+ def start_node
17
+ @predicate
17
18
  end
18
19
 
19
20
  def end_nodes
20
- [@body]
21
+ [@predicate]
21
22
  end
22
23
  end
23
24
  end
@@ -1,14 +1,28 @@
1
+ require "rdg/analysis/propagater"
2
+
1
3
  module RDG
2
4
  module Control
3
- class Def
4
- def initialize(ast_node, graph, state)
5
- @graph, @state = graph, state
6
- @name, @args, @body = ast_node.children
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 analyse
10
- @state[:current_method] = @name
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
@@ -1,10 +1,11 @@
1
- require_relative "analyser"
1
+ require "rdg/analysis/propagater"
2
2
 
3
3
  module RDG
4
4
  module Control
5
- class If < Analyser
6
- def initialize(ast_node, graph, state)
7
- super(ast_node, graph, state)
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 start_nodes
16
- [@predicate]
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
@@ -0,0 +1,11 @@
1
+ require_relative "jump"
2
+
3
+ module RDG
4
+ module Control
5
+ class JumpToStart < Jump
6
+ def new_successors
7
+ [equivalences.first(block.children.first)]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "jump_to_start"
2
+
3
+ module RDG
4
+ module Control
5
+ class Next < JumpToStart
6
+ register_analyser :next
7
+ end
8
+ end
9
+ end
@@ -1,10 +1,12 @@
1
+ require "rdg/analysis/analyser"
2
+
1
3
  module RDG
2
4
  module Control
3
- class None
4
- def initialize(_ast_node, _graph, _state)
5
- end
5
+ class None < Analysis::Analyser
6
+ register_default_analyser
6
7
 
7
8
  def analyse
9
+ # do nothing
8
10
  end
9
11
  end
10
12
  end
@@ -0,0 +1,9 @@
1
+ require_relative "jump_to_start"
2
+
3
+ module RDG
4
+ module Control
5
+ class Redo < JumpToStart
6
+ register_analyser :redo
7
+ end
8
+ end
9
+ end
@@ -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
@@ -0,0 +1,13 @@
1
+ require_relative "jump_to_start"
2
+
3
+ module RDG
4
+ module Control
5
+ class Retry < JumpToStart
6
+ register_analyser :retry
7
+
8
+ def block_types
9
+ %i(rescue)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,13 +1,12 @@
1
+ require "rdg/analysis/analyser"
2
+
1
3
  module RDG
2
4
  module Control
3
- class Return
4
- def initialize(ast_node, graph, state)
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
- return unless @state.key?(:current_method)
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