rubocop 1.19.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +129 -21
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +5 -3
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +3 -3
  8. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  9. data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
  10. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
  11. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  12. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  13. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  14. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  15. data/lib/rubocop/cop/documentation.rb +1 -1
  16. data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
  17. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  18. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  19. data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
  20. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +31 -24
  21. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  22. data/lib/rubocop/cop/generator.rb +14 -8
  23. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  24. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  26. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  28. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  29. data/lib/rubocop/cop/layout/class_structure.rb +2 -1
  30. data/lib/rubocop/cop/layout/dot_position.rb +34 -5
  31. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  32. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  33. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  34. data/lib/rubocop/cop/layout/end_alignment.rb +2 -3
  35. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  37. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  39. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  40. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  41. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  42. data/lib/rubocop/cop/layout/line_length.rb +9 -7
  43. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  44. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -3
  45. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  46. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  47. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  48. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +6 -5
  49. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  50. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  51. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  52. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  53. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  54. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  55. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  56. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -28
  57. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  58. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
  59. data/lib/rubocop/cop/lint/ambiguous_range.rb +11 -11
  60. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  61. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  62. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  63. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  64. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  65. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  66. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  67. data/lib/rubocop/cop/lint/else_layout.rb +10 -6
  68. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  69. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  70. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  71. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  72. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  73. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  74. data/lib/rubocop/cop/lint/loop.rb +4 -3
  75. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  76. data/lib/rubocop/cop/lint/number_conversion.rb +16 -2
  77. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  78. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  79. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  80. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  81. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  82. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  83. data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
  84. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  85. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  86. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  87. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  88. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  89. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  90. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  91. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  92. data/lib/rubocop/cop/lint/useless_times.rb +4 -3
  93. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  94. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  95. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  96. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  97. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  98. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  99. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  100. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  101. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  102. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
  103. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  104. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  105. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  106. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  107. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  108. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  109. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  110. data/lib/rubocop/cop/mixin/percent_array.rb +11 -3
  111. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  112. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  113. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  114. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  115. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  116. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  117. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  118. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  119. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  120. data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
  121. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  122. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  123. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  124. data/lib/rubocop/cop/security/json_load.rb +8 -7
  125. data/lib/rubocop/cop/security/open.rb +4 -0
  126. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  127. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  128. data/lib/rubocop/cop/style/and_or.rb +5 -0
  129. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  130. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  131. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  132. data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
  133. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  134. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  135. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  136. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  137. data/lib/rubocop/cop/style/collection_methods.rb +8 -6
  138. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  139. data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
  140. data/lib/rubocop/cop/style/commented_keyword.rb +9 -4
  141. data/lib/rubocop/cop/style/date_time.rb +5 -0
  142. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  143. data/lib/rubocop/cop/style/documentation.rb +23 -8
  144. data/lib/rubocop/cop/style/double_negation.rb +27 -6
  145. data/lib/rubocop/cop/style/empty_method.rb +2 -2
  146. data/lib/rubocop/cop/style/encoding.rb +26 -15
  147. data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
  148. data/lib/rubocop/cop/style/float_division.rb +10 -2
  149. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
  151. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  152. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  153. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  154. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  155. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  156. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  157. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  158. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
  159. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  160. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  161. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  162. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -1
  163. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  164. data/lib/rubocop/cop/style/module_function.rb +8 -9
  165. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  166. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  167. data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
  168. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  169. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  170. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  171. data/lib/rubocop/cop/style/not.rb +2 -2
  172. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  173. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  174. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  175. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  176. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  177. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  178. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  179. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  180. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  181. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  182. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  183. data/lib/rubocop/cop/style/quoted_symbols.rb +21 -7
  184. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  185. data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
  186. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  187. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  188. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  189. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  190. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  191. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  192. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  193. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  194. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  195. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +23 -28
  196. data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
  197. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  198. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  199. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  200. data/lib/rubocop/cop/style/select_by_regexp.rb +139 -0
  201. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  202. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  203. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  204. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  205. data/lib/rubocop/cop/style/static_class.rb +5 -5
  206. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  207. data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
  208. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  209. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
  210. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  211. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  212. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  213. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  214. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  215. data/lib/rubocop/cop/style/word_array.rb +3 -3
  216. data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
  217. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  218. data/lib/rubocop/cop/util.rb +15 -4
  219. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  220. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  221. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  222. data/lib/rubocop/magic_comment.rb +44 -15
  223. data/lib/rubocop/options.rb +126 -112
  224. data/lib/rubocop/rake_task.rb +1 -1
  225. data/lib/rubocop/remote_config.rb +1 -1
  226. data/lib/rubocop/result_cache.rb +3 -3
  227. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  228. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  229. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  230. data/lib/rubocop/rspec/support.rb +1 -0
  231. data/lib/rubocop/runner.rb +2 -3
  232. data/lib/rubocop/target_finder.rb +1 -1
  233. data/lib/rubocop/version.rb +1 -1
  234. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  235. data/lib/rubocop.rb +14 -2
  236. metadata +20 -5
@@ -33,6 +33,27 @@ module RuboCop
33
33
  # g = ( a + 3 )
34
34
  # y()
35
35
  #
36
+ # @example EnforcedStyle: compact
37
+ # # The `compact` style enforces that parentheses have a space at the
38
+ # # beginning with the exception that successive parentheses are allowed.
39
+ # # Note: Empty parentheses should not have spaces.
40
+ #
41
+ # # bad
42
+ # f(3)
43
+ # g = (a + 3)
44
+ # y( )
45
+ # g( f( x ) )
46
+ # g( f( x( 3 ) ), 5 )
47
+ # g( ( ( 3 + 5 ) * f) ** x, 5 )
48
+ #
49
+ # # good
50
+ # f( 3 )
51
+ # g = ( a + 3 )
52
+ # y()
53
+ # g( f( x ))
54
+ # g( f( x( 3 )), 5 )
55
+ # g((( 3 + 5 ) * f ) ** x, 5 )
56
+ #
36
57
  class SpaceInsideParens < Base
37
58
  include SurroundingSpace
38
59
  include RangeHelp
@@ -45,14 +66,13 @@ module RuboCop
45
66
  def on_new_investigation
46
67
  tokens = processed_source.sorted_tokens
47
68
 
48
- if style == :space
69
+ case style
70
+ when :space
49
71
  process_with_space_style(tokens)
72
+ when :compact
73
+ process_with_compact_style(tokens)
50
74
  else
51
- each_extraneous_space(tokens) do |range|
52
- add_offense(range) do |corrector|
53
- corrector.remove(range)
54
- end
55
- end
75
+ correct_extraneous_space(tokens)
56
76
  end
57
77
  end
58
78
 
@@ -60,20 +80,23 @@ module RuboCop
60
80
 
61
81
  def process_with_space_style(tokens)
62
82
  tokens.each_cons(2) do |token1, token2|
63
- each_extraneous_space_in_empty_parens(token1, token2) do |range|
64
- add_offense(range) do |corrector|
65
- corrector.remove(range)
66
- end
67
- end
68
- each_missing_space(token1, token2) do |range|
69
- add_offense(range, message: MSG_SPACE) do |corrector|
70
- corrector.insert_before(range, ' ')
71
- end
83
+ correct_extraneous_space_in_empty_parens(token1, token2)
84
+ correct_missing_space(token1, token2)
85
+ end
86
+ end
87
+
88
+ def process_with_compact_style(tokens)
89
+ tokens.each_cons(2) do |token1, token2|
90
+ correct_extraneous_space_in_empty_parens(token1, token2)
91
+ if !left_parens?(token1, token2) && !right_parens?(token1, token2)
92
+ correct_missing_space(token1, token2)
93
+ else
94
+ correct_extaneus_space_between_consecutive_parens(token1, token2)
72
95
  end
73
96
  end
74
97
  end
75
98
 
76
- def each_extraneous_space(tokens)
99
+ def correct_extraneous_space(tokens)
77
100
  tokens.each_cons(2) do |token1, token2|
78
101
  next unless parens?(token1, token2)
79
102
 
@@ -82,36 +105,59 @@ module RuboCop
82
105
  next if token2.comment?
83
106
  next unless same_line?(token1, token2) && token1.space_after?
84
107
 
85
- yield range_between(token1.end_pos, token2.begin_pos)
108
+ range = range_between(token1.end_pos, token2.begin_pos)
109
+ add_offense(range) do |corrector|
110
+ corrector.remove(range)
111
+ end
112
+ end
113
+ end
114
+
115
+ def correct_extaneus_space_between_consecutive_parens(token1, token2)
116
+ return if range_between(token1.end_pos, token2.begin_pos).source != ' '
117
+
118
+ range = range_between(token1.end_pos, token2.begin_pos)
119
+ add_offense(range) do |corrector|
120
+ corrector.remove(range)
86
121
  end
87
122
  end
88
123
 
89
- def each_extraneous_space_in_empty_parens(token1, token2)
124
+ def correct_extraneous_space_in_empty_parens(token1, token2)
90
125
  return unless token1.left_parens? && token2.right_parens?
91
126
 
92
127
  return if range_between(token1.begin_pos, token2.end_pos).source == '()'
93
128
 
94
- yield range_between(token1.end_pos, token2.begin_pos)
129
+ range = range_between(token1.end_pos, token2.begin_pos)
130
+ add_offense(range) do |corrector|
131
+ corrector.remove(range)
132
+ end
95
133
  end
96
134
 
97
- def each_missing_space(token1, token2)
135
+ def correct_missing_space(token1, token2)
98
136
  return if can_be_ignored?(token1, token2)
99
137
 
100
- if token1.left_parens?
101
- yield range_between(token2.begin_pos, token2.begin_pos + 1)
102
- elsif token2.right_parens?
103
- yield range_between(token2.begin_pos, token2.end_pos)
104
- end
105
- end
138
+ range = if token1.left_parens?
139
+ range_between(token2.begin_pos, token2.begin_pos + 1)
140
+ elsif token2.right_parens?
141
+ range_between(token2.begin_pos, token2.end_pos)
142
+ end
106
143
 
107
- def same_line?(token1, token2)
108
- token1.line == token2.line
144
+ add_offense(range, message: MSG_SPACE) do |corrector|
145
+ corrector.insert_before(range, ' ')
146
+ end
109
147
  end
110
148
 
111
149
  def parens?(token1, token2)
112
150
  token1.left_parens? || token2.right_parens?
113
151
  end
114
152
 
153
+ def left_parens?(token1, token2)
154
+ token1.left_parens? && token2.left_parens?
155
+ end
156
+
157
+ def right_parens?(token1, token2)
158
+ token1.right_parens? && token2.right_parens?
159
+ end
160
+
115
161
  def can_be_ignored?(token1, token2)
116
162
  return true unless parens?(token1, token2)
117
163
 
@@ -107,7 +107,7 @@ module RuboCop
107
107
  current_token = tokens.reverse.find(&:left_ref_bracket?)
108
108
  previous_token = previous_token(current_token)
109
109
 
110
- if node.method?(:[]=) || previous_token && !previous_token.right_bracket?
110
+ if node.method?(:[]=) || (previous_token && !previous_token.right_bracket?)
111
111
  tokens.find(&:left_ref_bracket?)
112
112
  else
113
113
  current_token
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop looks for expressions containing multiple binary operators
7
+ # where precedence is ambiguous due to lack of parentheses. For example,
8
+ # in `1 + 2 * 3`, the multiplication will happen before the addition, but
9
+ # lexically it appears that the addition will happen first.
10
+ #
11
+ # The cop does not consider unary operators (ie. `!a` or `-b`) or comparison
12
+ # operators (ie. `a =~ b`) because those are not ambiguous.
13
+ #
14
+ # NOTE: Ranges are handled by `Lint/AmbiguousRange`.
15
+ #
16
+ # @example
17
+ # # bad
18
+ # a + b * c
19
+ # a || b && c
20
+ # a ** b + c
21
+ #
22
+ # # good (different precedence)
23
+ # a + (b * c)
24
+ # a || (b && c)
25
+ # (a ** b) + c
26
+ #
27
+ # # good (same precedence)
28
+ # a + b + c
29
+ # a * b / c % d
30
+ class AmbiguousOperatorPrecedence < Base
31
+ extend AutoCorrector
32
+
33
+ # See https://ruby-doc.org/core-3.0.2/doc/syntax/precedence_rdoc.html
34
+ PRECEDENCE = [
35
+ %i[**],
36
+ %i[* / %],
37
+ %i[+ -],
38
+ %i[<< >>],
39
+ %i[&],
40
+ %i[| ^],
41
+ %i[&&],
42
+ %i[||]
43
+ ].freeze
44
+ RESTRICT_ON_SEND = PRECEDENCE.flatten.freeze
45
+ MSG = 'Wrap expressions with varying precedence with parentheses to avoid ambiguity.'
46
+
47
+ def on_new_investigation
48
+ # Cache the precedence of each node being investigated
49
+ # so that we only need to calculate it once
50
+ @node_precedences = {}
51
+ super
52
+ end
53
+
54
+ def on_and(node)
55
+ return unless (parent = node.parent)
56
+
57
+ return if parent.begin_type? # if the `and` is in a `begin`, it's parenthesized already
58
+ return unless parent.or_type?
59
+
60
+ add_offense(node) do |corrector|
61
+ autocorrect(corrector, node)
62
+ end
63
+ end
64
+
65
+ def on_send(node)
66
+ return if node.parenthesized?
67
+
68
+ return unless (parent = node.parent)
69
+ return unless operator?(parent)
70
+ return unless greater_precedence?(node, parent)
71
+
72
+ add_offense(node) do |corrector|
73
+ autocorrect(corrector, node)
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def precedence(node)
80
+ @node_precedences.fetch(node) do
81
+ PRECEDENCE.index { |operators| operators.include?(operator_name(node)) }
82
+ end
83
+ end
84
+
85
+ def operator?(node)
86
+ (node.send_type? && RESTRICT_ON_SEND.include?(node.method_name)) || node.operator_keyword?
87
+ end
88
+
89
+ def greater_precedence?(node1, node2)
90
+ node1_precedence = precedence(node1)
91
+ node2_precedence = precedence(node2)
92
+ return false unless node1_precedence && node2_precedence
93
+
94
+ node2_precedence > node1_precedence
95
+ end
96
+
97
+ def operator_name(node)
98
+ if node.send_type?
99
+ node.method_name
100
+ else
101
+ node.operator.to_sym
102
+ end
103
+ end
104
+
105
+ def autocorrect(corrector, node)
106
+ corrector.wrap(node, '(', ')')
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -8,13 +8,7 @@ module RuboCop
8
8
  # Ranges have quite low precedence, which leads to unexpected behaviour when
9
9
  # using a range with other operators. This cop avoids that by making ranges
10
10
  # explicit by requiring parenthesis around complex range boundaries (anything
11
- # that is not a basic literal: numerics, strings, symbols, etc.).
12
- #
13
- # NOTE: The cop auto-corrects by wrapping the entire boundary in parentheses, which
14
- # makes the outcome more explicit but is possible to not be the intention of the
15
- # programmer. For this reason, this cop's auto-correct is marked as unsafe (it
16
- # will not change the behaviour of the code, but will not necessarily match the
17
- # intent of the program).
11
+ # that is not a literal: numerics, strings, symbols, etc.).
18
12
  #
19
13
  # This cop can be configured with `RequireParenthesesForMethodChains` in order to
20
14
  # specify whether method chains (including `self.foo`) should be wrapped in parens
@@ -23,6 +17,13 @@ module RuboCop
23
17
  # NOTE: Regardless of this configuration, if a method receiver is a basic literal
24
18
  # value, it will be wrapped in order to prevent the ambiguity of `1..2.to_a`.
25
19
  #
20
+ # @safety
21
+ # The cop auto-corrects by wrapping the entire boundary in parentheses, which
22
+ # makes the outcome more explicit but is possible to not be the intention of the
23
+ # programmer. For this reason, this cop's auto-correct is unsafe (it will not
24
+ # change the behaviour of the code, but will not necessarily match the
25
+ # intent of the program).
26
+ #
26
27
  # @example
27
28
  # # bad
28
29
  # x || 1..2
@@ -55,7 +56,6 @@ module RuboCop
55
56
  #
56
57
  # # good
57
58
  # (a.foo)..(b.bar)
58
- #
59
59
  class AmbiguousRange < Base
60
60
  extend AutoCorrector
61
61
 
@@ -81,9 +81,9 @@ module RuboCop
81
81
 
82
82
  def acceptable?(node)
83
83
  node.begin_type? ||
84
- node.basic_literal? ||
85
- node.variable? || node.const_type? ||
86
- node.call_type? && acceptable_call?(node)
84
+ node.literal? ||
85
+ node.variable? || node.const_type? || node.self_type? ||
86
+ (node.call_type? && acceptable_call?(node))
87
87
  end
88
88
 
89
89
  def acceptable_call?(node)
@@ -49,7 +49,7 @@ module RuboCop
49
49
  def on_if(node)
50
50
  return if node.condition.block_type?
51
51
 
52
- traverse_node(node.condition, ASGN_TYPES) do |asgn_node|
52
+ traverse_node(node.condition) do |asgn_node|
53
53
  next :skip_children if skip_children?(asgn_node)
54
54
  next if allowed_construct?(asgn_node)
55
55
 
@@ -83,13 +83,15 @@ module RuboCop
83
83
  (safe_assignment_allowed? && safe_assignment?(asgn_node))
84
84
  end
85
85
 
86
- # each_node/visit_descendants_with_types with :skip_children
87
- def traverse_node(node, types, &block)
88
- result = yield node if types.include?(node.type)
86
+ def traverse_node(node, &block)
87
+ # if the node is a block, any assignments are irrelevant
88
+ return if node.block_type?
89
+
90
+ result = yield node if ASGN_TYPES.include?(node.type)
89
91
 
90
92
  return if result == :skip_children
91
93
 
92
- node.each_child_node { |child| traverse_node(child, types, &block) }
94
+ node.each_child_node { |child| traverse_node(child, &block) }
93
95
  end
94
96
  end
95
97
  end
@@ -5,15 +5,28 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for places where binary operator has identical operands.
7
7
  #
8
- # It covers arithmetic operators: `+`, `-`, `*`, `/`, `%`, `**`;
8
+ # It covers arithmetic operators: `-`, `/`, `%`;
9
9
  # comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`;
10
- # bitwise operators: `|`, `^`, `&`, `<<`, `>>`;
10
+ # bitwise operators: `|`, `^`, `&`;
11
11
  # boolean operators: `&&`, `||`
12
12
  # and "spaceship" operator - `<=>`.
13
13
  #
14
- # This cop is marked as unsafe as it does not consider side effects when calling methods
15
- # and thus can generate false positives:
14
+ # Simple arithmetic operations are allowed by this cop: `+`, `*`, `**`, `<<` and `>>`.
15
+ # Although these can be rewritten in a different way, it should not be necessary to
16
+ # do so. This does not include operations such as `-` or `/` where the result will
17
+ # always be the same (`x - x` will always be 0; `x / x` will always be 1), and
18
+ # thus are legitimate offenses.
19
+ #
20
+ # @safety
21
+ # This cop is unsafe as it does not consider side effects when calling methods
22
+ # and thus can generate false positives, for example:
23
+ #
24
+ # [source,ruby]
25
+ # ----
16
26
  # if wr.take_char == '\0' && wr.take_char == '\0'
27
+ # # ...
28
+ # end
29
+ # ----
17
30
  #
18
31
  # @example
19
32
  # # bad
@@ -24,7 +37,7 @@ module RuboCop
24
37
  # do_something
25
38
  # end
26
39
  #
27
- # def childs?
40
+ # def child?
28
41
  # left_child || left_child
29
42
  # end
30
43
  #
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # This cop checks for `:true` and `:false` symbols.
7
7
  # In most cases it would be a typo.
8
8
  #
9
+ # @safety
10
+ # Autocorrection is unsafe for this cop because code relying
11
+ # on `:true` or `:false` symbols will break when those are
12
+ # changed to actual booleans.
13
+ #
9
14
  # @example
10
15
  #
11
16
  # # bad
@@ -7,8 +7,8 @@ module RuboCop
7
7
  # not be kept for production code.
8
8
  #
9
9
  # The cop can be configured using `DebuggerMethods`. By default, a number of gems
10
- # debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `Pry`, `Rails`,
11
- # and `WebConsole`). Additional methods can be added.
10
+ # debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `debug.rb`,
11
+ # `Pry`, `Rails`, `RubyJard`, and `WebConsole`). Additional methods can be added.
12
12
  #
13
13
  # Specific default groups can be disabled if necessary:
14
14
  #
@@ -57,8 +57,6 @@ module RuboCop
57
57
  class Debugger < Base
58
58
  MSG = 'Remove debugger entry point `%<source>s`.'
59
59
 
60
- RESTRICT_ON_SEND = [].freeze
61
-
62
60
  # @!method kernel?(node)
63
61
  def_node_matcher :kernel?, <<~PATTERN
64
62
  (const {nil? cbase} :Kernel)
@@ -58,12 +58,12 @@ module RuboCop
58
58
  end
59
59
 
60
60
  def to_s
61
- [class_constant, method].compact.join(delimeter)
61
+ [class_constant, method].compact.join(delimiter)
62
62
  end
63
63
 
64
64
  private
65
65
 
66
- def delimeter
66
+ def delimiter
67
67
  CLASS_METHOD_DELIMETER
68
68
  end
69
69
  end
@@ -81,12 +81,12 @@ module RuboCop
81
81
  end
82
82
 
83
83
  def to_s
84
- [class_constant, method].compact.join(delimeter)
84
+ [class_constant, method].compact.join(delimiter)
85
85
  end
86
86
 
87
87
  private
88
88
 
89
- def delimeter
89
+ def delimiter
90
90
  instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER
91
91
  end
92
92
 
@@ -42,11 +42,12 @@ module RuboCop
42
42
  # Maybe further investigation of RuboCop AST will lead to an essential solution.
43
43
  return unless node.loc
44
44
 
45
- constant = node.absolute? ? constant_name(node, node.short_name.to_s) : node.source
45
+ constant = node.absolute? ? constant_name(node, node.short_name) : node.source
46
46
  return unless (deprecated_constant = deprecated_constants[constant])
47
47
 
48
48
  alternative = deprecated_constant['Alternative']
49
49
  version = deprecated_constant['DeprecatedVersion']
50
+ return if target_ruby_version < version.to_f
50
51
 
51
52
  add_offense(node, message: message(alternative, node.source, version)) do |corrector|
52
53
  corrector.replace(node, alternative)
@@ -56,7 +57,7 @@ module RuboCop
56
57
  private
57
58
 
58
59
  def constant_name(node, nested_constant_name)
59
- return nested_constant_name unless node.namespace.const_type?
60
+ return nested_constant_name.to_s unless node.namespace.const_type?
60
61
 
61
62
  constant_name(node.namespace, "#{node.namespace.short_name}::#{nested_constant_name}")
62
63
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop checks constructors for disjunctive assignments that should
6
+ # This cop checks constructors for disjunctive assignments (`||=`) that should
7
7
  # be plain assignments.
8
8
  #
9
9
  # So far, this cop is only concerned with disjunctive assignment of
@@ -12,6 +12,29 @@ module RuboCop
12
12
  # In ruby, an instance variable is nil until a value is assigned, so the
13
13
  # disjunction is unnecessary. A plain assignment has the same effect.
14
14
  #
15
+ # @safety
16
+ # This cop is unsafe because it can register a false positive when a
17
+ # method is redefined in a subclass that calls super. For example:
18
+ #
19
+ # [source,ruby]
20
+ # ----
21
+ # class Base
22
+ # def initialize
23
+ # @config ||= 'base'
24
+ # end
25
+ # end
26
+ #
27
+ # class Derived < Base
28
+ # def initialize
29
+ # @config = 'derived'
30
+ # super
31
+ # end
32
+ # end
33
+ # ----
34
+ #
35
+ # Without the disjunctive assignment, `Derived` will be unable to override
36
+ # the value for `@config`.
37
+ #
15
38
  # @example
16
39
  # # bad
17
40
  # def initialize
@@ -49,6 +49,9 @@ module RuboCop
49
49
  def on_if(node)
50
50
  return if node.ternary?
51
51
 
52
+ # If the if is on a single line, it'll be handled by `Style/OneLineConditional`
53
+ return if node.single_line?
54
+
52
55
  check(node)
53
56
  end
54
57
 
@@ -66,13 +69,10 @@ module RuboCop
66
69
 
67
70
  def check_else(node)
68
71
  else_branch = node.else_branch
69
-
70
- return unless else_branch.begin_type?
71
-
72
- first_else = else_branch.children.first
72
+ first_else = else_branch.begin_type? ? else_branch.children.first : else_branch
73
73
 
74
74
  return unless first_else
75
- return unless first_else.source_range.line == node.loc.else.line
75
+ return unless same_line?(first_else, node.loc.else)
76
76
 
77
77
  add_offense(first_else) { |corrector| autocorrect(corrector, node, first_else) }
78
78
  end
@@ -81,9 +81,13 @@ module RuboCop
81
81
  corrector.insert_after(node.loc.else, "\n")
82
82
 
83
83
  blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
84
- indentation = indent(node.else_branch.children[1])
84
+ indentation = indent(node, offset: indentation_width)
85
85
  corrector.replace(blank_range, indentation)
86
86
  end
87
+
88
+ def indentation_width
89
+ @config.for_cop('Layout/IndentationWidth')['Width'] || 2
90
+ end
87
91
  end
88
92
  end
89
93
  end
@@ -51,7 +51,7 @@ module RuboCop
51
51
 
52
52
  def on_case_match(node)
53
53
  node.in_pattern_branches.each do |branch|
54
- next if branch.body || cop_config['AllowComments'] && comment_lines?(node)
54
+ next if branch.body || (cop_config['AllowComments'] && comment_lines?(node))
55
55
 
56
56
  add_offense(branch)
57
57
  end
@@ -118,7 +118,7 @@ module RuboCop
118
118
  end
119
119
 
120
120
  def correct_arguments?(arguments)
121
- arguments.size == 1 || arguments.size == 2 && arguments[1].hash_type?
121
+ arguments.size == 1 || (arguments.size == 2 && arguments[1].hash_type?)
122
122
  end
123
123
 
124
124
  def build_kwargs(node)
@@ -24,7 +24,7 @@ module RuboCop
24
24
  def on_float(node)
25
25
  value, = *node
26
26
 
27
- return unless value.infinite? || value.zero? && /[1-9]/.match?(node.source)
27
+ return unless value.infinite? || (value.zero? && /[1-9]/.match?(node.source))
28
28
 
29
29
  add_offense(node)
30
30
  end
@@ -3,10 +3,19 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Prefer using `Hash#compare_by_identity` than using `object_id` for hash keys.
6
+ # Prefer using `Hash#compare_by_identity` rather than using `object_id`
7
+ # for hash keys.
7
8
  #
8
- # This cop is marked as unsafe as a hash possibly can contain other keys
9
- # besides `object_id`s.
9
+ # This cop looks for hashes being keyed by objects' `object_id`, using
10
+ # one of these methods: `key?`, `has_key?`, `fetch`, `[]` and `[]=`.
11
+ #
12
+ # @safety
13
+ # This cop is unsafe. Although unlikely, the hash could store both object
14
+ # ids and other values that need be compared by value, and thus
15
+ # could be a false positive.
16
+ #
17
+ # Furthermore, this cop cannot guarantee that the receiver of one of the
18
+ # methods (`key?`, etc.) is actually a hash.
10
19
  #
11
20
  # @example
12
21
  # # bad