Class: Spoom::Deadcode::Remover::NodeFinder

Inherits:
Visitor
  • Object
show all
Defined in:
lib/spoom/deadcode/remover.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Visitor

#visit_alias_global_variable_node, #visit_alias_method_node, #visit_alternation_pattern_node, #visit_and_node, #visit_arguments_node, #visit_array_node, #visit_array_pattern_node, #visit_assoc_node, #visit_assoc_splat_node, #visit_back_reference_read_node, #visit_begin_node, #visit_block_argument_node, #visit_block_local_variable_node, #visit_block_node, #visit_block_parameter_node, #visit_block_parameters_node, #visit_break_node, #visit_call_and_write_node, #visit_call_node, #visit_call_operator_write_node, #visit_call_or_write_node, #visit_call_target_node, #visit_capture_pattern_node, #visit_case_match_node, #visit_case_node, #visit_child_nodes, #visit_class_node, #visit_class_variable_and_write_node, #visit_class_variable_operator_write_node, #visit_class_variable_or_write_node, #visit_class_variable_read_node, #visit_class_variable_target_node, #visit_class_variable_write_node, #visit_constant_and_write_node, #visit_constant_operator_write_node, #visit_constant_or_write_node, #visit_constant_path_and_write_node, #visit_constant_path_node, #visit_constant_path_operator_write_node, #visit_constant_path_or_write_node, #visit_constant_path_target_node, #visit_constant_path_write_node, #visit_constant_read_node, #visit_constant_target_node, #visit_constant_write_node, #visit_def_node, #visit_defined_node, #visit_else_node, #visit_embedded_statements_node, #visit_embedded_variable_node, #visit_ensure_node, #visit_false_node, #visit_find_pattern_node, #visit_flip_flop_node, #visit_float_node, #visit_for_node, #visit_forwarding_arguments_node, #visit_forwarding_parameter_node, #visit_forwarding_super_node, #visit_global_variable_and_write_node, #visit_global_variable_operator_write_node, #visit_global_variable_or_write_node, #visit_global_variable_read_node, #visit_global_variable_target_node, #visit_global_variable_write_node, #visit_hash_node, #visit_hash_pattern_node, #visit_if_node, #visit_imaginary_node, #visit_implicit_node, #visit_implicit_rest_node, #visit_in_node, #visit_index_and_write_node, #visit_index_operator_write_node, #visit_index_or_write_node, #visit_index_target_node, #visit_instance_variable_and_write_node, #visit_instance_variable_operator_write_node, #visit_instance_variable_or_write_node, #visit_instance_variable_read_node, #visit_instance_variable_target_node, #visit_instance_variable_write_node, #visit_integer_node, #visit_interpolated_match_last_line_node, #visit_interpolated_regular_expression_node, #visit_interpolated_string_node, #visit_interpolated_symbol_node, #visit_interpolated_x_string_node, #visit_keyword_hash_node, #visit_keyword_rest_parameter_node, #visit_lambda_node, #visit_local_variable_and_write_node, #visit_local_variable_operator_write_node, #visit_local_variable_or_write_node, #visit_local_variable_read_node, #visit_local_variable_target_node, #visit_local_variable_write_node, #visit_match_last_line_node, #visit_match_predicate_node, #visit_match_required_node, #visit_match_write_node, #visit_missing_node, #visit_module_node, #visit_multi_target_node, #visit_multi_write_node, #visit_next_node, #visit_nil_node, #visit_no_keywords_parameter_node, #visit_numbered_parameters_node, #visit_numbered_reference_read_node, #visit_optional_keyword_parameter_node, #visit_optional_parameter_node, #visit_or_node, #visit_parameters_node, #visit_parentheses_node, #visit_pinned_expression_node, #visit_pinned_variable_node, #visit_post_execution_node, #visit_pre_execution_node, #visit_program_node, #visit_range_node, #visit_rational_node, #visit_redo_node, #visit_regular_expression_node, #visit_required_keyword_parameter_node, #visit_required_parameter_node, #visit_rescue_modifier_node, #visit_rescue_node, #visit_rest_parameter_node, #visit_retry_node, #visit_return_node, #visit_self_node, #visit_singleton_class_node, #visit_source_encoding_node, #visit_source_file_node, #visit_source_line_node, #visit_splat_node, #visit_statements_node, #visit_string_node, #visit_super_node, #visit_symbol_node, #visit_true_node, #visit_undef_node, #visit_unless_node, #visit_until_node, #visit_when_node, #visit_while_node, #visit_x_string_node, #visit_yield_node

Constructor Details

#initialize(location, kind) ⇒ NodeFinder

: (Location location, Definition::Kind? kind) -> void



598
599
600
601
602
603
604
# File 'lib/spoom/deadcode/remover.rb', line 598

def initialize(location, kind)
  super()
  @location = location
  @kind = kind
  @node = T.let(nil, T.nilable(Prism::Node))
  @nodes_nesting = T.let([], T::Array[Prism::Node])
end

Instance Attribute Details

#nodeObject (readonly)

: Prism::Node?



592
593
594
# File 'lib/spoom/deadcode/remover.rb', line 592

def node
  @node
end

#nodes_nestingObject (readonly)

: Array



595
596
597
# File 'lib/spoom/deadcode/remover.rb', line 595

def nodes_nesting
  @nodes_nesting
end

Class Method Details

.find(source, location, kind) ⇒ Object

: (String source, Location location, Definition::Kind? kind) -> NodeContext



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/spoom/deadcode/remover.rb', line 533

def find(source, location, kind)
  result = Prism.parse(source)

  unless result.success?
    message = result.errors.map do |e|
      "#{e.message} (at #{e.location.start_line}:#{e.location.start_column})."
    end.join(" ")

    raise ParseError, "Error while parsing #{location.file}: #{message}"
  end

  visitor = new(location, kind)
  visitor.visit(result.value)

  node = visitor.node
  unless node
    raise Error, "Can't find node at #{location}"
  end

  if kind && !node_match_kind?(node, kind)
    raise Error, "Can't find node at #{location}, expected #{kind} but got #{node.class}"
  end

   = T.let(
    result.comments.to_h do |comment|
      [comment.location.start_line, comment]
    end,
    T::Hash[Integer, Prism::Comment],
  )

  NodeContext.new(source, , node, visitor.nodes_nesting)
end

.node_match_kind?(node, kind) ⇒ Boolean

: (Prism::Node node, Definition::Kind kind) -> bool

Returns:

  • (Boolean)


567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
# File 'lib/spoom/deadcode/remover.rb', line 567

def node_match_kind?(node, kind)
  case kind
  when Definition::Kind::AttrReader, Definition::Kind::AttrWriter
    node.is_a?(Prism::SymbolNode)
  when Definition::Kind::Class
    node.is_a?(Prism::ClassNode)
  when Definition::Kind::Constant
    node.is_a?(Prism::ConstantWriteNode) ||
      node.is_a?(Prism::ConstantAndWriteNode) ||
      node.is_a?(Prism::ConstantOrWriteNode) ||
      node.is_a?(Prism::ConstantOperatorWriteNode) ||
      node.is_a?(Prism::ConstantPathWriteNode) ||
      node.is_a?(Prism::ConstantPathAndWriteNode) ||
      node.is_a?(Prism::ConstantPathOrWriteNode) ||
      node.is_a?(Prism::ConstantPathOperatorWriteNode) ||
      node.is_a?(Prism::ConstantTargetNode)
  when Definition::Kind::Method
    node.is_a?(Prism::DefNode)
  when Definition::Kind::Module
    node.is_a?(Prism::ModuleNode)
  end
end

Instance Method Details

#visit(node) ⇒ Object

: (Prism::Node? node) -> void



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/spoom/deadcode/remover.rb', line 608

def visit(node)
  return unless node

  location = Location.from_prism(@location.file, node.location)

  if location == @location
    # We found the node we're looking for at `@location`
    @node = node

    # The node we found matches the kind we're looking for, we can stop here
    return if @kind && self.class.node_match_kind?(node, @kind)

    # There may be a more precise child inside the node that also matches `@location`, let's visit them
    @nodes_nesting << node
    super(node)
    @nodes_nesting.pop if @nodes_nesting.last == @node
  elsif location.include?(@location)
    # The node we're looking for is inside `node`, let's visit it
    @nodes_nesting << node
    super(node)
  end
end