lib/rubocop/ast_node.rb in rubocop-0.37.0 vs lib/rubocop/ast_node.rb in rubocop-0.37.1

- old
+ new

@@ -41,12 +41,10 @@ :or, :postexe, :redo, :rescue, :retry, :return, :self, :super, :zsuper, :then, :undef, :until, :when, :while, :yield].freeze OPERATOR_KEYWORDS = [:and, :or].freeze SPECIAL_KEYWORDS = %w(__FILE__ __LINE__ __ENCODING__).freeze - RSPEC_METHODS = [:describe, :it].freeze - # def_matcher can be used to define a pattern-matching method on Node class << self def def_matcher(method_name, pattern_str) compiler = RuboCop::NodePattern::Compiler.new(pattern_str, 'self') src = "def #{method_name}(" \ @@ -329,27 +327,51 @@ when :class, :module, :casgn # TODO: if constant name has cbase (leading ::), then we don't need # to keep traversing up through nested classes/modules ancestor.defined_module_name when :sclass - obj = ancestor.children[0] - # TODO: look for constant definition and see if it is nested - # inside a class or module - return "#<Class:#{obj.const_name}>" if obj.const_type? - return "#<Class:#{ancestor.parent_module_name}>" if obj.self_type? - return nil + return parent_module_name_for_sclass(ancestor) else # block - return nil if ancestor.known_dsl? - if ancestor.method_name == :class_eval && ancestor.receiver - return nil unless ancestor.receiver.const_type? - ancestor.receiver.const_name + if ancestor.method_name == :class_eval + # `class_eval` with no receiver applies to whatever module or class + # we are currently in + next unless (receiver = ancestor.receiver) + return nil unless receiver.const_type? + receiver.const_name + elsif new_class_or_module_block?(ancestor) + # we will catch this in the `casgn` branch above + next + else + return nil end end end.compact.reverse.join('::') result.empty? ? 'Object' : result end + def parent_module_name_for_sclass(sclass_node) + # TODO: look for constant definition and see if it is nested + # inside a class or module + subject = sclass_node.children[0] + + if subject.const_type? + "#<Class:#{subject.const_name}>" + elsif subject.self_type? + "#<Class:#{sclass_node.parent_module_name}>" + end + end + + def new_class_or_module_block?(block_node) + receiver = block_node.receiver + + block_node.method_name == :new && + receiver && receiver.const_type? && + (receiver.const_name == 'Class' || receiver.const_name == 'Module') && + block_node.parent && + block_node.parent.casgn_type? + end + ## Predicates def multiline? expr = loc.expression expr && (expr.first_line != expr.last_line) @@ -520,14 +542,9 @@ :pair, :regexp, :until, :until_post, :when, :while, :while_post child_nodes.all?(&:pure?) else false end - end - - # Known DSL methods which eval body inside an anonymous class/module - def known_dsl? - RSPEC_METHODS.include?(method_name) && receiver.nil? end protected def visit_descendants(&block)