Skip to content

Commit

Permalink
In a refinement, assign smells to the refined module or class
Browse files Browse the repository at this point in the history
  • Loading branch information
mvz committed Jan 3, 2021
1 parent fd8560b commit c304b81
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
16 changes: 16 additions & 0 deletions lib/reek/context/refinement_context.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

require_relative 'module_context'

module Reek
module Context
#
# A context wrapper for any refinement blocks found in a syntax tree.
#
class RefinementContext < ModuleContext
def full_name
exp.call.args.first.name
end
end
end
end
18 changes: 16 additions & 2 deletions lib/reek/context_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require_relative 'context/ghost_context'
require_relative 'context/method_context'
require_relative 'context/module_context'
require_relative 'context/refinement_context'
require_relative 'context/root_context'
require_relative 'context/send_context'
require_relative 'context/singleton_attribute_context'
Expand All @@ -20,7 +21,7 @@ module Reek
# counting. Ideally `ContextBuilder` would only build up the context tree and leave the
# statement and reference counting to the contexts.
#
# @quality :reek:TooManyMethods { max_methods: 31 }
# @quality :reek:TooManyMethods { max_methods: 32 }
# @quality :reek:UnusedPrivateMethod { exclude: [ !ruby/regexp /process_/ ] }
# @quality :reek:DataClump
class ContextBuilder
Expand Down Expand Up @@ -263,9 +264,16 @@ def process_super(exp, _parent)
#
# Counts non-empty blocks as one statement.
#
# A refinement block is handled differently and causes a RefinementContext
# to be opened.
#
def process_block(exp, _parent)
increase_statement_count_by(exp.block)
process(exp)
if exp.call.name == :refine
handle_refinement_block(exp)
else
process(exp)
end
end

# Handles `begin` and `kwbegin` nodes. `begin` nodes are created implicitly
Expand Down Expand Up @@ -508,6 +516,12 @@ def append_new_context(klass, *args)
end
end

def handle_refinement_block(exp)
inside_new_context(Context::RefinementContext, exp) do
process(exp)
end
end

def handle_send_for_modules(exp)
arg_names = exp.args.map { |arg| arg.children.first }
current_context.track_visibility(exp.name, arg_names)
Expand Down
16 changes: 16 additions & 0 deletions spec/reek/smell_detectors/utility_function_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,22 @@ def bravo(charlie) charlie.to_s; end
end
end

context 'when examining refinements' do
it 'reports on the refined class' do
src = <<-RUBY
module Alfa
refine Bravo do
def bravo(charlie)
charlie.delta.echo
end
end
end
RUBY

expect(src).to reek_of(:UtilityFunction, context: 'Bravo#bravo')
end
end

describe 'method visibility' do
it 'reports private methods' do
src = <<-RUBY
Expand Down

0 comments on commit c304b81

Please sign in to comment.