Skip to content

Commit 1899514

Browse files
committed
Add and configure new Rubocop cops
1 parent fa3246f commit 1899514

File tree

5 files changed

+245
-1
lines changed

5 files changed

+245
-1
lines changed

.rubocop.yml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
require:
2+
- ./tool/rubocop-truffleruby/cop/replace_with_primitive_nil.rb
3+
- ./tool/rubocop-truffleruby/cop/replace_with_primitive_object_class.rb
4+
- ./tool/rubocop-truffleruby/cop/replace_with_primitive_object_equal.rb
5+
- ./tool/rubocop-truffleruby/cop/replace_with_primitive_object_kind_of.rb
6+
17
AllCops:
28
TargetRubyVersion: 3.1
39
DisabledByDefault: true
@@ -389,4 +395,28 @@ Layout/SpaceInsideBlockBraces:
389395
# Supports --auto-correct
390396
Layout/SpaceAroundEqualsInParameterDefault:
391397
Description: Checks that the equals signs in parameter default assignments have or don't have surrounding space depending on configuration.
392-
Enabled: true
398+
Enabled: true
399+
400+
# Supports --auto-correct
401+
TruffleRuby/ReplaceWithPrimitiveNil:
402+
Enabled: true
403+
Include: # inspect *only* this directory
404+
- src/main/ruby/**/*.rb
405+
406+
# Supports --auto-correct
407+
TruffleRuby/ReplaceWithPrimitiveObjectClass:
408+
Enabled: true
409+
Include: # inspect *only* this directory
410+
- src/main/ruby/**/*.rb
411+
412+
# Supports --auto-correct
413+
TruffleRuby/ReplaceWithPrimitiveObjectEqual:
414+
Enabled: true
415+
Include: # inspect *only* this directory
416+
- src/main/ruby/**/*.rb
417+
418+
# Supports --auto-correct
419+
TruffleRuby/ReplaceWithPrimitiveObjectKindOf:
420+
Enabled: true
421+
Include: # inspect *only* this directory
422+
- src/main/ruby/**/*.rb
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module TruffleRuby
6+
# Prefer Primitive method `nil?` to check whether object is `nil`
7+
#
8+
# @example
9+
#
10+
# # bad
11+
# object.nil?
12+
#
13+
# # bad
14+
# object == nil
15+
#
16+
# # bad
17+
# object != nil
18+
#
19+
# # bad
20+
# object.equal?(nil)
21+
#
22+
# # bad
23+
# nil.equal?(object)
24+
#
25+
# # bad
26+
# Primitive.object_equal(nil, object)
27+
#
28+
# # bad
29+
# Primitive.object_equal(object, nil)
30+
#
31+
# # good
32+
# Primitive.nil?(object)
33+
#
34+
class ReplaceWithPrimitiveNil < Base
35+
extend AutoCorrector
36+
37+
MSG = 'Use `Primitive.nil?` instead of `Object#nil?` or `object == nil`'
38+
RESTRICT_ON_SEND = %i[nil? == != equal? object_equal].freeze
39+
40+
# @!method bad_method?(node)
41+
def_node_matcher :bad_method?, <<~PATTERN
42+
{
43+
(send $_ :nil?)
44+
(send $_ :== nil)
45+
(send $_ :!= nil)
46+
(send nil :equal? $_)
47+
(send $_ :equal? nil)
48+
(send (const {nil? cbase} :Primitive) :object_equal $_ nil)
49+
(send (const {nil? cbase} :Primitive) :object_equal nil $_)
50+
}
51+
PATTERN
52+
53+
def on_send(node)
54+
receiver = bad_method?(node)
55+
return unless receiver
56+
57+
add_offense(node) do |corrector|
58+
source_string = "Primitive.nil?(#{receiver.source})"
59+
source_string = "!#{source_string}" if node.method_name == :!=
60+
corrector.replace(node.loc.expression, source_string)
61+
end
62+
end
63+
end
64+
end
65+
end
66+
end
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module TruffleRuby
6+
# Prefer Primitive method `object_class` to get a logical class of an object.
7+
#
8+
# @example
9+
#
10+
# # bad
11+
# object.class
12+
#
13+
# # good
14+
# Primitive.object_class(object)
15+
#
16+
class ReplaceWithPrimitiveObjectClass < Base
17+
extend AutoCorrector
18+
19+
MSG = 'Use `Primitive.object_class` instead of `Object#class`'
20+
RESTRICT_ON_SEND = %i[class].freeze
21+
22+
# @!method bad_method?(node)
23+
def_node_matcher :bad_method?, <<~PATTERN
24+
(send $_ :class)
25+
PATTERN
26+
27+
def on_send(node)
28+
receiver = bad_method?(node)
29+
return unless receiver
30+
31+
add_offense(node) do |corrector|
32+
source_string = "Primitive.object_class(#{receiver.source})"
33+
corrector.replace(node.loc.expression, source_string)
34+
end
35+
end
36+
end
37+
end
38+
end
39+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module TruffleRuby
6+
# Prefer Primitive method `object_equal` to check whether two objects are
7+
# the same object.
8+
#
9+
# @example
10+
#
11+
# # bad
12+
# foo.equal?(bar)
13+
#
14+
# # good
15+
# Primitive.object_equal(foo, bar)
16+
#
17+
class ReplaceWithPrimitiveObjectEqual < Base
18+
extend AutoCorrector
19+
20+
MSG = 'Use `Primitive.object_equal` instead of `#equal?`'
21+
RESTRICT_ON_SEND = %i[equal?].freeze
22+
23+
# @!method bad_method?(node)
24+
def_node_matcher :bad_method?, <<~PATTERN
25+
(send $_ :equal? $_)
26+
PATTERN
27+
28+
def on_send(node)
29+
captures = bad_method?(node)
30+
return unless captures
31+
32+
add_offense(node) do |corrector|
33+
receiver, argument = captures.map { |n| n&.source }
34+
receiver ||= 'self'
35+
36+
source_string = "Primitive.object_equal(#{receiver}, #{argument})"
37+
corrector.replace(node.loc.expression, source_string)
38+
end
39+
end
40+
end
41+
end
42+
end
43+
end
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module TruffleRuby
6+
# Prefer Primitive method `object_kind_of?` to check an object class for
7+
# performance reasons.
8+
#
9+
# @safety
10+
# This cop is unsafe because #=== call's receiver might be not a module.
11+
#
12+
# @example
13+
#
14+
# # bad
15+
# a.is_a?(String)
16+
#
17+
# # bad
18+
# a.kind_of?(String)
19+
#
20+
# # bad
21+
# String === a
22+
#
23+
# # good
24+
# Primitive.object_kind_of?(a, String)
25+
#
26+
class ReplaceWithPrimitiveObjectKindOf < Base
27+
extend AutoCorrector
28+
29+
MSG = 'Use `Primitive.object_kind_of?` instead of `#kind_of?` or `#is_a?`'
30+
RESTRICT_ON_SEND = %i[is_a? kind_of? ===].freeze
31+
32+
# @!method bad_method?(node)
33+
def_node_matcher :bad_method?, <<~PATTERN
34+
{
35+
(send $_ { :is_a? :kind_of? } $_)
36+
(send $const :=== $_)
37+
}
38+
PATTERN
39+
40+
def on_send(node)
41+
captures = bad_method?(node)
42+
return unless captures
43+
44+
add_offense(node) do |corrector|
45+
source_string = build_expression_to_replace_by(node, captures)
46+
corrector.replace(node.loc.expression, source_string)
47+
end
48+
end
49+
50+
private
51+
52+
def build_expression_to_replace_by(node, captures)
53+
if node.method_name == :===
54+
object = captures[1].source
55+
constant = captures[0].source
56+
else
57+
object = captures[0]&.source || 'self'
58+
constant = captures[1].source
59+
end
60+
61+
"Primitive.object_kind_of?(#{object}, #{constant})"
62+
end
63+
end
64+
end
65+
end
66+
end

0 commit comments

Comments
 (0)