Class: Reek::SmellDetectors::ControlParameterHelpers::ControlParameterFinder

Inherits:
Object
  • Object
show all
Defined in:
lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb

Overview

Finds cases of ControlParameter in a particular node for a particular parameter

Constant Summary collapse

CONDITIONAL_NODE_TYPES =
[:if, :case, :and, :or].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node, parameter) ⇒ ControlParameterFinder

Returns a new instance of ControlParameterFinder.

Parameters:

  • node (Reek::AST::Node)

    the node in our current scope, e.g. s(:def, :alfa,

    s(:args,
      s(:arg, :bravo),
    
  • parameter (Symbol)

    the parameter name in question e.g. in the example above this would be :bravo



20
21
22
23
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 20

def initialize(node, parameter)
  @node = node
  @parameter = parameter
end

Instance Attribute Details

#nodeObject (readonly, private)

Returns the value of attribute node.



47
48
49
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 47

def node
  @node
end

#parameterObject (readonly, private)

Returns the value of attribute parameter.



47
48
49
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 47

def parameter
  @parameter
end

Instance Method Details

#conditional_nodesArray<Reek::AST::Node> (private)

Returns the conditional nodes scoped below the current node.

Returns:

  • (Array<Reek::AST::Node>)

    the conditional nodes scoped below the current node



88
89
90
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 88

def conditional_nodes
  node.body_nodes(CONDITIONAL_NODE_TYPES)
end

#find_matchesArray<Reek::AST::Node>

Returns all nodes where the parameter is used for control flow.

Returns:

  • (Array<Reek::AST::Node>)

    all nodes where the parameter is used for control flow



28
29
30
31
32
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 28

def find_matches
  return [] if legitimate_uses?

  nested_finders.flat_map(&:find_matches) + uses_of_param_in_condition
end

#legitimate_uses?Boolean

Returns true if the parameter is not used for control flow.

Returns:

  • (Boolean)

    true if the parameter is not used for control flow



37
38
39
40
41
42
43
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 37

def legitimate_uses?
  return true if CallInConditionFinder.new(node, parameter).uses_param_in_call_in_condition?
  return true if parameter_used_in_body?
  return true if nested_finders.any?(&:legitimate_uses?)

  false
end

#nested_findersArray<ControlParameterFinder> (private)

Returns:



68
69
70
71
72
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 68

def nested_finders
  @nested_finders ||= conditional_nodes.flat_map do |node|
    self.class.new(node, parameter)
  end
end

#parameter_used_in_body?Boolean (private)

Returns if the parameter is used in the body of the method e.g. this

def alfa(bravo)

puts bravo
if bravo then charlie end

end

would cause this method to return true because of the “puts bravo”.

Returns:

  • (Boolean)

    if the parameter is used in the body of the method e.g. this

    def alfa(bravo)

    puts bravo
    if bravo then charlie end
    

    end

    would cause this method to return true because of the “puts bravo”



60
61
62
63
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 60

def parameter_used_in_body?
  nodes = node.body_nodes([:lvar], CONDITIONAL_NODE_TYPES)
  nodes.any? { |lvar_node| lvar_node.var_name == parameter }
end

#uses_of_param_in_conditionArray<Reek::AST::Node> (private)

Returns all nodes where the parameter is part of a condition, e.g. [s(:lvar, :charlie)].

Returns:

  • (Array<Reek::AST::Node>)

    all nodes where the parameter is part of a condition, e.g. [s(:lvar, :charlie)]



78
79
80
81
82
83
# File 'lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb', line 78

def uses_of_param_in_condition
  condition = node.condition
  return [] unless condition

  condition.each_node(:lvar).select { |inner| inner.var_name == parameter }
end