lib/rubocop/cop/lint/useless_assignment.rb in rubocop-0.12.0 vs lib/rubocop/cop/lint/useless_assignment.rb in rubocop-0.13.0

- old
+ new

@@ -1,90 +1,87 @@ # encoding: utf-8 module Rubocop module Cop module Lint - # This cop checks for useless assignment as the final expression - # of a function definition. + # This cop checks for every useless assignment to local variable in every + # scope. + # The basic idea for this cop was from the warning of `ruby -cw`: # - # @example + # assigned but unused variable - foo # - # def something - # x = 5 - # end - # - # def something - # x = Something.new - # x.attr = 5 - # end + # Currently this cop has advanced logic that detects unreferenced + # reassignments and properly handles varied cases such as branch, loop, + # rescue, ensure, etc. class UselessAssignment < Cop - MSG = 'Useless assignment to local variable %s.' + include VariableInspector - def on_def(node) - _name, args, body = *node + MSG = 'Useless assignment to variable - %s' - check_for_useless_assignment(body, args) + def investigate(processed_source) + inspect_variables(processed_source.ast) end - def on_defs(node) - _target, _name, args, body = *node - - check_for_useless_assignment(body, args) + def after_leaving_scope(scope) + scope.variables.each_value do |variable| + check_for_unused_assignments(variable) + check_for_unused_block_local_variable(variable) + end end - private + def check_for_unused_assignments(variable) + return if variable.name.to_s.start_with?('_') - def check_for_useless_assignment(body, args) - return unless body + variable.assignments.each do |assignment| + next if assignment.used? - if body.type == :begin - expression = body.children - else - expression = body - end + message = message_for_useless_assignment(assignment) - last_expr = expression.is_a?(Array) ? expression.last : expression - return unless last_expr + location = if assignment.regexp_named_capture? + assignment.node.children.first.loc.expression + else + assignment.node.loc.name + end - case last_expr.type - when :lvasgn - var_name, = *last_expr - add_offence(:warning, last_expr.loc.name, MSG.format(var_name)) - when :send - receiver, method, _args = *last_expr - return unless receiver - return unless receiver.type == :lvar - return unless method =~ /\w=$/ - - var_name, = *receiver - return if contains_object_passed_as_argument?(var_name, body, args) - - add_offence(:warning, - receiver.loc.name, - MSG.format(receiver.loc.name.source)) + warning(nil, location, message) end end - def contains_object_passed_as_argument?(lvar_name, body, args) - variable_table = {} + def message_for_useless_assignment(assignment) + variable = assignment.variable - args.children.each do |arg_node| - arg_name, = *arg_node - variable_table[arg_name] = true + message = sprintf(MSG, variable.name) + + if assignment.multiple_assignment? + message << ". Use _ or _#{variable.name} as a variable name " + + "to indicate that it won't be used." + elsif assignment.operator_assignment? + return_value_node = return_value_node_of_scope(variable.scope) + if assignment.meta_assignment_node.equal?(return_value_node) + non_assignment_operator = assignment.operator.sub(/=$/, '') + message << ". Use just operator #{non_assignment_operator}." + end end - on_node([:lvasgn, :ivasgn, :cvasgn, :gvasgn], body) do |asgn_node| - lhs_var_name, rhs_node = *asgn_node + message + end - if [:lvar, :ivar, :cvar, :gvar].include?(rhs_node.type) - rhs_var_name, = *rhs_node - variable_table[lhs_var_name] = variable_table[rhs_var_name] - else - variable_table[lhs_var_name] = false - end + # TODO: More precise handling (rescue, ensure, nested begin, etc.) + def return_value_node_of_scope(scope) + body_node = scope.body_node + + if body_node.type == :begin + body_node.children.last + else + body_node end + end - variable_table[lvar_name] + def check_for_unused_block_local_variable(variable) + return unless variable.block_local_variable? + return unless variable.assignments.empty? + message = sprintf(MSG, variable.name) + warning(variable.declaration_node, :expression, message) end end end end end