rubocop-rails 2.12.1 → 2.13.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +43 -8
  3. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +34 -0
  4. data/lib/rubocop/cop/rails/active_record_aliases.rb +6 -2
  5. data/lib/rubocop/cop/rails/application_controller.rb +5 -1
  6. data/lib/rubocop/cop/rails/application_job.rb +5 -1
  7. data/lib/rubocop/cop/rails/application_mailer.rb +5 -1
  8. data/lib/rubocop/cop/rails/application_record.rb +6 -1
  9. data/lib/rubocop/cop/rails/arel_star.rb +6 -0
  10. data/lib/rubocop/cop/rails/blank.rb +5 -4
  11. data/lib/rubocop/cop/rails/compact_blank.rb +98 -0
  12. data/lib/rubocop/cop/rails/content_tag.rb +15 -8
  13. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +2 -7
  14. data/lib/rubocop/cop/rails/duration_arithmetic.rb +97 -0
  15. data/lib/rubocop/cop/rails/dynamic_find_by.rb +4 -0
  16. data/lib/rubocop/cop/rails/find_each.rb +13 -0
  17. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -1
  18. data/lib/rubocop/cop/rails/http_positional_arguments.rb +1 -1
  19. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +8 -7
  20. data/lib/rubocop/cop/rails/mailer_name.rb +4 -0
  21. data/lib/rubocop/cop/rails/negate_include.rb +3 -2
  22. data/lib/rubocop/cop/rails/output.rb +4 -0
  23. data/lib/rubocop/cop/rails/pick.rb +7 -0
  24. data/lib/rubocop/cop/rails/pluck_id.rb +3 -0
  25. data/lib/rubocop/cop/rails/pluck_in_where.rb +7 -6
  26. data/lib/rubocop/cop/rails/rake_environment.rb +5 -0
  27. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +192 -0
  28. data/lib/rubocop/cop/rails/reflection_class_name.rb +4 -2
  29. data/lib/rubocop/cop/rails/relative_date_constant.rb +4 -1
  30. data/lib/rubocop/cop/rails/reversible_migration.rb +11 -3
  31. data/lib/rubocop/cop/rails/root_join_chain.rb +72 -0
  32. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +12 -3
  33. data/lib/rubocop/cop/rails/save_bang.rb +19 -0
  34. data/lib/rubocop/cop/rails/schema_comment.rb +104 -0
  35. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +4 -2
  36. data/lib/rubocop/cop/rails/time_zone.rb +3 -0
  37. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +29 -35
  38. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
  39. data/lib/rubocop/cop/rails/where_equals.rb +4 -0
  40. data/lib/rubocop/cop/rails/where_exists.rb +9 -8
  41. data/lib/rubocop/cop/rails_cops.rb +6 -0
  42. data/lib/rubocop/rails/version.rb +1 -1
  43. metadata +11 -4
@@ -9,6 +9,13 @@ module RuboCop
9
9
  # `pick` avoids. When called on an Active Record relation, `pick` adds a
10
10
  # limit to the query so that only one value is fetched from the database.
11
11
  #
12
+ # @safety
13
+ # This cop is unsafe because `pluck` is defined on both `ActiveRecord::Relation` and `Enumerable`,
14
+ # whereas `pick` is only defined on `ActiveRecord::Relation` in Rails 6.0. This was addressed
15
+ # in Rails 6.1 via rails/rails#38760, at which point the cop is safe.
16
+ #
17
+ # See: https://github.com/rubocop/rubocop-rails/pull/249
18
+ #
12
19
  # @example
13
20
  # # bad
14
21
  # Model.pluck(:a).first
@@ -5,6 +5,9 @@ module RuboCop
5
5
  module Rails
6
6
  # This cop enforces the use of `ids` over `pluck(:id)` and `pluck(primary_key)`.
7
7
  #
8
+ # @safety
9
+ # This cop is unsafe if the receiver object is not an Active Record object.
10
+ #
8
11
  # @example
9
12
  # # bad
10
13
  # User.pluck(:id)
@@ -9,14 +9,15 @@ module RuboCop
9
9
  # Since `pluck` is an eager method and hits the database immediately,
10
10
  # using `select` helps to avoid additional database queries.
11
11
  #
12
- # This cop has two different enforcement modes. When the EnforcedStyle
13
- # is conservative (the default) then only calls to `pluck` on a constant
12
+ # This cop has two different enforcement modes. When the `EnforcedStyle`
13
+ # is `conservative` (the default) then only calls to `pluck` on a constant
14
14
  # (i.e. a model class) in the `where` is used as offenses.
15
15
  #
16
- # When the EnforcedStyle is aggressive then all calls to `pluck` in the
17
- # `where` is used as offenses. This may lead to false positives
18
- # as the cop cannot replace to `select` between calls to `pluck` on an
19
- # `ActiveRecord::Relation` instance vs a call to `pluck` on an `Array` instance.
16
+ # @safety
17
+ # When the `EnforcedStyle` is `aggressive` then all calls to `pluck` in the
18
+ # `where` is used as offenses. This may lead to false positives
19
+ # as the cop cannot replace to `select` between calls to `pluck` on an
20
+ # `ActiveRecord::Relation` instance vs a call to `pluck` on an `Array` instance.
20
21
  #
21
22
  # @example
22
23
  # # bad
@@ -14,6 +14,11 @@ module RuboCop
14
14
  # * The task does not need application code.
15
15
  # * The task invokes the `:environment` task.
16
16
  #
17
+ # @safety
18
+ # Probably not a problem in most cases, but it is possible that calling `:environment` task
19
+ # will break a behavior. It's also slower. E.g. some task that only needs one gem to be
20
+ # loaded to run will run significantly faster without loading the whole application.
21
+ #
17
22
  # @example
18
23
  # # bad
19
24
  # task :foo do
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Since Rails 5.0 the default for `belongs_to` is `optional: false`
7
+ # unless `config.active_record.belongs_to_required_by_default` is
8
+ # explicitly set to `false`. The presence validator is added
9
+ # automatically, and explicit presence validation is redundant.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # belongs_to :user
14
+ # validates :user, presence: true
15
+ #
16
+ # # bad
17
+ # belongs_to :user
18
+ # validates :user_id, presence: true
19
+ #
20
+ # # bad
21
+ # belongs_to :author, foreign_key: :user_id
22
+ # validates :user_id, presence: true
23
+ #
24
+ # # good
25
+ # belongs_to :user
26
+ #
27
+ # # good
28
+ # belongs_to :author, foreign_key: :user_id
29
+ #
30
+ class RedundantPresenceValidationOnBelongsTo < Base
31
+ include RangeHelp
32
+ extend AutoCorrector
33
+ extend TargetRailsVersion
34
+
35
+ MSG = 'Remove explicit presence validation for `%<association>s`.'
36
+ RESTRICT_ON_SEND = %i[validates].freeze
37
+
38
+ minimum_target_rails_version 5.0
39
+
40
+ # @!method presence_validation?(node)
41
+ # Match a `validates` statement with a presence check
42
+ #
43
+ # @example source that matches - by association
44
+ # validates :user, presence: true
45
+ #
46
+ # @example source that matches - with presence options
47
+ # validates :user, presence: { message: 'duplicate' }
48
+ #
49
+ # @example source that matches - by a foreign key
50
+ # validates :user_id, presence: true
51
+ def_node_matcher :presence_validation?, <<~PATTERN
52
+ $(
53
+ send nil? :validates
54
+ (sym $_)
55
+ ...
56
+ $(hash <$(pair (sym :presence) {true hash}) ...>)
57
+ )
58
+ PATTERN
59
+
60
+ # @!method optional_option?(node)
61
+ # Match a `belongs_to` association with an optional option in a hash
62
+ def_node_matcher :optional?, <<~PATTERN
63
+ (send nil? :belongs_to _ ... #optional_option?)
64
+ PATTERN
65
+
66
+ # @!method optional_option?(node)
67
+ # Match an optional option in a hash
68
+ def_node_matcher :optional_option?, <<~PATTERN
69
+ {
70
+ (hash <(pair (sym :optional) true) ...>) # optional: true
71
+ (hash <(pair (sym :required) false) ...>) # required: false
72
+ }
73
+ PATTERN
74
+
75
+ # @!method any_belongs_to?(node, association:)
76
+ # Match a class with `belongs_to` with no regard to `foreign_key` option
77
+ #
78
+ # @example source that matches
79
+ # belongs_to :user
80
+ #
81
+ # @example source that matches - regardless of `foreign_key`
82
+ # belongs_to :author, foreign_key: :user_id
83
+ #
84
+ # @param node [RuboCop::AST::Node]
85
+ # @param association [Symbol]
86
+ # @return [Array<RuboCop::AST::Node>, nil] matching node
87
+ def_node_matcher :any_belongs_to?, <<~PATTERN
88
+ (begin
89
+ <
90
+ $(send nil? :belongs_to (sym %association) ...)
91
+ ...
92
+ >
93
+ )
94
+ PATTERN
95
+
96
+ # @!method belongs_to?(node, key:, fk:)
97
+ # Match a class with a matching association, either by name or an explicit
98
+ # `foreign_key` option
99
+ #
100
+ # @example source that matches - fk matches `foreign_key` option
101
+ # belongs_to :author, foreign_key: :user_id
102
+ #
103
+ # @example source that matches - key matches association name
104
+ # belongs_to :user
105
+ #
106
+ # @example source that does not match - explicit `foreign_key` does not match
107
+ # belongs_to :user, foreign_key: :account_id
108
+ #
109
+ # @param node [RuboCop::AST::Node]
110
+ # @param key [Symbol] e.g. `:user`
111
+ # @param fk [Symbol] e.g. `:user_id`
112
+ # @return [Array<RuboCop::AST::Node>] matching nodes
113
+ def_node_matcher :belongs_to?, <<~PATTERN
114
+ (begin
115
+ <
116
+ ${
117
+ #belongs_to_without_fk?(%key) # belongs_to :user
118
+ #belongs_to_with_a_matching_fk?(%fk) # belongs_to :author, foreign_key: :user_id
119
+ }
120
+ ...
121
+ >
122
+ )
123
+ PATTERN
124
+
125
+ # @!method belongs_to_without_fk?(node, fk)
126
+ # Match a matching `belongs_to` association, without an explicit `foreign_key` option
127
+ #
128
+ # @param node [RuboCop::AST::Node]
129
+ # @param key [Symbol] e.g. `:user`
130
+ # @return [Array<RuboCop::AST::Node>] matching nodes
131
+ def_node_matcher :belongs_to_without_fk?, <<~PATTERN
132
+ {
133
+ (send nil? :belongs_to (sym %1)) # belongs_to :user
134
+ (send nil? :belongs_to (sym %1) !hash) # belongs_to :user, -> { not_deleted }
135
+ (send nil? :belongs_to (sym %1) !(hash <(pair (sym :foreign_key) _) ...>))
136
+ }
137
+ PATTERN
138
+
139
+ # @!method belongs_to_with_a_matching_fk?(node, fk)
140
+ # Match a matching `belongs_to` association with a matching explicit `foreign_key` option
141
+ #
142
+ # @example source that matches
143
+ # belongs_to :author, foreign_key: :user_id
144
+ #
145
+ # @param node [RuboCop::AST::Node]
146
+ # @param fk [Symbol] e.g. `:user_id`
147
+ # @return [Array<RuboCop::AST::Node>] matching nodes
148
+ def_node_matcher :belongs_to_with_a_matching_fk?, <<~PATTERN
149
+ (send nil? :belongs_to ... (hash <(pair (sym :foreign_key) (sym %1)) ...>))
150
+ PATTERN
151
+
152
+ def on_send(node)
153
+ validation, key, options, presence = presence_validation?(node)
154
+ return unless validation
155
+
156
+ belongs_to = belongs_to_for(node.parent, key)
157
+ return unless belongs_to
158
+ return if optional?(belongs_to)
159
+
160
+ message = format(MSG, association: key.to_s)
161
+
162
+ add_offense(presence, message: message) do |corrector|
163
+ remove_presence_validation(corrector, node, options, presence)
164
+ end
165
+ end
166
+
167
+ private
168
+
169
+ def belongs_to_for(model_class_node, key)
170
+ if key.to_s.end_with?('_id')
171
+ normalized_key = key.to_s.delete_suffix('_id').to_sym
172
+ belongs_to?(model_class_node, key: normalized_key, fk: key)
173
+ else
174
+ any_belongs_to?(model_class_node, association: key)
175
+ end
176
+ end
177
+
178
+ def remove_presence_validation(corrector, node, options, presence)
179
+ if options.children.one?
180
+ corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
181
+ else
182
+ range = range_with_surrounding_comma(
183
+ range_with_surrounding_space(range: presence.source_range, side: :left),
184
+ :left
185
+ )
186
+ corrector.remove(range)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -5,8 +5,10 @@ module RuboCop
5
5
  module Rails
6
6
  # This cop checks if the value of the option `class_name`, in
7
7
  # the definition of a reflection is a string.
8
- # It is marked as unsafe because it cannot be determined whether
9
- # constant or method return value specified to `class_name` is a string.
8
+ #
9
+ # @safety
10
+ # This cop is unsafe because it cannot be determined whether
11
+ # constant or method return value specified to `class_name` is a string.
10
12
  #
11
13
  # @example
12
14
  # # bad
@@ -6,6 +6,9 @@ module RuboCop
6
6
  # This cop checks whether constant value isn't relative date.
7
7
  # Because the relative date will be evaluated only once.
8
8
  #
9
+ # @safety
10
+ # This cop's autocorrection is unsafe because its dependence on the constant is not corrected.
11
+ #
9
12
  # @example
10
13
  # # bad
11
14
  # class SomeClass
@@ -90,7 +93,7 @@ module RuboCop
90
93
  end
91
94
 
92
95
  def nested_relative_date(node, &callback)
93
- return if node.block_type?
96
+ return if node.nil? || node.block_type?
94
97
 
95
98
  node.each_child_node do |child|
96
99
  nested_relative_date(child, &callback)
@@ -179,7 +179,7 @@ module RuboCop
179
179
  MSG = '%<action>s is not reversible.'
180
180
 
181
181
  def_node_matcher :irreversible_schema_statement_call, <<~PATTERN
182
- (send nil? ${:execute :remove_belongs_to} ...)
182
+ (send nil? ${:change_column :execute :remove_belongs_to :remove_reference} ...)
183
183
  PATTERN
184
184
 
185
185
  def_node_matcher :drop_table_call, <<~PATTERN
@@ -317,16 +317,24 @@ module RuboCop
317
317
  return if receiver != node.receiver &&
318
318
  reversible_change_table_call?(node)
319
319
 
320
+ action = if method_name == :remove
321
+ target_rails_version >= 6.1 ? 't.remove (without type)' : 't.remove'
322
+ else
323
+ "change_table(with #{method_name})"
324
+ end
325
+
320
326
  add_offense(
321
327
  node,
322
- message: format(MSG, action: "change_table(with #{method_name})")
328
+ message: format(MSG, action: action)
323
329
  )
324
330
  end
325
331
 
326
332
  def reversible_change_table_call?(node)
327
333
  case node.method_name
328
- when :change, :remove
334
+ when :change
329
335
  false
336
+ when :remove
337
+ target_rails_version >= 6.1 && all_hash_key?(node.arguments.last, :type)
330
338
  when :change_default, :change_column_default, :change_table_comment,
331
339
  :change_column_comment
332
340
  all_hash_key?(node.arguments.last, :from, :to)
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Use a single `#join` instead of chaining on `Rails.root` or `Rails.public_path`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # Rails.root.join('db').join('schema.rb')
11
+ # Rails.root.join('db').join(migrate).join('migration.rb')
12
+ # Rails.public_path.join('path').join('file.pdf')
13
+ # Rails.public_path.join('path').join(to).join('file.pdf')
14
+ #
15
+ # # good
16
+ # Rails.root.join('db', 'schema.rb')
17
+ # Rails.root.join('db', migrate, 'migration.rb')
18
+ # Rails.public_path.join('path', 'file.pdf')
19
+ # Rails.public_path.join('path', to, 'file.pdf')
20
+ #
21
+ class RootJoinChain < Base
22
+ extend AutoCorrector
23
+ include RangeHelp
24
+
25
+ MSG = 'Use `%<root>s.join(...)` instead of chaining `#join` calls.'
26
+
27
+ RESTRICT_ON_SEND = %i[join].to_set.freeze
28
+
29
+ # @!method rails_root?(node)
30
+ def_node_matcher :rails_root?, <<~PATTERN
31
+ (send (const {nil? cbase} :Rails) {:root :public_path})
32
+ PATTERN
33
+
34
+ # @!method join?(node)
35
+ def_node_matcher :join?, <<~PATTERN
36
+ (send _ :join $...)
37
+ PATTERN
38
+
39
+ def on_send(node)
40
+ evidence(node) do |rails_node, args|
41
+ add_offense(node, message: format(MSG, root: rails_node.source)) do |corrector|
42
+ range = range_between(rails_node.loc.selector.end_pos, node.loc.expression.end_pos)
43
+ replacement = ".join(#{args.map(&:source).join(', ')})"
44
+
45
+ corrector.replace(range, replacement)
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def evidence(node)
53
+ # Are we at the *end* of the join chain?
54
+ return if join?(node.parent)
55
+ # Is there only one join?
56
+ return if rails_root?(node.receiver)
57
+
58
+ all_args = []
59
+
60
+ while (args = join?(node))
61
+ all_args = args + all_args
62
+ node = node.receiver
63
+ end
64
+
65
+ rails_root?(node) do
66
+ yield(node, all_args)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -6,9 +6,18 @@ module RuboCop
6
6
  # This cop checks to make sure safe navigation isn't used with `blank?` in
7
7
  # a conditional.
8
8
  #
9
- # While the safe navigation operator is generally a good idea, when
10
- # checking `foo&.blank?` in a conditional, `foo` being `nil` will actually
11
- # do the opposite of what the author intends.
9
+ # @safety
10
+ # While the safe navigation operator is generally a good idea, when
11
+ # checking `foo&.blank?` in a conditional, `foo` being `nil` will actually
12
+ # do the opposite of what the author intends.
13
+ #
14
+ # For example:
15
+ #
16
+ # [source,ruby]
17
+ # ----
18
+ # foo&.blank? #=> nil
19
+ # foo.blank? #=> true
20
+ # ----
12
21
  #
13
22
  # @example
14
23
  # # bad
@@ -25,6 +25,25 @@ module RuboCop
25
25
  # You can permit receivers that are giving false positives with
26
26
  # `AllowedReceivers: []`
27
27
  #
28
+ # @safety
29
+ # This cop's autocorrection is unsafe because a custom `update` method call would be changed to `update!`,
30
+ # but the method name in the definition would be unchanged.
31
+ #
32
+ # [source,ruby]
33
+ # ----
34
+ # # Original code
35
+ # def update_attributes
36
+ # end
37
+ #
38
+ # update_attributes
39
+ #
40
+ # # After running rubocop --safe-auto-correct
41
+ # def update_attributes
42
+ # end
43
+ #
44
+ # update
45
+ # ----
46
+ #
28
47
  # @example
29
48
  #
30
49
  # # bad
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop enforces the use of the `comment` option when adding a new table or column
7
+ # to the database during a migration.
8
+ #
9
+ # @example
10
+ # # bad (no comment for a new column or table)
11
+ # add_column :table, :column, :integer
12
+ #
13
+ # create_table :table do |t|
14
+ # t.type :column
15
+ # end
16
+ #
17
+ # # good
18
+ # add_column :table, :column, :integer, comment: 'Number of offenses'
19
+ #
20
+ # create_table :table, comment: 'Table of offenses data' do |t|
21
+ # t.type :column, comment: 'Number of offenses'
22
+ # end
23
+ #
24
+ class SchemaComment < Base
25
+ include ActiveRecordMigrationsHelper
26
+
27
+ COLUMN_MSG = 'New database column without `comment`.'
28
+ TABLE_MSG = 'New database table without `comment`.'
29
+ RESTRICT_ON_SEND = %i[add_column create_table].freeze
30
+ CREATE_TABLE_COLUMN_METHODS = Set[
31
+ *(
32
+ RAILS_ABSTRACT_SCHEMA_DEFINITIONS |
33
+ RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS |
34
+ POSTGRES_SCHEMA_DEFINITIONS |
35
+ MYSQL_SCHEMA_DEFINITIONS
36
+ )
37
+ ].freeze
38
+
39
+ # @!method comment_present?(node)
40
+ def_node_matcher :comment_present?, <<~PATTERN
41
+ (hash <(pair {(sym :comment) (str "comment")} (_ [present?])) ...>)
42
+ PATTERN
43
+
44
+ # @!method add_column?(node)
45
+ def_node_matcher :add_column?, <<~PATTERN
46
+ (send nil? :add_column _table _column _type _?)
47
+ PATTERN
48
+
49
+ # @!method add_column_with_comment?(node)
50
+ def_node_matcher :add_column_with_comment?, <<~PATTERN
51
+ (send nil? :add_column _table _column _type #comment_present?)
52
+ PATTERN
53
+
54
+ # @!method create_table?(node)
55
+ def_node_matcher :create_table?, <<~PATTERN
56
+ (send nil? :create_table _table _?)
57
+ PATTERN
58
+
59
+ # @!method create_table?(node)
60
+ def_node_matcher :create_table_with_comment?, <<~PATTERN
61
+ (send nil? :create_table _table #comment_present? ...)
62
+ PATTERN
63
+
64
+ # @!method t_column?(node)
65
+ def_node_matcher :t_column?, <<~PATTERN
66
+ (send _var CREATE_TABLE_COLUMN_METHODS ...)
67
+ PATTERN
68
+
69
+ # @!method t_column_with_comment?(node)
70
+ def_node_matcher :t_column_with_comment?, <<~PATTERN
71
+ (send _var CREATE_TABLE_COLUMN_METHODS _column _type? #comment_present?)
72
+ PATTERN
73
+
74
+ def on_send(node)
75
+ if add_column_without_comment?(node)
76
+ add_offense(node, message: COLUMN_MSG)
77
+ elsif create_table?(node)
78
+ if create_table_without_comment?(node)
79
+ add_offense(node, message: TABLE_MSG)
80
+ elsif create_table_column_call_without_comment?(node)
81
+ add_offense(node.parent.body, message: COLUMN_MSG)
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def add_column_without_comment?(node)
89
+ add_column?(node) && !add_column_with_comment?(node)
90
+ end
91
+
92
+ def create_table_without_comment?(node)
93
+ create_table?(node) && !create_table_with_comment?(node)
94
+ end
95
+
96
+ def create_table_column_call_without_comment?(node)
97
+ create_table_with_block?(node.parent) &&
98
+ t_column?(node.parent.body) &&
99
+ !t_column_with_comment?(node.parent.body)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -5,8 +5,10 @@ module RuboCop
5
5
  module Rails
6
6
  #
7
7
  # Checks SQL heredocs to use `.squish`.
8
- # Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines
9
- # to be preserved in order to work, thus auto-correction for this cop is not safe.
8
+ #
9
+ # @safety
10
+ # Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines
11
+ # to be preserved in order to work, thus auto-correction for this cop is not safe.
10
12
  #
11
13
  # @example
12
14
  # # bad
@@ -14,6 +14,9 @@ module RuboCop
14
14
  # When EnforcedStyle is 'flexible' then it's also allowed
15
15
  # to use `Time#in_time_zone`.
16
16
  #
17
+ # @safety
18
+ # This cop's autocorrection is unsafe because it may change handling time.
19
+ #
17
20
  # @example
18
21
  # # bad
19
22
  # Time.now