deep-cover-core 0.6.3.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rspec_all +3 -0
  4. data/.rubocop.yml +1 -0
  5. data/Gemfile +11 -0
  6. data/deep_cover_core.gemspec +46 -0
  7. data/lib/deep-cover.rb +3 -0
  8. data/lib/deep_cover/analyser/base.rb +104 -0
  9. data/lib/deep_cover/analyser/branch.rb +41 -0
  10. data/lib/deep_cover/analyser/covered_code_source.rb +21 -0
  11. data/lib/deep_cover/analyser/function.rb +14 -0
  12. data/lib/deep_cover/analyser/node.rb +54 -0
  13. data/lib/deep_cover/analyser/per_char.rb +38 -0
  14. data/lib/deep_cover/analyser/per_line.rb +41 -0
  15. data/lib/deep_cover/analyser/ruby25_like_branch.rb +211 -0
  16. data/lib/deep_cover/analyser/statement.rb +33 -0
  17. data/lib/deep_cover/analyser/stats.rb +54 -0
  18. data/lib/deep_cover/analyser/subset.rb +27 -0
  19. data/lib/deep_cover/analyser.rb +23 -0
  20. data/lib/deep_cover/auto_run.rb +71 -0
  21. data/lib/deep_cover/autoload_tracker.rb +215 -0
  22. data/lib/deep_cover/backports.rb +22 -0
  23. data/lib/deep_cover/base.rb +117 -0
  24. data/lib/deep_cover/basics.rb +22 -0
  25. data/lib/deep_cover/builtin_takeover.rb +10 -0
  26. data/lib/deep_cover/config.rb +104 -0
  27. data/lib/deep_cover/config_setter.rb +33 -0
  28. data/lib/deep_cover/core_ext/autoload_overrides.rb +112 -0
  29. data/lib/deep_cover/core_ext/coverage_replacement.rb +61 -0
  30. data/lib/deep_cover/core_ext/exec_callbacks.rb +27 -0
  31. data/lib/deep_cover/core_ext/instruction_sequence_load_iseq.rb +32 -0
  32. data/lib/deep_cover/core_ext/load_overrides.rb +19 -0
  33. data/lib/deep_cover/core_ext/require_overrides.rb +28 -0
  34. data/lib/deep_cover/coverage/analysis.rb +42 -0
  35. data/lib/deep_cover/coverage/persistence.rb +84 -0
  36. data/lib/deep_cover/coverage.rb +125 -0
  37. data/lib/deep_cover/covered_code.rb +145 -0
  38. data/lib/deep_cover/custom_requirer.rb +187 -0
  39. data/lib/deep_cover/flag_comment_associator.rb +68 -0
  40. data/lib/deep_cover/load.rb +66 -0
  41. data/lib/deep_cover/memoize.rb +48 -0
  42. data/lib/deep_cover/module_override.rb +39 -0
  43. data/lib/deep_cover/node/arguments.rb +51 -0
  44. data/lib/deep_cover/node/assignments.rb +273 -0
  45. data/lib/deep_cover/node/base.rb +155 -0
  46. data/lib/deep_cover/node/begin.rb +27 -0
  47. data/lib/deep_cover/node/block.rb +61 -0
  48. data/lib/deep_cover/node/branch.rb +32 -0
  49. data/lib/deep_cover/node/case.rb +113 -0
  50. data/lib/deep_cover/node/collections.rb +31 -0
  51. data/lib/deep_cover/node/const.rb +12 -0
  52. data/lib/deep_cover/node/def.rb +40 -0
  53. data/lib/deep_cover/node/empty_body.rb +32 -0
  54. data/lib/deep_cover/node/exceptions.rb +79 -0
  55. data/lib/deep_cover/node/if.rb +73 -0
  56. data/lib/deep_cover/node/keywords.rb +86 -0
  57. data/lib/deep_cover/node/literals.rb +100 -0
  58. data/lib/deep_cover/node/loops.rb +74 -0
  59. data/lib/deep_cover/node/mixin/can_augment_children.rb +65 -0
  60. data/lib/deep_cover/node/mixin/check_completion.rb +18 -0
  61. data/lib/deep_cover/node/mixin/child_can_be_empty.rb +27 -0
  62. data/lib/deep_cover/node/mixin/executed_after_children.rb +15 -0
  63. data/lib/deep_cover/node/mixin/execution_location.rb +66 -0
  64. data/lib/deep_cover/node/mixin/filters.rb +47 -0
  65. data/lib/deep_cover/node/mixin/flow_accounting.rb +71 -0
  66. data/lib/deep_cover/node/mixin/has_child.rb +145 -0
  67. data/lib/deep_cover/node/mixin/has_child_handler.rb +75 -0
  68. data/lib/deep_cover/node/mixin/has_tracker.rb +46 -0
  69. data/lib/deep_cover/node/mixin/is_statement.rb +20 -0
  70. data/lib/deep_cover/node/mixin/rewriting.rb +35 -0
  71. data/lib/deep_cover/node/mixin/wrapper.rb +15 -0
  72. data/lib/deep_cover/node/module.rb +66 -0
  73. data/lib/deep_cover/node/root.rb +20 -0
  74. data/lib/deep_cover/node/send.rb +161 -0
  75. data/lib/deep_cover/node/short_circuit.rb +42 -0
  76. data/lib/deep_cover/node/splat.rb +15 -0
  77. data/lib/deep_cover/node/variables.rb +16 -0
  78. data/lib/deep_cover/node.rb +23 -0
  79. data/lib/deep_cover/parser_ext/range.rb +21 -0
  80. data/lib/deep_cover/problem_with_diagnostic.rb +63 -0
  81. data/lib/deep_cover/reporter/base.rb +68 -0
  82. data/lib/deep_cover/reporter/html/base.rb +14 -0
  83. data/lib/deep_cover/reporter/html/index.rb +59 -0
  84. data/lib/deep_cover/reporter/html/site.rb +68 -0
  85. data/lib/deep_cover/reporter/html/source.rb +136 -0
  86. data/lib/deep_cover/reporter/html/template/assets/32px.png +0 -0
  87. data/lib/deep_cover/reporter/html/template/assets/40px.png +0 -0
  88. data/lib/deep_cover/reporter/html/template/assets/deep_cover.css +291 -0
  89. data/lib/deep_cover/reporter/html/template/assets/deep_cover.css.sass +336 -0
  90. data/lib/deep_cover/reporter/html/template/assets/jquery-3.2.1.min.js +4 -0
  91. data/lib/deep_cover/reporter/html/template/assets/jquery-3.2.1.min.map +1 -0
  92. data/lib/deep_cover/reporter/html/template/assets/jstree.css +1108 -0
  93. data/lib/deep_cover/reporter/html/template/assets/jstree.js +8424 -0
  94. data/lib/deep_cover/reporter/html/template/assets/jstreetable.js +1069 -0
  95. data/lib/deep_cover/reporter/html/template/assets/throbber.gif +0 -0
  96. data/lib/deep_cover/reporter/html/template/index.html.erb +75 -0
  97. data/lib/deep_cover/reporter/html/template/source.html.erb +35 -0
  98. data/lib/deep_cover/reporter/html.rb +15 -0
  99. data/lib/deep_cover/reporter/istanbul.rb +184 -0
  100. data/lib/deep_cover/reporter/text.rb +58 -0
  101. data/lib/deep_cover/reporter/tree/util.rb +86 -0
  102. data/lib/deep_cover/reporter.rb +10 -0
  103. data/lib/deep_cover/tools/blank.rb +25 -0
  104. data/lib/deep_cover/tools/builtin_coverage.rb +55 -0
  105. data/lib/deep_cover/tools/camelize.rb +13 -0
  106. data/lib/deep_cover/tools/content_tag.rb +11 -0
  107. data/lib/deep_cover/tools/covered.rb +9 -0
  108. data/lib/deep_cover/tools/execute_sample.rb +34 -0
  109. data/lib/deep_cover/tools/format.rb +18 -0
  110. data/lib/deep_cover/tools/format_char_cover.rb +19 -0
  111. data/lib/deep_cover/tools/format_generated_code.rb +27 -0
  112. data/lib/deep_cover/tools/indent_string.rb +26 -0
  113. data/lib/deep_cover/tools/merge.rb +16 -0
  114. data/lib/deep_cover/tools/number_lines.rb +22 -0
  115. data/lib/deep_cover/tools/our_coverage.rb +11 -0
  116. data/lib/deep_cover/tools/profiling.rb +68 -0
  117. data/lib/deep_cover/tools/render_template.rb +13 -0
  118. data/lib/deep_cover/tools/require_relative_dir.rb +12 -0
  119. data/lib/deep_cover/tools/scan_match_datas.rb +10 -0
  120. data/lib/deep_cover/tools/silence_warnings.rb +18 -0
  121. data/lib/deep_cover/tools/slice.rb +9 -0
  122. data/lib/deep_cover/tools/strip_heredoc.rb +18 -0
  123. data/lib/deep_cover/tools/truncate_backtrace.rb +32 -0
  124. data/lib/deep_cover/tools.rb +22 -0
  125. data/lib/deep_cover/tracker_bucket.rb +50 -0
  126. data/lib/deep_cover/tracker_hits_per_path.rb +35 -0
  127. data/lib/deep_cover/tracker_storage.rb +76 -0
  128. data/lib/deep_cover/tracker_storage_per_path.rb +34 -0
  129. data/lib/deep_cover/version.rb +5 -0
  130. data/lib/deep_cover.rb +22 -0
  131. metadata +329 -0
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepCover
4
+ class CustomRequirer
5
+ attr_reader :load_paths, :loaded_features, :filter
6
+ def initialize(load_paths: $LOAD_PATH, loaded_features: $LOADED_FEATURES, &filter)
7
+ @load_paths = load_paths
8
+ @loaded_features = loaded_features
9
+ @filter = filter
10
+ @paths_being_required = Set.new
11
+
12
+ # A Set of the loaded_features for faster access
13
+ @loaded_features_set = Set.new
14
+ # A dup of the loaded_features as they are expected to be for the Set to be valid
15
+ # If this is different from loaded_features, the set should be refreshed
16
+ @duped_loaded_features_used_for_set = []
17
+ end
18
+
19
+ # Returns a path to an existing file or nil if none can be found.
20
+ # The search follows how ruby search for files using the $LOAD_PATH, but limits
21
+ # those it checks based on the LoadPathsSubset.
22
+ #
23
+ # An absolute path is returned directly if it exists, otherwise nil is returned
24
+ # without searching anywhere else.
25
+ def resolve_path(path, extensions_to_try = ['.rb', '.so'])
26
+ if extensions_to_try
27
+ extensions_to_try = [''] if extensions_to_try.any? { |ext| path.end_with?(ext) }
28
+ else
29
+ extensions_to_try = ['']
30
+ end
31
+
32
+ abs_path = File.absolute_path(path)
33
+ path = abs_path if path.start_with?('./', '../')
34
+
35
+ paths_with_ext = extensions_to_try.map { |ext| path + ext }
36
+
37
+ refresh_loaded_features_set
38
+
39
+ # Doing this check in every case instead of only for absolute_path because ruby has some
40
+ # built-in $LOADED_FEATURES which aren't an absolute path. Ex: enumerator.so, thread.rb
41
+ path_from_loaded_features = first_path_from_loaded_features_set(paths_with_ext)
42
+ return path_from_loaded_features if path_from_loaded_features
43
+
44
+ if path == abs_path
45
+ paths_with_ext.each do |path_with_ext|
46
+ return path_with_ext if File.exist?(path_with_ext)
47
+ end
48
+ else
49
+ possible_paths = paths_with_load_paths(paths_with_ext)
50
+ path_from_loaded_features = first_path_from_loaded_features_set(possible_paths)
51
+ return path_from_loaded_features if path_from_loaded_features
52
+
53
+ possible_paths.each do |possible_path|
54
+ next unless File.exist?(possible_path)
55
+ # Ruby 2.5 changed some behaviors of require related to symlinks in $LOAD_PATH
56
+ # https://bugs.ruby-lang.org/issues/10222
57
+ return File.realpath(possible_path) if RUBY_VERSION >= '2.5'
58
+ return possible_path
59
+ end
60
+ end
61
+ nil
62
+ end
63
+
64
+ # Homemade #require to be able to instrument the code before it gets executed.
65
+ # Returns true when everything went right. (Same as regular ruby)
66
+ # Returns false when the found file was already required. (Same as regular ruby)
67
+ # Calls &fallback_block with the reason as parameter if the work couldn't be done.
68
+ # The possible reasons are:
69
+ # - :not_found if the file couldn't be found.
70
+ # - :not_in_covered_paths if the file is not in the paths to cover
71
+ # - :cover_failed if DeepCover couldn't apply instrumentation the file found.
72
+ # - :not_supported for files that are not supported (such as .so files)
73
+ # - :skipped if the filter block returned `true`
74
+ # Exceptions raised by the required code bubble up as normal, except for
75
+ # SyntaxError, which is turned into a :cover_failed which calls the fallback_block.
76
+ def require(path) # &fallback_block
77
+ path = path.to_s
78
+
79
+ found_path = resolve_path(path)
80
+
81
+ if found_path
82
+ return false if @loaded_features.include?(found_path)
83
+ return false if @paths_being_required.include?(found_path)
84
+ end
85
+
86
+ DeepCover.autoload_tracker.wrap_require(path, found_path) do
87
+ begin
88
+ # Either a problem with resolve_path, or a gem that will be added to the load_path by RubyGems
89
+ return yield(:not_found) unless found_path
90
+
91
+ @paths_being_required.add(found_path)
92
+ return yield(:not_in_covered_paths) unless DeepCover.within_lookup_paths?(found_path)
93
+ return yield(:not_supported) if found_path.end_with?('.so')
94
+ return yield(:skipped) if filter && filter.call(found_path)
95
+
96
+ cover_and_execute(found_path) { |reason| return yield(reason) }
97
+
98
+ @loaded_features << found_path
99
+ ensure
100
+ @paths_being_required.delete(found_path)
101
+ add_last_loaded_feature_to_set
102
+ end
103
+ end
104
+ true
105
+ end
106
+
107
+ # Homemade #load to be able to instrument the code before it gets executed.
108
+ # Note, this doesn't support the `wrap` parameter that ruby's #load has.
109
+ # Same yield/return behavior as CustomRequirer#require, except that it
110
+ # cannot return false #load doesn't care about a file already being executed.
111
+ def load(path) # &fallback_block
112
+ path = path.to_s
113
+
114
+ found_path = resolve_path(path, nil)
115
+
116
+ if found_path.nil?
117
+ # #load has a final fallback of always trying relative to current work directory
118
+ possible_path = File.absolute_path(path)
119
+ found_path = possible_path if File.exist?(possible_path)
120
+ end
121
+
122
+ return yield(:not_found) unless found_path
123
+ return yield(:not_in_covered_paths) unless DeepCover.within_lookup_paths?(found_path)
124
+
125
+ cover_and_execute(found_path) { |reason| return yield(reason) }
126
+
127
+ true
128
+ end
129
+
130
+ def is_being_required?(path)
131
+ found_path = resolve_path(path)
132
+ @paths_being_required.include?(found_path)
133
+ end
134
+
135
+ protected
136
+
137
+ # updates the loaded_features_set if it needs it
138
+ def refresh_loaded_features_set
139
+ return if @duped_loaded_features_used_for_set == @loaded_features
140
+
141
+ @duped_loaded_features_used_for_set = @loaded_features.dup
142
+ @loaded_features_set = Set.new(@duped_loaded_features_used_for_set)
143
+ end
144
+
145
+ # Returns the first path found in the loaded_features_set
146
+ # Should be called after doing a #refresh_loaded_features_set
147
+ def first_path_from_loaded_features_set(paths)
148
+ paths.detect { |path| @loaded_features_set.include?(path) }
149
+ end
150
+
151
+ # Called after a require, adds the last entry of loaded_features to the
152
+ # loaded_features_set and the clone used to check for a need to refresh
153
+ # the loaded_features_set. Doing this allows us to never need to update
154
+ # the loaded_feature_set from scratch (almost? this is a safety precaution)
155
+ def add_last_loaded_feature_to_set
156
+ loaded_feature = @loaded_features.last
157
+ unless @loaded_features_set.include?(loaded_feature)
158
+ @duped_loaded_features_used_for_set << loaded_feature
159
+ @loaded_features_set << loaded_feature
160
+ end
161
+ end
162
+
163
+ def paths_with_load_paths(paths)
164
+ paths.flat_map do |path|
165
+ @load_paths.map do |load_path|
166
+ File.absolute_path(path, load_path)
167
+ end
168
+ end
169
+ end
170
+
171
+ def cover_and_execute(path) # &fallback_block
172
+ covered_code = DeepCover.coverage.covered_code_or_warn(path)
173
+ if covered_code.nil?
174
+ yield(:cover_failed)
175
+ raise "The fallback_block is supposed to either return or break, but didn't do either"
176
+ end
177
+
178
+ success = covered_code.execute_code_or_warn
179
+ unless success
180
+ yield(:cover_failed)
181
+ raise "The fallback_block is supposed to either return or break, but didn't do either"
182
+ end
183
+
184
+ covered_code
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepCover
4
+ ##
5
+ # A processor which computes which lines to be considered flagged with the
6
+ # given lookup
7
+ #
8
+ class FlagCommentAssociator
9
+ ##
10
+ # @param [DeepCover::RootNode] ast
11
+ # @param [Array(Parser::Source::Comment)] comments
12
+ def initialize(covered_code, lookup = 'nocov')
13
+ @covered_code = covered_code
14
+ @lookup = /^#[\s#*-]*#{lookup}[\s#*-]*$/
15
+ @ranges = nil
16
+ end
17
+
18
+ def include?(range)
19
+ return false unless (exp = range.expression)
20
+ lineno = exp.line
21
+ ranges.any? { |r| r.cover? lineno }
22
+ end
23
+
24
+ def ranges
25
+ @ranges ||= compute_ranges
26
+ end
27
+
28
+ private
29
+
30
+ def compute_ranges
31
+ @ranges = []
32
+ @flag_start = nil
33
+ index_ast_lines
34
+ @covered_code.comments.each { |comment| process(comment) }
35
+ toggle_flag(@covered_code.buffer.last_line) # handle end of file in case of opened flag
36
+ @ranges
37
+ end
38
+
39
+ def process(comment)
40
+ return unless comment.text =~ @lookup
41
+ ln = comment.location.expression.line
42
+ toggle_flag(ln) unless line_has_only_comments?(ln)
43
+ toggle_flag(ln + 1)
44
+ end
45
+
46
+ def toggle_flag(lineno)
47
+ if @flag_start
48
+ @ranges << (@flag_start..(lineno - 1))
49
+ @flag_start = nil
50
+ else
51
+ @flag_start = lineno
52
+ end
53
+ end
54
+
55
+ def index_ast_lines
56
+ @starts = []
57
+ @covered_code.each_node do |node|
58
+ if (exp = node.expression)
59
+ @starts[exp.line] = true
60
+ end
61
+ end
62
+ end
63
+
64
+ def line_has_only_comments?(line)
65
+ !@starts[line]
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepCover
4
+ module Load
5
+ AUTOLOAD = %i[analyser autoload_tracker auto_run config
6
+ coverage covered_code custom_requirer
7
+ tracker_hits_per_path tracker_storage_per_path
8
+ flag_comment_associator memoize module_override node
9
+ problem_with_diagnostic reporter tracker_bucket
10
+ ]
11
+
12
+ def load_absolute_basics
13
+ require_relative 'base'
14
+ require_relative 'basics'
15
+ require_relative 'config_setter'
16
+ require_relative 'tools/camelize'
17
+ AUTOLOAD.each do |module_name|
18
+ DeepCover.autoload(Tools::Camelize.camelize(module_name), "#{__dir__}/#{module_name}")
19
+ end
20
+ DeepCover.autoload :VERSION, "#{__dir__}/version"
21
+ Object.autoload :Term, 'term/ansicolor'
22
+ Object.autoload :Terminal, 'terminal-table'
23
+ Object.autoload :YAML, 'yaml'
24
+ Object.autoload :Forwardable, 'forwardable'
25
+ end
26
+
27
+ def bootstrap
28
+ @bootstrapped ||= false # Avoid warning
29
+ return if @bootstrapped
30
+ require_relative 'backports'
31
+ require_relative 'tools'
32
+ @bootstrapped = true
33
+ end
34
+
35
+ def load_parser
36
+ @parser_loaded ||= false # Avoid warning
37
+ return if @parser_loaded
38
+ silence_warnings do
39
+ require 'parser'
40
+ require 'parser/current'
41
+ end
42
+ require_relative_dir 'parser_ext'
43
+ @parser_loaded = true
44
+ end
45
+
46
+ def load_pry
47
+ silence_warnings do # Avoid "WARN: Unresolved specs during Gem::Specification.reset"
48
+ require 'pry' # after `pry` calls `Gem.refresh`
49
+ end
50
+ end
51
+
52
+ def load_all
53
+ @all_loaded ||= false
54
+ return if @all_loaded
55
+ bootstrap
56
+ load_parser
57
+ AUTOLOAD.each do |module_name|
58
+ DeepCover.const_get(Tools::Camelize.camelize(module_name))
59
+ end
60
+ DeepCover.const_get(:VERSION)
61
+ @all_loaded = true
62
+ end
63
+ end
64
+
65
+ extend Load
66
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepCover
4
+ bootstrap
5
+
6
+ # Memoize is a quick way to prepend a module that defines
7
+ # the memoized methods as `@_cache ||= super.freeze`
8
+ # It also refines `freeze` to precache memoized methods
9
+ #
10
+ module Memoize
11
+ def self.included(base)
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ def freeze
16
+ self.class.memoized.each do |method|
17
+ send method
18
+ end
19
+ super
20
+ end
21
+
22
+ module ClassMethods
23
+ def memoized
24
+ @memoized ||= [].freeze
25
+ end
26
+
27
+ def memoizer_module
28
+ @memoizer_module ||= begin
29
+ mod = const_set(:Memoizer, Module.new)
30
+ prepend mod
31
+ mod
32
+ end
33
+ end
34
+
35
+ def memoize(*methods)
36
+ @memoized = (memoized | methods).freeze
37
+
38
+ methods.each do |method|
39
+ memoizer_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
40
+ def #{method} # def foo
41
+ @_#{method} ||= super.freeze # @_foo ||= super.freeze
42
+ end # end
43
+ RUBY
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepCover
4
+ # Helps redefine methods in overriden_modules.
5
+ # For each methods in Mod, this defines `<method>_with{out}_deep_cover`.
6
+ # Set `active` to true or false to alias <method> to one or the other.
7
+ module ModuleOverride
8
+ attr_reader :overriden_modules
9
+
10
+ def active=(active)
11
+ each do |mod, method_name|
12
+ mod.send :alias_method, method_name, :"#{method_name}_#{active ? 'with' : 'without'}_deep_cover"
13
+ if mod == ::Kernel
14
+ mod.send :private, method_name
15
+ end
16
+ end
17
+ end
18
+
19
+ def override(*modules)
20
+ @overriden_modules = modules
21
+ each do |mod, method_name|
22
+ mod.send :alias_method, :"#{method_name}_without_deep_cover", method_name
23
+ mod.send :define_method, :"#{method_name}_with_deep_cover", instance_method(method_name)
24
+ if mod == ::Kernel
25
+ mod.send :private, :"#{method_name}_without_deep_cover"
26
+ mod.send :private, :"#{method_name}_with_deep_cover"
27
+ end
28
+ end
29
+ end
30
+
31
+ def each(&block)
32
+ overriden_modules.each do |mod|
33
+ instance_methods(false).each do |method_name|
34
+ yield mod, method_name
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'assignments'
4
+
5
+ module DeepCover
6
+ class Node
7
+ class Arg < Node
8
+ has_child name: Symbol
9
+ def executable?
10
+ false
11
+ end
12
+ end
13
+ Kwarg = Arg
14
+
15
+ class Restarg < Node
16
+ has_child name: [Symbol, nil]
17
+ def executable?
18
+ false
19
+ end
20
+ end
21
+ Kwrestarg = Restarg
22
+
23
+ class Optarg < Node
24
+ has_tracker :default
25
+ has_child name: Symbol
26
+ has_child default: Node, flow_entry_count: :default_tracker_hits, rewrite: '(%{default_tracker};%{node})'
27
+
28
+ def executable?
29
+ false
30
+ end
31
+ end
32
+ Kwoptarg = Optarg
33
+
34
+ # foo(&block)
35
+ class Blockarg < Node
36
+ has_child name: Symbol
37
+
38
+ def executable?
39
+ false
40
+ end
41
+ end
42
+
43
+ class Args < Node
44
+ has_extra_children arguments: [Arg, Optarg, Restarg, Kwarg, Kwoptarg, Kwrestarg, Blockarg, Mlhs]
45
+
46
+ def executable?
47
+ false
48
+ end
49
+ end
50
+ end
51
+ end