Class: RuboCop::Cop::Yast::Ops

Inherits:
RuboCop::Cop show all
Includes:
Niceness
Defined in:
lib/rubocop/cop/yast/ops.rb

Overview

This cop checks for Ops.* calls, it can autocorrect safe places or all places in unsafe mode

Constant Summary collapse

REPLACEMENT =

Ops replacement mapping

{
  add: "+"
}
MSG =
"Obsolete Ops.%s call found"

Constants included from Niceness

Niceness::NICE_GLOBAL_METHODS, Niceness::NICE_LITERAL_NODE_TYPES, Niceness::NICE_OPERATORS

Instance Method Summary collapse

Methods included from Niceness

#nice, #nice_begin, #nice_literal, #nice_send, #nice_variable

Constructor Details

#initialize(config = nil, options = nil) ⇒ Ops

Returns a new instance of Ops.



26
27
28
29
30
31
32
# File 'lib/rubocop/cop/yast/ops.rb', line 26

def initialize(config = nil, options = nil)
  super(config, options)

  @scopes = VariableScopeStack.new
  @safe_mode = cop_config["SafeMode"]
  @replaced_nodes = []
end

Instance Method Details

#on_and_asgn(node) ⇒ Object



103
104
105
106
107
108
109
# File 'lib/rubocop/cop/yast/ops.rb', line 103

def on_and_asgn(node)
  var, value = * node
  return if var.type != :lvasgn
  name = var.children[0]

  scope[name].nice &&= nice(value)
end

#on_block(_node) ⇒ Object Also known as: on_for



128
129
130
131
# File 'lib/rubocop/cop/yast/ops.rb', line 128

def on_block(_node)
  # ignore body, clean slate
  scope.clear
end

#on_case(node) ⇒ Object

def on_unless Does not exist. ‘unless` is parsed as an `if` with then_body and else_body swapped. Compare with `while` and `until` which cannot do that and thus need distinct node types. end



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/rubocop/cop/yast/ops.rb', line 83

def on_case(node)
  expr, *cases = *node
  process(expr)

  cases.each do |case_|
    scopes.with_copy do
      process(case_)
    end
  end

  # clean slate
  scope.clear
end

#on_class(node) ⇒ Object



68
69
70
# File 'lib/rubocop/cop/yast/ops.rb', line 68

def on_class(node)
  with_new_scope_rescuing_oops(node)
end

#on_def(node) ⇒ Object



56
57
58
# File 'lib/rubocop/cop/yast/ops.rb', line 56

def on_def(node)
  with_new_scope_rescuing_oops(node)
end

#on_defs(node) ⇒ Object



60
61
62
# File 'lib/rubocop/cop/yast/ops.rb', line 60

def on_defs(node)
  with_new_scope_rescuing_oops(node)
end

#on_ensure(_node) ⇒ Object



176
177
178
179
180
181
# File 'lib/rubocop/cop/yast/ops.rb', line 176

def on_ensure(_node)
  # (:ensure, guarded-code, ensuring-code)
  # guarded-code may be a :rescue or not

  scope.clear
end

#on_lvasgn(node) ⇒ Object



97
98
99
100
101
# File 'lib/rubocop/cop/yast/ops.rb', line 97

def on_lvasgn(node)
  name, value = * node
  return if value.nil? # and-asgn, or-asgn, resbody do this
  scope[name].nice = nice(value)
end

#on_module(node) ⇒ Object



64
65
66
# File 'lib/rubocop/cop/yast/ops.rb', line 64

def on_module(node)
  with_new_scope_rescuing_oops(node)
end

#on_or_asgn(node) ⇒ Object



111
112
113
114
115
116
117
# File 'lib/rubocop/cop/yast/ops.rb', line 111

def on_or_asgn(node)
  var, value = * node
  return if var.type != :lvasgn
  name = var.children[0]

  scope[name].nice ||= nice(value)
end

#on_resbody(_node) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/rubocop/cop/yast/ops.rb', line 163

def on_resbody(_node)
  # How it is parsed:
  # (:resbody, exception-types-or-nil, exception-variable-or-nil, body)
  # exception-types is an :array
  # exception-variable is a (:lvasgn, name), without a value

  # A rescue means that *some* previous code was skipped.
  # We know nothing. We could process the resbodies individually,
  # and join begin-block with else-block, but it is little worth
  # because they will contain few zombies.
  scope.clear
end

#on_rescue(node) ⇒ Object

Exceptions: ‘raise` is an ordinary :send for the parser



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/rubocop/cop/yast/ops.rb', line 146

def on_rescue(node)
  # (:rescue, begin-block, resbody..., else-block-or-nil)
  _begin_body, *_rescue_bodies, _else_body = *node

  # FIXME
  #  @source_rewriter.transaction do
  #    process(begin_body)
  #    process(else_body)
  #    rescue_bodies.each do |r|
  #      process(r)
  #    end
  #  end
  #  rescue TooComplexToTranslateError
  #    warning "begin-rescue is too complex to translate due to a retry"
  #  end
end

#on_retry(_node) ⇒ Object



183
184
185
186
187
# File 'lib/rubocop/cop/yast/ops.rb', line 183

def on_retry(_node)
  # that makes the :rescue a loop, top-down data-flow fails
  # FIXME
  # raise TooComplexToTranslateError
end

#on_sclass(node) ⇒ Object



72
73
74
# File 'lib/rubocop/cop/yast/ops.rb', line 72

def on_sclass(node)
  with_new_scope_rescuing_oops(node)
end

#on_send(node) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/rubocop/cop/yast/ops.rb', line 119

def on_send(node)
  return unless call?(node, :Ops, :add)

  _ops, method, a, b = *node
  return if !(nice(a) && nice(b)) && safe_mode

  add_offense(node, :selector, format(MSG, method))
end

#on_while(_node) ⇒ Object Also known as: on_until



134
135
136
137
138
139
140
# File 'lib/rubocop/cop/yast/ops.rb', line 134

def on_while(_node)
  # ignore both condition and body,
  # with a simplistic scope we cannot handle them

  # clean slate
  scope.clear
end

#process(node) ⇒ Object

FIXME



35
36
37
38
39
40
41
# File 'lib/rubocop/cop/yast/ops.rb', line 35

def process(node)
  return if node.nil?
  #  if ! @unsafe
  #  oops(node, RuntimeError.new("Unknown node type #{node.type}")) \
  #    unless HANDLED_NODE_TYPES.include? node.type
  #  end
end

#scopeObject

currently visible scope



44
45
46
# File 'lib/rubocop/cop/yast/ops.rb', line 44

def scope
  scopes.innermost
end

#with_new_scope_rescuing_oops(node, &block) ⇒ Object



48
49
50
51
52
53
54
# File 'lib/rubocop/cop/yast/ops.rb', line 48

def with_new_scope_rescuing_oops(node, &block)
  scopes.with_new do
    block.call if block_given?
  end
rescue => e
  oops(node, e)
end