rubocop-thread_safety 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ci.yml +26 -0
- data/.github/workflows/lint.yml +19 -0
- data/.rubocop.yml +10 -1
- data/.rubocop_todo.yml +12 -0
- data/Appraisals +4 -18
- data/LICENSE.txt +2 -1
- data/README.md +7 -5
- data/config/default.yml +1 -0
- data/gemfiles/{rubocop_0.53.gemfile → rubocop_0.90.gemfile} +1 -1
- data/lib/rubocop/cop/thread_safety/class_and_module_attributes.rb +12 -2
- data/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb +86 -12
- data/lib/rubocop/cop/thread_safety/mutable_class_instance_variable.rb +32 -18
- data/lib/rubocop/cop/thread_safety/new_thread.rb +4 -2
- data/lib/rubocop/thread_safety/version.rb +1 -1
- data/rubocop-thread_safety.gemspec +3 -3
- metadata +12 -11
- data/.travis.yml +0 -64
- data/gemfiles/rubocop_0.81.gemfile +0 -7
- data/gemfiles/rubocop_0.86.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6186a05451917191f601a118b61cfd9e14fe59a4a187daa09af557450fee9935
|
4
|
+
data.tar.gz: 2a161a1fabc1fd5cdee9d13b3cd7729e497a4e8c2862427d002baaa1943b0bf0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aaa04443787ec115fa6dc9e8aa3b069fe2bf7967e38c9eec9ea5c00c9c3d32208dc161a5cb082888279dd183f25acf935a3ccd3aac854e78b1b727ccb3c9121e
|
7
|
+
data.tar.gz: 7957032ddf36e744c0b1dd640bfcf1f3f9e1f899cb73bb1566c8e88ce858e008637a8e3502baaa266617100c89e62be8a852cea471a0c358de1e7c62b7fada86
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
ruby: ["2.5", "2.6", "2.7", "3.0", "3.1", "3.2", ruby-head, jruby-9.2, jruby-9.3]
|
14
|
+
rubocop_version: ["0.90", "1.20"]
|
15
|
+
env:
|
16
|
+
BUNDLE_GEMFILE: "gemfiles/rubocop_${{ matrix.rubocop_version }}.gemfile"
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v3
|
19
|
+
- name: Set up Ruby
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
bundler-cache: true # 'bundle install' and cache gems
|
23
|
+
ruby-version: ${{ matrix.ruby }}
|
24
|
+
bundler: 2.3.26
|
25
|
+
- name: Run tests
|
26
|
+
run: bundle exec rspec
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Lint
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
lint:
|
7
|
+
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
name: Rubocop
|
10
|
+
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v3
|
13
|
+
- name: Set up Ruby
|
14
|
+
uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
bundler-cache: true # 'bundle install' and cache gems
|
17
|
+
ruby-version: "2.7"
|
18
|
+
- name: Run Rubocop
|
19
|
+
run: bundle exec rubocop
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
require:
|
4
|
+
- rubocop/cop/internal_affairs
|
5
|
+
|
1
6
|
AllCops:
|
2
7
|
DisplayCopNames: true
|
3
|
-
TargetRubyVersion: 2.
|
8
|
+
TargetRubyVersion: 2.5
|
4
9
|
|
5
10
|
Lint/RaiseException:
|
6
11
|
Enabled: true
|
@@ -31,6 +36,10 @@ Style/AutoResourceCleanup:
|
|
31
36
|
Style/CollectionMethods:
|
32
37
|
Enabled: true
|
33
38
|
|
39
|
+
Style/FormatStringToken:
|
40
|
+
Exclude:
|
41
|
+
- spec/**/*
|
42
|
+
|
34
43
|
Style/FrozenStringLiteralComment:
|
35
44
|
Exclude:
|
36
45
|
- "gemfiles/*.gemfile"
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config --no-auto-gen-timestamp`
|
3
|
+
# using RuboCop version 1.12.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 3
|
10
|
+
InternalAffairs/NodeDestructuring:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/rubocop/cop/thread_safety/mutable_class_instance_variable.rb'
|
data/Appraisals
CHANGED
@@ -1,23 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
appraise 'rubocop-0.
|
4
|
-
gem 'rubocop', '~> 0.
|
3
|
+
appraise 'rubocop-0.90' do
|
4
|
+
gem 'rubocop', '~> 0.90.0'
|
5
5
|
end
|
6
6
|
|
7
|
-
appraise 'rubocop-
|
8
|
-
gem 'rubocop', '~>
|
9
|
-
end
|
10
|
-
|
11
|
-
if Gem::Requirement.new('>= 2.4.0')
|
12
|
-
.satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
13
|
-
appraise 'rubocop-0.86' do
|
14
|
-
gem 'rubocop', '~> 0.86.0'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
if Gem::Requirement.new('>= 2.5.0')
|
19
|
-
.satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
20
|
-
appraise 'rubocop-1.20' do
|
21
|
-
gem 'rubocop', '~> 1.20.0'
|
22
|
-
end
|
7
|
+
appraise 'rubocop-1.20' do
|
8
|
+
gem 'rubocop', '~> 1.20.0'
|
23
9
|
end
|
data/LICENSE.txt
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
Copyright 2016-
|
1
|
+
Portions Copyright 2016-2023 Michael Gee and contributors
|
2
|
+
Portions Copyright 2016-2023 CoverMyMeds
|
2
3
|
|
3
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
5
|
|
data/README.md
CHANGED
@@ -7,10 +7,10 @@ Thread-safety analysis for your projects, as an extension to
|
|
7
7
|
|
8
8
|
### Installation into an application
|
9
9
|
|
10
|
-
Add this line to your application's Gemfile:
|
10
|
+
Add this line to your application's Gemfile (using `require: false` as it's a standalone tool):
|
11
11
|
|
12
12
|
```ruby
|
13
|
-
gem 'rubocop-thread_safety'
|
13
|
+
gem 'rubocop-thread_safety', require: false
|
14
14
|
```
|
15
15
|
|
16
16
|
Install it with Bundler by invoking:
|
@@ -36,7 +36,7 @@ Scan the application for just thread-safety issues:
|
|
36
36
|
|
37
37
|
### Configuration
|
38
38
|
|
39
|
-
There are some added [configuration options](https://github.com/
|
39
|
+
There are some added [configuration options](https://github.com/rubocop/rubocop-thread_safety/blob/master/config/default.yml) that can be tweaked to modify the behaviour of these thread-safety cops.
|
40
40
|
|
41
41
|
### Correcting code for thread-safety
|
42
42
|
|
@@ -68,9 +68,11 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
68
68
|
|
69
69
|
## Contributing
|
70
70
|
|
71
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
71
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rubocop/rubocop-thread_safety.
|
72
72
|
|
73
73
|
## Copyright
|
74
74
|
|
75
|
-
Copyright (c) 2016-
|
75
|
+
Portions Copyright (c) 2016-2023 Michael Gee and [contributors](https://github.com/rubocop/rubocop-thread_safety/graphs/contributors).
|
76
|
+
Portions Copyright (c) 2016-2023 CoverMyMeds.
|
77
|
+
|
76
78
|
See [LICENSE.txt](LICENSE.txt) for further details.
|
data/config/default.yml
CHANGED
@@ -14,6 +14,7 @@ ThreadSafety/MutableClassInstanceVariable:
|
|
14
14
|
Description: 'Do not assign mutable objects to class instance variables.'
|
15
15
|
Enabled: true
|
16
16
|
EnforcedStyle: literals
|
17
|
+
SafeAutoCorrect: false
|
17
18
|
SupportedStyles:
|
18
19
|
# literals: freeze literals assigned to constants
|
19
20
|
# strict: freeze all constants
|
@@ -12,27 +12,37 @@ module RuboCop
|
|
12
12
|
# class User
|
13
13
|
# cattr_accessor :current_user
|
14
14
|
# end
|
15
|
-
class ClassAndModuleAttributes <
|
15
|
+
class ClassAndModuleAttributes < Base
|
16
16
|
MSG = 'Avoid mutating class and module attributes.'
|
17
|
+
RESTRICT_ON_SEND = %i[
|
18
|
+
mattr_writer mattr_accessor cattr_writer cattr_accessor
|
19
|
+
class_attribute
|
20
|
+
attr attr_accessor attr_writer
|
21
|
+
attr_internal attr_internal_accessor attr_internal_writer
|
22
|
+
].freeze
|
17
23
|
|
24
|
+
# @!method mattr?(node)
|
18
25
|
def_node_matcher :mattr?, <<~MATCHER
|
19
26
|
(send nil?
|
20
27
|
{:mattr_writer :mattr_accessor :cattr_writer :cattr_accessor}
|
21
28
|
...)
|
22
29
|
MATCHER
|
23
30
|
|
31
|
+
# @!method attr?(node)
|
24
32
|
def_node_matcher :attr?, <<~MATCHER
|
25
33
|
(send nil?
|
26
34
|
{:attr :attr_accessor :attr_writer}
|
27
35
|
...)
|
28
36
|
MATCHER
|
29
37
|
|
38
|
+
# @!method attr_internal?(node)
|
30
39
|
def_node_matcher :attr_internal?, <<~MATCHER
|
31
40
|
(send nil?
|
32
41
|
{:attr_internal :attr_internal_accessor :attr_internal_writer}
|
33
42
|
...)
|
34
43
|
MATCHER
|
35
44
|
|
45
|
+
# @!method class_attr?(node)
|
36
46
|
def_node_matcher :class_attr?, <<~MATCHER
|
37
47
|
(send nil?
|
38
48
|
:class_attribute
|
@@ -43,7 +53,7 @@ module RuboCop
|
|
43
53
|
return unless mattr?(node) || class_attr?(node) ||
|
44
54
|
singleton_attr?(node)
|
45
55
|
|
46
|
-
add_offense(node
|
56
|
+
add_offense(node)
|
47
57
|
end
|
48
58
|
|
49
59
|
private
|
@@ -37,59 +37,101 @@ module RuboCop
|
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
# end
|
40
|
-
|
40
|
+
#
|
41
|
+
# module Example
|
42
|
+
# class_methods do
|
43
|
+
# def test(params)
|
44
|
+
# @params = params
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# module Example
|
50
|
+
# module_function
|
51
|
+
#
|
52
|
+
# def test(params)
|
53
|
+
# @params = params
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# module Example
|
58
|
+
# def test(params)
|
59
|
+
# @params = params
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# module_function :test
|
63
|
+
# end
|
64
|
+
class InstanceVariableInClassMethod < Base
|
41
65
|
MSG = 'Avoid instance variables in class methods.'
|
66
|
+
RESTRICT_ON_SEND = %i[
|
67
|
+
instance_variable_set
|
68
|
+
instance_variable_get
|
69
|
+
].freeze
|
42
70
|
|
71
|
+
# @!method instance_variable_set_call?(node)
|
43
72
|
def_node_matcher :instance_variable_set_call?, <<~MATCHER
|
44
73
|
(send nil? :instance_variable_set (...) (...))
|
45
74
|
MATCHER
|
46
75
|
|
76
|
+
# @!method instance_variable_get_call?(node)
|
47
77
|
def_node_matcher :instance_variable_get_call?, <<~MATCHER
|
48
78
|
(send nil? :instance_variable_get (...))
|
49
79
|
MATCHER
|
50
80
|
|
51
81
|
def on_ivar(node)
|
52
82
|
return unless class_method_definition?(node)
|
83
|
+
return if method_definition?(node)
|
53
84
|
return if synchronized?(node)
|
54
85
|
|
55
|
-
add_offense(node
|
86
|
+
add_offense(node.loc.name)
|
56
87
|
end
|
57
88
|
alias on_ivasgn on_ivar
|
58
89
|
|
59
90
|
def on_send(node)
|
60
91
|
return unless instance_variable_call?(node)
|
61
92
|
return unless class_method_definition?(node)
|
93
|
+
return if method_definition?(node)
|
62
94
|
return if synchronized?(node)
|
63
95
|
|
64
|
-
add_offense(node
|
96
|
+
add_offense(node)
|
65
97
|
end
|
66
98
|
|
67
99
|
private
|
68
100
|
|
69
101
|
def class_method_definition?(node)
|
102
|
+
return false if method_definition?(node)
|
103
|
+
|
70
104
|
in_defs?(node) ||
|
71
105
|
in_def_sclass?(node) ||
|
72
106
|
in_def_class_methods?(node) ||
|
107
|
+
in_def_module_function?(node) ||
|
73
108
|
singleton_method_definition?(node)
|
74
109
|
end
|
75
110
|
|
76
111
|
def in_defs?(node)
|
77
|
-
node.ancestors.any?
|
78
|
-
ancestor.type == :defs
|
79
|
-
end
|
112
|
+
node.ancestors.any?(&:defs_type?)
|
80
113
|
end
|
81
114
|
|
82
115
|
def in_def_sclass?(node)
|
83
|
-
defn = node.ancestors.find
|
84
|
-
ancestor.type == :def
|
85
|
-
end
|
116
|
+
defn = node.ancestors.find(&:def_type?)
|
86
117
|
|
87
|
-
defn&.ancestors&.any?
|
88
|
-
ancestor.type == :sclass
|
89
|
-
end
|
118
|
+
defn&.ancestors&.any?(&:sclass_type?)
|
90
119
|
end
|
91
120
|
|
92
121
|
def in_def_class_methods?(node)
|
122
|
+
in_def_class_methods_dsl?(node) || in_def_class_methods_module?(node)
|
123
|
+
end
|
124
|
+
|
125
|
+
def in_def_class_methods_dsl?(node)
|
126
|
+
node.ancestors.any? do |ancestor|
|
127
|
+
next unless ancestor.block_type?
|
128
|
+
next unless ancestor.children.first.is_a? AST::SendNode
|
129
|
+
|
130
|
+
ancestor.children.first.command? :class_methods
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def in_def_class_methods_module?(node)
|
93
135
|
defn = node.ancestors.find(&:def_type?)
|
94
136
|
return unless defn
|
95
137
|
|
@@ -101,6 +143,14 @@ module RuboCop
|
|
101
143
|
class_methods_module?(mod)
|
102
144
|
end
|
103
145
|
|
146
|
+
def in_def_module_function?(node)
|
147
|
+
defn = node.ancestors.find(&:def_type?)
|
148
|
+
return unless defn
|
149
|
+
|
150
|
+
defn.left_siblings.any? { |sibling| module_function_bare_access_modifier?(sibling) } ||
|
151
|
+
defn.right_siblings.any? { |sibling| module_function_for?(sibling, defn.method_name) }
|
152
|
+
end
|
153
|
+
|
104
154
|
def singleton_method_definition?(node)
|
105
155
|
node.ancestors.any? do |ancestor|
|
106
156
|
next unless ancestor.children.first.is_a? AST::SendNode
|
@@ -109,6 +159,14 @@ module RuboCop
|
|
109
159
|
end
|
110
160
|
end
|
111
161
|
|
162
|
+
def method_definition?(node)
|
163
|
+
node.ancestors.any? do |ancestor|
|
164
|
+
next unless ancestor.children.first.is_a? AST::SendNode
|
165
|
+
|
166
|
+
ancestor.children.first.command? :define_method
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
112
170
|
def synchronized?(node)
|
113
171
|
node.ancestors.find do |ancestor|
|
114
172
|
next unless ancestor.block_type?
|
@@ -122,9 +180,25 @@ module RuboCop
|
|
122
180
|
instance_variable_set_call?(node) || instance_variable_get_call?(node)
|
123
181
|
end
|
124
182
|
|
183
|
+
def module_function_bare_access_modifier?(node)
|
184
|
+
return false unless node
|
185
|
+
|
186
|
+
node.send_type? && node.bare_access_modifier? && node.method?(:module_function)
|
187
|
+
end
|
188
|
+
|
189
|
+
def match_name?(arg_name, method_name)
|
190
|
+
arg_name.to_sym == method_name.to_sym
|
191
|
+
end
|
192
|
+
|
193
|
+
# @!method class_methods_module?(node)
|
125
194
|
def_node_matcher :class_methods_module?, <<~PATTERN
|
126
195
|
(module (const _ :ClassMethods) ...)
|
127
196
|
PATTERN
|
197
|
+
|
198
|
+
# @!method module_function_for?(node)
|
199
|
+
def_node_matcher :module_function_for?, <<~PATTERN
|
200
|
+
(send nil? {:module_function} ({sym str} #match_name?(%1)))
|
201
|
+
PATTERN
|
128
202
|
end
|
129
203
|
end
|
130
204
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module ThreadSafety
|
6
|
-
#
|
6
|
+
# Checks whether some class instance variable isn't a
|
7
7
|
# mutable literal (e.g. array or hash).
|
8
8
|
#
|
9
9
|
# It is based on Style/MutableConstant from RuboCop.
|
@@ -72,7 +72,8 @@ module RuboCop
|
|
72
72
|
# end
|
73
73
|
# end.freeze
|
74
74
|
# end
|
75
|
-
class MutableClassInstanceVariable <
|
75
|
+
class MutableClassInstanceVariable < Base
|
76
|
+
extend AutoCorrector
|
76
77
|
include FrozenStringLiteral
|
77
78
|
include ConfigurableEnforcedStyle
|
78
79
|
|
@@ -108,23 +109,21 @@ module RuboCop
|
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
111
|
-
def autocorrect(node)
|
112
|
+
def autocorrect(corrector, node)
|
112
113
|
expr = node.source_range
|
113
114
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
corrector.insert_after(expr, ')')
|
124
|
-
end
|
125
|
-
|
126
|
-
corrector.insert_after(expr, '.freeze')
|
115
|
+
splat_value = splat_value(node)
|
116
|
+
if splat_value
|
117
|
+
correct_splat_expansion(corrector, expr, splat_value)
|
118
|
+
elsif node.array_type? && !node.bracketed?
|
119
|
+
corrector.insert_before(expr, '[')
|
120
|
+
corrector.insert_after(expr, ']')
|
121
|
+
elsif requires_parentheses?(node)
|
122
|
+
corrector.insert_before(expr, '(')
|
123
|
+
corrector.insert_after(expr, ')')
|
127
124
|
end
|
125
|
+
|
126
|
+
corrector.insert_after(expr, '.freeze')
|
128
127
|
end
|
129
128
|
|
130
129
|
private
|
@@ -152,7 +151,9 @@ module RuboCop
|
|
152
151
|
return if operation_produces_threadsafe_object?(value)
|
153
152
|
return if frozen_string_literal?(value)
|
154
153
|
|
155
|
-
add_offense(value)
|
154
|
+
add_offense(value) do |corrector|
|
155
|
+
autocorrect(corrector, value)
|
156
|
+
end
|
156
157
|
end
|
157
158
|
|
158
159
|
def check(value)
|
@@ -160,7 +161,9 @@ module RuboCop
|
|
160
161
|
range_enclosed_in_parentheses?(value)
|
161
162
|
return if frozen_string_literal?(value)
|
162
163
|
|
163
|
-
add_offense(value)
|
164
|
+
add_offense(value) do |corrector|
|
165
|
+
autocorrect(corrector, value)
|
166
|
+
end
|
164
167
|
end
|
165
168
|
|
166
169
|
def in_class?(node)
|
@@ -174,6 +177,7 @@ module RuboCop
|
|
174
177
|
|
175
178
|
def container?(node)
|
176
179
|
return true if define_singleton_method?(node)
|
180
|
+
return true if define_method?(node)
|
177
181
|
|
178
182
|
%i[def defs class module].include?(node.type)
|
179
183
|
end
|
@@ -205,16 +209,24 @@ module RuboCop
|
|
205
209
|
end
|
206
210
|
end
|
207
211
|
|
212
|
+
# @!method define_singleton_method?(node)
|
208
213
|
def_node_matcher :define_singleton_method?, <<~PATTERN
|
209
214
|
(block (send nil? :define_singleton_method ...) ...)
|
210
215
|
PATTERN
|
211
216
|
|
217
|
+
# @!method define_method?(node)
|
218
|
+
def_node_matcher :define_method?, <<~PATTERN
|
219
|
+
(block (send nil? :define_method ...) ...)
|
220
|
+
PATTERN
|
221
|
+
|
222
|
+
# @!method splat_value(node)
|
212
223
|
def_node_matcher :splat_value, <<~PATTERN
|
213
224
|
(array (splat $_))
|
214
225
|
PATTERN
|
215
226
|
|
216
227
|
# NOTE: Some of these patterns may not actually return an immutable
|
217
228
|
# object but we will consider them immutable for this cop.
|
229
|
+
# @!method operation_produces_immutable_object?(node)
|
218
230
|
def_node_matcher :operation_produces_immutable_object?, <<~PATTERN
|
219
231
|
{
|
220
232
|
(const _ _)
|
@@ -231,6 +243,7 @@ module RuboCop
|
|
231
243
|
}
|
232
244
|
PATTERN
|
233
245
|
|
246
|
+
# @!method operation_produces_threadsafe_object?(node)
|
234
247
|
def_node_matcher :operation_produces_threadsafe_object?, <<~PATTERN
|
235
248
|
{
|
236
249
|
(send (const {nil? cbase} :Queue) :new ...)
|
@@ -263,6 +276,7 @@ module RuboCop
|
|
263
276
|
}
|
264
277
|
PATTERN
|
265
278
|
|
279
|
+
# @!method range_enclosed_in_parentheses?(node)
|
266
280
|
def_node_matcher :range_enclosed_in_parentheses?, <<~PATTERN
|
267
281
|
(begin ({irange erange} _ _))
|
268
282
|
PATTERN
|
@@ -10,9 +10,11 @@ module RuboCop
|
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
12
|
# Thread.new { do_work }
|
13
|
-
class NewThread <
|
13
|
+
class NewThread < Base
|
14
14
|
MSG = 'Avoid starting new threads.'
|
15
|
+
RESTRICT_ON_SEND = %i[new].freeze
|
15
16
|
|
17
|
+
# @!method new_thread?(node)
|
16
18
|
def_node_matcher :new_thread?, <<~MATCHER
|
17
19
|
(send (const {nil? cbase} :Thread) :new)
|
18
20
|
MATCHER
|
@@ -20,7 +22,7 @@ module RuboCop
|
|
20
22
|
def on_send(node)
|
21
23
|
return unless new_thread?(node)
|
22
24
|
|
23
|
-
add_offense(node
|
25
|
+
add_offense(node)
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
Thread-safety checks via static analysis.
|
16
16
|
A plugin for the RuboCop code style enforcing & linting tool.
|
17
17
|
DESCRIPTION
|
18
|
-
spec.homepage = 'https://github.com/
|
18
|
+
spec.homepage = 'https://github.com/rubocop/rubocop-thread_safety'
|
19
19
|
spec.licenses = ['MIT']
|
20
20
|
|
21
21
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
@@ -26,9 +26,9 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ['lib']
|
28
28
|
|
29
|
-
spec.required_ruby_version = '>= 2.
|
29
|
+
spec.required_ruby_version = '>= 2.5.0'
|
30
30
|
|
31
|
-
spec.add_runtime_dependency 'rubocop', '>= 0.
|
31
|
+
spec.add_runtime_dependency 'rubocop', '>= 0.90.0'
|
32
32
|
|
33
33
|
spec.add_development_dependency 'appraisal'
|
34
34
|
spec.add_development_dependency 'bundler', '>= 1.10', '< 3'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-thread_safety
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Gee
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.90.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.90.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: appraisal
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,10 +109,13 @@ executables: []
|
|
109
109
|
extensions: []
|
110
110
|
extra_rdoc_files: []
|
111
111
|
files:
|
112
|
+
- ".github/dependabot.yml"
|
113
|
+
- ".github/workflows/ci.yml"
|
114
|
+
- ".github/workflows/lint.yml"
|
112
115
|
- ".gitignore"
|
113
116
|
- ".rspec"
|
114
117
|
- ".rubocop.yml"
|
115
|
-
- ".
|
118
|
+
- ".rubocop_todo.yml"
|
116
119
|
- Appraisals
|
117
120
|
- Gemfile
|
118
121
|
- LICENSE.txt
|
@@ -121,9 +124,7 @@ files:
|
|
121
124
|
- bin/console
|
122
125
|
- bin/setup
|
123
126
|
- config/default.yml
|
124
|
-
- gemfiles/rubocop_0.
|
125
|
-
- gemfiles/rubocop_0.81.gemfile
|
126
|
-
- gemfiles/rubocop_0.86.gemfile
|
127
|
+
- gemfiles/rubocop_0.90.gemfile
|
127
128
|
- gemfiles/rubocop_1.20.gemfile
|
128
129
|
- lib/rubocop-thread_safety.rb
|
129
130
|
- lib/rubocop/cop/thread_safety/class_and_module_attributes.rb
|
@@ -134,7 +135,7 @@ files:
|
|
134
135
|
- lib/rubocop/thread_safety/inject.rb
|
135
136
|
- lib/rubocop/thread_safety/version.rb
|
136
137
|
- rubocop-thread_safety.gemspec
|
137
|
-
homepage: https://github.com/
|
138
|
+
homepage: https://github.com/rubocop/rubocop-thread_safety
|
138
139
|
licenses:
|
139
140
|
- MIT
|
140
141
|
metadata: {}
|
@@ -146,14 +147,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
147
|
requirements:
|
147
148
|
- - ">="
|
148
149
|
- !ruby/object:Gem::Version
|
149
|
-
version: 2.
|
150
|
+
version: 2.5.0
|
150
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
152
|
requirements:
|
152
153
|
- - ">="
|
153
154
|
- !ruby/object:Gem::Version
|
154
155
|
version: '0'
|
155
156
|
requirements: []
|
156
|
-
rubygems_version: 3.
|
157
|
+
rubygems_version: 3.2.33
|
157
158
|
signing_key:
|
158
159
|
specification_version: 4
|
159
160
|
summary: Thread-safety checks via static analysis
|
data/.travis.yml
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
cache: bundler
|
2
|
-
language: ruby
|
3
|
-
rvm:
|
4
|
-
- jruby-9.2.9.0
|
5
|
-
- 2.3.0
|
6
|
-
- 2.4
|
7
|
-
- 2.5
|
8
|
-
- 2.6
|
9
|
-
- 2.7
|
10
|
-
- 3.0
|
11
|
-
|
12
|
-
gemfile:
|
13
|
-
- gemfiles/rubocop_0.53.gemfile
|
14
|
-
- gemfiles/rubocop_0.81.gemfile
|
15
|
-
- gemfiles/rubocop_0.86.gemfile
|
16
|
-
- gemfiles/rubocop_1.20.gemfile
|
17
|
-
|
18
|
-
script_rubocop: &script_rubocop
|
19
|
-
- bundle exec rspec
|
20
|
-
- bundle exec rubocop
|
21
|
-
|
22
|
-
jobs:
|
23
|
-
fast_finish: true
|
24
|
-
exclude:
|
25
|
-
- rvm: 2.3.0
|
26
|
-
gemfile: gemfiles/rubocop_0.86.gemfile
|
27
|
-
- rvm: 2.3.0
|
28
|
-
gemfile: gemfiles/rubocop_1.20.gemfile
|
29
|
-
- rvm: 2.5
|
30
|
-
gemfile: gemfiles/rubocop_0.53.gemfile
|
31
|
-
- rvm: 2.6
|
32
|
-
gemfile: gemfiles/rubocop_0.53.gemfile
|
33
|
-
- rvm: 2.7
|
34
|
-
gemfile: gemfiles/rubocop_0.53.gemfile
|
35
|
-
- rvm: 3.0
|
36
|
-
gemfile: gemfiles/rubocop_0.53.gemfile
|
37
|
-
include:
|
38
|
-
- rvm: jruby-9.2.9.0
|
39
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
40
|
-
script: *script_rubocop
|
41
|
-
- rvm: 2.3.0
|
42
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
43
|
-
script: *script_rubocop
|
44
|
-
- rvm: 2.4
|
45
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
46
|
-
script: *script_rubocop
|
47
|
-
- rvm: 2.5
|
48
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
49
|
-
script: *script_rubocop
|
50
|
-
- rvm: 2.6
|
51
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
52
|
-
script: *script_rubocop
|
53
|
-
- rvm: 2.7
|
54
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
55
|
-
script: *script_rubocop
|
56
|
-
- rvm: 3.0
|
57
|
-
gemfile: gemfiles/rubocop_0.81.gemfile
|
58
|
-
script: *script_rubocop
|
59
|
-
|
60
|
-
before_install: gem install --remote bundler
|
61
|
-
install:
|
62
|
-
- bundle install --retry=3
|
63
|
-
script:
|
64
|
-
- bundle exec rspec
|