Skip to content

Commit

Permalink
Avoid crash in Rails/EnumUniqueness cop
Browse files Browse the repository at this point in the history
`Rails/EnumUniqueness` cop crashes when `enum` method receives a variable.

For example

```ruby
class Foo < ApplicationRecord
  var = {status: {open: 1, closed: 2}}
  enum var
end
```

```sh
$ rubocop --rails
An error occurred while Rails/EnumUniqueness cop was inspecting /tmp/tmp.sIFH7vguiW/app/models/foo.rb.

1 error occurred:
An error occurred while Rails/EnumUniqueness cop was inspecting /tmp/tmp.sIFH7vguiW/app/models/foo.rb.
Errors are usually caused by RuboCop bugs.
Please, report your problems to RuboCop's issue tracker.
Mention the following information in the issue report:
0.46.0 (using Parser 2.3.2.0, running on ruby 2.3.1 x86_64-linux)
For /tmp/tmp.sIFH7vguiW: configuration from /home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/config/default.yml
Inheriting configuration from /home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/config/enabled.yml
Inheriting configuration from /home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/config/disabled.yml
Inspecting 1 file
Scanning /tmp/tmp.sIFH7vguiW/app/models/foo.rb
undefined method `child_nodes' for nil:NilClass
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/rails/enum_uniqueness.rb:61:in `parse_args'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/rails/enum_uniqueness.rb:28:in `on_send'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:41:in `block (2 levels) in on_send'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:96:in `with_cop_error_handling'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:40:in `block in on_send'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:39:in `each'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:39:in `on_send'
(eval):2:in `block in on_begin'
(eval):2:in `each'
(eval):2:in `on_begin'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:45:in `on_begin'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/ast_node/traversal.rb:88:in `on_class'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:45:in `on_class'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/ast_node/traversal.rb:12:in `walk'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/commissioner.rb:58:in `investigate'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/team.rb:120:in `investigate'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/team.rb:108:in `offenses'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cop/team.rb:51:in `inspect_file'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:243:in `inspect_file'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:190:in `block in do_inspection_loop'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:222:in `block in iterate_until_no_changes'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:215:in `loop'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:215:in `iterate_until_no_changes'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:186:in `do_inspection_loop'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:101:in `block in file_offenses'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:111:in `file_offense_cache'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:99:in `file_offenses'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:90:in `process_file'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:68:in `block in each_inspected_file'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:65:in `each'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:65:in `reduce'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:65:in `each_inspected_file'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:57:in `inspect_files'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/runner.rb:36:in `run'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cli.rb:72:in `execute_runner'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/lib/rubocop/cli.rb:27:in `run'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/bin/rubocop:13:in `block in <top (required)>'
/usr/lib/ruby/2.3.0/benchmark.rb:308:in `realtime'
/home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.46.0/bin/rubocop:12:in `<top (required)>'
/home/pocke/.gem/ruby/2.3.0/bin/rubocop:23:in `load'
/home/pocke/.gem/ruby/2.3.0/bin/rubocop:23:in `<main>'
C

Offenses:

app/models/foo.rb:3:9: C: Style/SpaceInsideHashLiteralBraces: Space inside { missing.
  var = {status: {open: 1, closed: 2}}
        ^
app/models/foo.rb:3:18: C: Style/SpaceInsideHashLiteralBraces: Space inside { missing.
  var = {status: {open: 1, closed: 2}}
                 ^
app/models/foo.rb:3:37: C: Style/SpaceInsideHashLiteralBraces: Space inside } missing.
  var = {status: {open: 1, closed: 2}}
                                    ^
app/models/foo.rb:3:38: C: Style/SpaceInsideHashLiteralBraces: Space inside } missing.
  var = {status: {open: 1, closed: 2}}
                                     ^

1 file inspected, 4 offenses detected
Finished in 0.10733168199658394 seconds
```

I fixed the problem.
  • Loading branch information
pocke authored and bbatsov committed Dec 1, 2016
1 parent df0e1aa commit 1207b62
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,10 @@

## master (unreleased)

### Bug fixes

* [#xxxx](https://github.com/bbatsov/rubocop/pull/xxxx): Avoid crash in `Rails/EnumUniqueness` cop. ([@pocke][])

## 0.46.0 (2016-11-30)

### New features
Expand Down
28 changes: 10 additions & 18 deletions lib/rubocop/cop/rails/enum_uniqueness.rb
Expand Up @@ -20,17 +20,18 @@ module Rails
class EnumUniqueness < Cop
MSG = 'Duplicate value `%s` found in `%s` enum declaration.'.freeze

def on_send(node)
_receiver, method_name, *args = *node

return unless method_name == :enum

enum_name, enum_args = parse_args(args)
def_node_matcher :enum_call, <<-END
(send nil :enum (hash (pair (_ $_) $_)))
END

dupes = arr_dupes(enum_values(enum_args))
return if dupes.empty?
def on_send(node)
enum_call(node) do |enum_name, enum_args|
dupes = arr_dupes(enum_values(enum_args))
return if dupes.empty?

add_offense(node, :selector, format(MSG, dupes.join(','), enum_name))
add_offense(node, :selector,
format(MSG, dupes.join(','), enum_name))
end
end

private
Expand All @@ -56,15 +57,6 @@ def enum_hash_values(hash_node)
def arr_dupes(array)
array.select { |element| array.count(element) > 1 }.uniq
end

def parse_args(args)
enum_config = args.first.each_child_node.first.child_nodes

enum_name = enum_config.first.source
enum_opts = enum_config.last

[enum_name, enum_opts]
end
end
end
end
Expand Down
8 changes: 8 additions & 0 deletions spec/rubocop/cop/rails/enum_uniqueness_spec.rb
Expand Up @@ -34,4 +34,12 @@
expect(cop.messages).to be_empty
end
end

context 'when received a variable' do
it 'does not register an offence' do
inspect_source(cop, ['var = { status: { active: 0, archived: 1 } }',
'enum var'])
expect(cop.messages).to be_empty
end
end
end

0 comments on commit 1207b62

Please sign in to comment.