From c6b1043e9d1b7fe9912c330b6e7d4342f2a9694e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=99=88=20=20jacopo=20beschi=20=F0=9F=99=89?= Date: Wed, 18 Apr 2018 09:19:40 +0000 Subject: Resolve "Make a Rubocop that forbids returning from a block" --- rubocop/cop/avoid_break_from_strong_memoize.rb | 48 ++++++++++++++++ rubocop/cop/avoid_return_from_blocks.rb | 77 ++++++++++++++++++++++++++ rubocop/cop/migration/safer_boolean_column.rb | 4 +- rubocop/rubocop.rb | 2 + 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 rubocop/cop/avoid_break_from_strong_memoize.rb create mode 100644 rubocop/cop/avoid_return_from_blocks.rb (limited to 'rubocop') diff --git a/rubocop/cop/avoid_break_from_strong_memoize.rb b/rubocop/cop/avoid_break_from_strong_memoize.rb new file mode 100644 index 00000000000..9b436118db3 --- /dev/null +++ b/rubocop/cop/avoid_break_from_strong_memoize.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # Checks for break inside strong_memoize blocks. + # For more information see: https://gitlab.com/gitlab-org/gitlab-ce/issues/42889 + # + # @example + # # bad + # strong_memoize(:result) do + # break if something + # + # do_an_heavy_calculation + # end + # + # # good + # strong_memoize(:result) do + # next if something + # + # do_an_heavy_calculation + # end + # + class AvoidBreakFromStrongMemoize < RuboCop::Cop::Cop + MSG = 'Do not use break inside strong_memoize, use next instead.' + + def on_block(node) + block_body = node.body + + return unless block_body + return unless node.method_name == :strong_memoize + + block_body.each_node(:break) do |break_node| + next if container_block_for(break_node) != node + + add_offense(break_node) + end + end + + private + + def container_block_for(current_node) + current_node = current_node.parent until current_node.type == :block && current_node.method_name == :strong_memoize + + current_node + end + end + end +end diff --git a/rubocop/cop/avoid_return_from_blocks.rb b/rubocop/cop/avoid_return_from_blocks.rb new file mode 100644 index 00000000000..40b2aed019f --- /dev/null +++ b/rubocop/cop/avoid_return_from_blocks.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # Checks for return inside blocks. + # For more information see: https://gitlab.com/gitlab-org/gitlab-ce/issues/42889 + # + # @example + # # bad + # call do + # return if something + # + # do_something_else + # end + # + # # good + # call do + # break if something + # + # do_something_else + # end + # + class AvoidReturnFromBlocks < RuboCop::Cop::Cop + MSG = 'Do not return from a block, use next or break instead.' + DEF_METHODS = %i[define_method lambda].freeze + WHITELISTED_METHODS = %i[each each_filename times loop].freeze + + def on_block(node) + block_body = node.body + + return unless block_body + return unless top_block?(node) + + block_body.each_node(:return) do |return_node| + next if parent_blocks(node, return_node).all?(&method(:whitelisted?)) + + add_offense(return_node) + end + end + + private + + def top_block?(node) + current_node = node + top_block = nil + + while current_node && current_node.type != :def + top_block = current_node if current_node.type == :block + current_node = current_node.parent + end + + top_block == node + end + + def parent_blocks(node, current_node) + blocks = [] + + until node == current_node || def?(current_node) + blocks << current_node if current_node.type == :block + current_node = current_node.parent + end + + blocks << node if node == current_node && !def?(node) + blocks + end + + def def?(node) + node.type == :def || node.type == :defs || + (node.type == :block && DEF_METHODS.include?(node.method_name)) + end + + def whitelisted?(block_node) + WHITELISTED_METHODS.include?(block_node.method_name) + end + end + end +end diff --git a/rubocop/cop/migration/safer_boolean_column.rb b/rubocop/cop/migration/safer_boolean_column.rb index dc5c55df6fb..a7d922c752f 100644 --- a/rubocop/cop/migration/safer_boolean_column.rb +++ b/rubocop/cop/migration/safer_boolean_column.rb @@ -61,7 +61,7 @@ module RuboCop return true unless opts each_hash_node_pair(opts) do |key, value| - return value == 'nil' if key == :default + break value == 'nil' if key == :default end end @@ -69,7 +69,7 @@ module RuboCop return true unless opts each_hash_node_pair(opts) do |key, value| - return value != 'false' if key == :null + break value != 'false' if key == :null end end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb index c2254332e7d..96061672749 100644 --- a/rubocop/rubocop.rb +++ b/rubocop/rubocop.rb @@ -4,6 +4,8 @@ require_relative 'cop/gitlab/httparty' require_relative 'cop/gitlab/module_with_instance_variables' require_relative 'cop/gitlab/predicate_memoization' require_relative 'cop/include_sidekiq_worker' +require_relative 'cop/avoid_return_from_blocks' +require_relative 'cop/avoid_break_from_strong_memoize' require_relative 'cop/line_break_around_conditional_block' require_relative 'cop/migration/add_column' require_relative 'cop/migration/add_concurrent_foreign_key' -- cgit v1.2.1