From 0ab47b994caa80c5587f33dc818626b66cfdafe2 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 13 Feb 2020 15:08:52 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- rubocop/cop/gitlab/keys-first-and-values-first.rb | 55 +++++++++++++++++++++++ rubocop/rubocop.rb | 1 + 2 files changed, 56 insertions(+) create mode 100644 rubocop/cop/gitlab/keys-first-and-values-first.rb (limited to 'rubocop') diff --git a/rubocop/cop/gitlab/keys-first-and-values-first.rb b/rubocop/cop/gitlab/keys-first-and-values-first.rb new file mode 100644 index 00000000000..9b68957cba2 --- /dev/null +++ b/rubocop/cop/gitlab/keys-first-and-values-first.rb @@ -0,0 +1,55 @@ +module RuboCop + module Cop + module Gitlab + class KeysFirstAndValuesFirst < RuboCop::Cop::Cop + FIRST_PATTERN = /\Afirst\z/.freeze + + def message(used_method) + <<~MSG + Don't use `.keys.first` and `.values.first`. + Instead use `.each_key.first` and `.each_value.first` (or `.first.first` and `first.second`) + + This will reduce memory usage and execution time. + MSG + end + + def on_send(node) + if find_on_keys_or_values?(node) + add_offense(node, location: :selector, message: message(node.method_name)) + end + end + + def autocorrect(node) + lambda do |corrector| + replace_with = if node.descendants.first.method_name == :values + '.each_value' + elsif node.descendants.first.method_name == :keys + '.each_key' + else + throw("Expect '.values.first' or '.keys.first', but get #{node.descendants.first.method_name}.first") + end + + upto_including_keys_or_values = node.descendants.first.source_range + before_keys_or_values = node.descendants[1].source_range + range_to_replace = node.source_range + .with(begin_pos: before_keys_or_values.end_pos, + end_pos: upto_including_keys_or_values.end_pos) + corrector.replace(range_to_replace, replace_with) + end + end + + def find_on_keys_or_values?(node) + chained_on_node = node.descendants.first + node.method_name.to_s =~ FIRST_PATTERN && + chained_on_node.is_a?(RuboCop::AST::SendNode) && + [:keys, :values].include?(chained_on_node.method_name) && + node.descendants[1] + end + + def method_name_for_node(node) + children[1].to_s + end + end + end + end +end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb index 5284cef5346..9305153dc7d 100644 --- a/rubocop/rubocop.rb +++ b/rubocop/rubocop.rb @@ -5,6 +5,7 @@ require_relative 'cop/gitlab/httparty' require_relative 'cop/gitlab/finder_with_find_by' require_relative 'cop/gitlab/union' require_relative 'cop/gitlab/rails_logger' +require_relative 'cop/gitlab/keys-first-and-values-first' require_relative 'cop/include_sidekiq_worker' require_relative 'cop/safe_params' require_relative 'cop/active_record_association_reload' -- cgit v1.2.3