Class: SimpleCov::StaticCoverageExtractor::Visitor
- Inherits:
-
Prism::Visitor
- Object
- Prism::Visitor
- SimpleCov::StaticCoverageExtractor::Visitor
- Includes:
- ConditionFolding, LocationConventions, MethodCollector
- Defined in:
- lib/simplecov/static_coverage_extractor/visitor.rb
Overview
Prism visitor that accumulates branch and method tuples in the
shape Ruby's Coverage reports. Tuple ids are sequential across
the file — Coverage uses sequential ids too, so this matches the
conventional shape. Only defined when Prism is loadable;
StaticCoverageExtractor.available? is the runtime gate.
Constant Summary
Constants included from ConditionFolding
ConditionFolding::STATIC_CONDITION_TYPES
Constants included from LocationConventions
LocationConventions::LEGACY_COVERAGE_LOCATIONS
Instance Attribute Summary collapse
-
#branches ⇒ Object
readonly
Returns the value of attribute branches.
-
#methods ⇒ Object
readonly
Returns the value of attribute methods.
Instance Method Summary collapse
-
#initialize ⇒ Visitor
constructor
A new instance of Visitor.
- #visit_call_node(node) ⇒ Object
- #visit_case_match_node(node) ⇒ Object
-
#visit_case_node(node) ⇒ Object
case/whenandcase/in(pattern matching) parse as CaseNode and CaseMatchNode respectively. -
#visit_if_node(node) ⇒ Object
if/unless/ postfix-if / postfix-unless / ternary all parse as IfNode (or UnlessNode). - #visit_match_predicate_node(node) ⇒ Object
-
#visit_match_required_node(node) ⇒ Object
One-line pattern matching:
x => pattern(MatchRequiredNode) andx in pattern(MatchPredicateNode). -
#visit_program_node(node) ⇒ Object
Entry point for a parsed file.
- #visit_unless_node(node) ⇒ Object
- #visit_until_node(node) ⇒ Object
-
#visit_while_node(node) ⇒ Object
while/untilloops get a single:bodyarm.
Methods included from MethodCollector
#visit_class_node, #visit_def_node, #visit_module_node
Constructor Details
#initialize ⇒ Visitor
Returns a new instance of Visitor.
60 61 62 63 64 65 66 67 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 60 def initialize super @branches = {} @methods = {} @next_id = 0 @class_stack = [] @value_positions = nil end |
Instance Attribute Details
#branches ⇒ Object (readonly)
Returns the value of attribute branches.
58 59 60 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 58 def branches @branches end |
#methods ⇒ Object (readonly)
Returns the value of attribute methods.
58 59 60 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 58 def methods @methods end |
Instance Method Details
#visit_call_node(node) ⇒ Object
97 98 99 100 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 97 def visit_call_node(node) (node) if node.respond_to?(:safe_navigation?) && node. super end |
#visit_case_match_node(node) ⇒ Object
110 111 112 113 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 110 def visit_case_match_node(node) emit_case_like(node, :in) super end |
#visit_case_node(node) ⇒ Object
case/when and case/in (pattern matching) parse as CaseNode
and CaseMatchNode respectively. When there's no explicit else,
Coverage synthesizes one at the case's range.
105 106 107 108 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 105 def visit_case_node(node) emit_case_like(node, :when) super end |
#visit_if_node(node) ⇒ Object
if / unless / postfix-if / postfix-unless / ternary all parse
as IfNode (or UnlessNode). Both carry a then arm (the
statements body) and an optional subsequent (an ElseNode for
else, another IfNode for elsif). When the subsequent is
missing, Coverage synthesizes a :else arm attributed to the
whole condition's range — we do the same.
87 88 89 90 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 87 def visit_if_node(node) emit_if_like(node, :if) unless static_condition?(node.predicate) super end |
#visit_match_predicate_node(node) ⇒ Object
127 128 129 130 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 127 def visit_match_predicate_node(node) emit_oneline_pattern(node, node.pattern.location) if LEGACY_COVERAGE_LOCATIONS super end |
#visit_match_required_node(node) ⇒ Object
One-line pattern matching: x => pattern (MatchRequiredNode) and
x in pattern (MatchPredicateNode). Ruby 3.3's Coverage reports
these as a :case with an :in and an :else arm; 3.4 dropped
them entirely (no branch), so this is legacy-only. The two forms
differ only in where Coverage anchors the synthesized :else:
=> uses the whole expression, in uses just the pattern.
simplecov:disable branch — legacy-only arms; unreachable on the modern dogfood Ruby
122 123 124 125 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 122 def visit_match_required_node(node) emit_oneline_pattern(node, node.location) if LEGACY_COVERAGE_LOCATIONS super end |
#visit_program_node(node) ⇒ Object
Entry point for a parsed file. On legacy Rubies the location of an empty branch arm depends on whether its construct is in value (tail) position, so precompute that once for the whole tree before emitting anything. Modern Rubies don't need it (see LocationConventions), so the pass is skipped there.
74 75 76 77 78 79 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 74 def visit_program_node(node) # simplecov:disable branch — legacy-only arm; unreachable on the modern dogfood Ruby @value_positions = ValuePositions.call(node) if LEGACY_COVERAGE_LOCATIONS # simplecov:enable branch super end |
#visit_unless_node(node) ⇒ Object
92 93 94 95 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 92 def visit_unless_node(node) emit_if_like(node, :unless) unless static_condition?(node.predicate) super end |
#visit_until_node(node) ⇒ Object
140 141 142 143 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 140 def visit_until_node(node) emit_loop(node, :until) super end |
#visit_while_node(node) ⇒ Object
while / until loops get a single :body arm. No synthetic
else (the loop either runs the body or doesn't).
135 136 137 138 |
# File 'lib/simplecov/static_coverage_extractor/visitor.rb', line 135 def visit_while_node(node) emit_loop(node, :while) super end |