Class: Taski::StaticAnalysis::Visitor
- Inherits:
-
Prism::Visitor
- Object
- Prism::Visitor
- Taski::StaticAnalysis::Visitor
- Defined in:
- lib/taski/static_analysis/visitor.rb
Instance Attribute Summary collapse
-
#dependencies ⇒ Object
readonly
Returns the value of attribute dependencies.
Instance Method Summary collapse
-
#follow_method_calls ⇒ Object
After visiting, follow any method calls that need analysis.
-
#initialize(target_task_class, target_method = :run, methods_to_analyze = nil) ⇒ Visitor
constructor
A new instance of Visitor.
- #visit_call_node(node) ⇒ Object
- #visit_class_node(node) ⇒ Object
- #visit_def_node(node) ⇒ Object
- #visit_module_node(node) ⇒ Object
Constructor Details
#initialize(target_task_class, target_method = :run, methods_to_analyze = nil) ⇒ Visitor
Returns a new instance of Visitor.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/taski/static_analysis/visitor.rb', line 13 def initialize(target_task_class, target_method = :run, methods_to_analyze = nil) super() @target_task_class = target_task_class @target_method = target_method @dependencies = Set.new @in_target_method = false @current_namespace_path = [] # Methods to analyze: starts with just the target method, grows as we find calls @methods_to_analyze = methods_to_analyze || Set.new([@target_method]) # Track which methods we've already analyzed to prevent infinite loops @analyzed_methods = Set.new # Collect method calls made within analyzed methods (for following) @method_calls_to_follow = Set.new # Store method definitions found in the class for later analysis @class_method_defs = {} end |
Instance Attribute Details
#dependencies ⇒ Object (readonly)
Returns the value of attribute dependencies.
8 9 10 |
# File 'lib/taski/static_analysis/visitor.rb', line 8 def dependencies @dependencies end |
Instance Method Details
#follow_method_calls ⇒ Object
After visiting, follow any method calls that need analysis
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/taski/static_analysis/visitor.rb', line 66 def follow_method_calls new_methods = @method_calls_to_follow - @analyzed_methods return if new_methods.empty? # Add new methods to analyze @methods_to_analyze.merge(new_methods) @method_calls_to_follow.clear # Re-analyze the class methods # Set namespace path from target class name for constant resolution @current_namespace_path = @target_task_class.name.split("::") @class_method_defs.each do |method_name, method_node| next unless new_methods.include?(method_name) @analyzed_methods.add(method_name) @in_target_method = true @current_analyzing_method = method_name visit(method_node) @in_target_method = false @current_analyzing_method = nil end # Recursively follow any new calls discovered follow_method_calls end |
#visit_call_node(node) ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/taski/static_analysis/visitor.rb', line 57 def visit_call_node(node) if @in_target_method detect_task_dependency(node) detect_method_call_to_follow(node) end super end |
#visit_class_node(node) ⇒ Object
30 31 32 33 34 35 36 37 38 |
# File 'lib/taski/static_analysis/visitor.rb', line 30 def visit_class_node(node) within_namespace(extract_constant_name(node.constant_path)) do if in_target_class? # First pass: collect all method definitions in the target class collect_method_definitions(node) end super end end |
#visit_def_node(node) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/taski/static_analysis/visitor.rb', line 44 def visit_def_node(node) if in_target_class? && should_analyze_method?(node.name) @analyzed_methods.add(node.name) @in_target_method = true @current_analyzing_method = node.name super @in_target_method = false @current_analyzing_method = nil else super end end |
#visit_module_node(node) ⇒ Object
40 41 42 |
# File 'lib/taski/static_analysis/visitor.rb', line 40 def visit_module_node(node) within_namespace(extract_constant_name(node.constant_path)) { super } end |