Git Product home page Git Product logo

rubocop-thread_safety's Introduction

RuboCop Logo


Ruby Style Guide Gem Version CircleCI Status Actions Status Test Coverage Maintainability Discord

Role models are important.
-- Officer Alex J. Murphy / RoboCop

RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter. Out of the box it will enforce many of the guidelines outlined in the community Ruby Style Guide. Apart from reporting the problems discovered in your code, RuboCop can also automatically fix many of them for you.

RuboCop is extremely flexible and most aspects of its behavior can be tweaked via various configuration options.


Patreon OpenCollective OpenCollective Tidelift

Working on RuboCop is often fun, but it also requires a great deal of time and energy.

Please consider financially supporting its ongoing development.

Installation

RuboCop's installation is pretty standard:

$ gem install rubocop

If you'd rather install RuboCop using bundler, add a line for it in your Gemfile (but set the require option to false, as it is a standalone tool):

gem 'rubocop', require: false

RuboCop is stable between minor versions, both in terms of API and cop configuration. We aim to ease the maintenance of RuboCop extensions and the upgrades between RuboCop releases. All big changes are reserved for major releases. To prevent an unwanted RuboCop update you might want to use a conservative version lock in your Gemfile:

gem 'rubocop', '~> 1.63', require: false

See our versioning policy for further details.

Quickstart

Just type rubocop in a Ruby project's folder and watch the magic happen.

$ cd my/cool/ruby/project
$ rubocop

You can also use this magic in your favorite editor with RuboCop's built-in LSP server.

Documentation

You can read a lot more about RuboCop in its official docs.

Compatibility

RuboCop officially supports the following runtime Ruby implementations:

  • MRI 2.7+
  • JRuby 9.4+

Targets Ruby 2.0+ code analysis.

See the compatibility documentation for further details.

Readme Badge

If you use RuboCop in your project, you can include one of these badges in your readme to let people know that your code is written following the community Ruby Style Guide.

Ruby Style Guide

Ruby Style Guide

Here are the Markdown snippets for the two badges:

[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)

[![Ruby Style Guide](https://img.shields.io/badge/code_style-community-brightgreen.svg)](https://rubystyle.guide)

Team

Here's a list of RuboCop's core developers:

See the team page for more details.

Logo

RuboCop's logo was created by Dimiter Petrov. You can find the logo in various formats here.

The logo is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

Contributors

Here's a list of all the people who have contributed to the development of RuboCop.

I'm extremely grateful to each and every one of them!

If you'd like to contribute to RuboCop, please take the time to go through our short contribution guidelines.

Converting more of the Ruby Style Guide into RuboCop cops is our top priority right now. Writing a new cop is a great way to dive into RuboCop!

Of course, bug reports and suggestions for improvements are always welcome. GitHub pull requests are even better! :-)

Funding

While RuboCop is free software and will always be, the project would benefit immensely from some funding. Raising a monthly budget of a couple of thousand dollars would make it possible to pay people to work on certain complex features, fund other development related stuff (e.g. hardware, conference trips) and so on. Raising a monthly budget of over $5000 would open the possibility of someone working full-time on the project which would speed up the pace of development significantly.

We welcome both individual and corporate sponsors! We also offer a wide array of funding channels to account for your preferences (although currently Open Collective is our preferred funding platform).

If you're working in a company that's making significant use of RuboCop we'd appreciate it if you suggest to your company to become a RuboCop sponsor.

You can support the development of RuboCop via GitHub Sponsors, Patreon, PayPal, Open Collective and Tidelift .

Note: If doing a sponsorship in the form of donation is problematic for your company from an accounting standpoint, we'd recommend the use of Tidelift, where you can get a support-like subscription instead.

Open Collective Backers

Support us with a monthly donation and help us continue our activities. [Become a backer]

Open Collective Sponsors

Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor]

Changelog

RuboCop's changelog is available here.

Copyright

Copyright (c) 2012-2024 Bozhidar Batsov. See LICENSE.txt for further details.

rubocop-thread_safety's People

Contributors

bdewater avatar biinari avatar biow0lf avatar bquorning avatar emiedlar avatar koic avatar m-nakamura145 avatar mikegee avatar olliebennett avatar petergoldstein avatar pocke avatar ydah avatar ytjmt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rubocop-thread_safety's Issues

Time for a new release?

class Foo
  def self.bar
    define_method :baz do
      @x = 10
    end
  end
end
foo.rb:4:7: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
      @x = 10
      ^^

In the context of define_method instance variables are actual instance variables, not class instance variables.

Incompatibility with Rubocop 1.45.0

I have a project that uses several Rubocop extensions (rubocop-performance, rubocop-rails, rubocop-rake, rubocop-rspec, rubocop-thread_safety). For Rubocop versions prior to Rubocop 1.45.0 this all runs fine.

When upgrading to the just released Rubocop 1.45.0 I get an error when I attempt to run bundle exec rubocop. Specifically I get:

private method `begin_investigation' called for #<RuboCop::Cop::ThreadSafety::InstanceVariableInClassMethod:0x... <instance to string>
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cop/commissioner.rb:100:in `block in begin_investigation'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cop/commissioner.rb:99:in `each'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cop/commissioner.rb:99:in `begin_investigation'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cop/commissioner.rb:82:in `investigate'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cop/team.rb:155:in `investigate_partial'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cop/team.rb:97:in `investigate'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:345:in `block in inspect_file'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:344:in `each'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:344:in `flat_map'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:344:in `inspect_file'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:287:in `block in do_inspection_loop'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:321:in `block in iterate_until_no_changes'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:314:in `loop'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:314:in `iterate_until_no_changes'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:283:in `do_inspection_loop'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:164:in `block in file_offenses'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:189:in `file_offense_cache'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:163:in `file_offenses'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:99:in `block in warm_cache'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:587:in `call_with_index'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:557:in `process_incoming_jobs'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:537:in `block in worker'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:528:in `fork'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:528:in `worker'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:519:in `block in create_workers'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:518:in `each'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:518:in `each_with_index'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:518:in `create_workers'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:457:in `work_in_processes'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:294:in `map'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/parallel-1.22.1/lib/parallel.rb:238:in `each'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:99:in `warm_cache'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/runner.rb:72:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli/command/execute_runner.rb:26:in `block in execute_runner'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli/command/execute_runner.rb:52:in `with_redirect'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli/command/execute_runner.rb:25:in `execute_runner'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli/command/execute_runner.rb:17:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli/command.rb:11:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli/environment.rb:18:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli.rb:118:in `run_command'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli.rb:125:in `execute_runners'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli.rb:51:in `block in run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli.rb:77:in `profile_if_needed'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/lib/rubocop/cli.rb:43:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/exe/rubocop:19:in `block in <top (required)>'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/3.2.0/benchmark.rb:311:in `realtime'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rubocop-1.45.0/exe/rubocop:19:in `<top (required)>'
/Users/peter/.rbenv/versions/3.2.0/bin/rubocop:25:in `load'
/Users/peter/.rbenv/versions/3.2.0/bin/rubocop:25:in `<top (required)>'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/cli/exec.rb:58:in `load'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/cli/exec.rb:58:in `kernel_load'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/cli/exec.rb:23:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/cli.rb:491:in `exec'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/cli.rb:34:in `dispatch'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/cli.rb:28:in `start'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.6/exe/bundle:45:in `block in <top (required)>'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/Users/peter/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.6/exe/bundle:33:in `<top (required)>'

with very long instance to string removed.

Removing rubocop-thread_safety from my .rubocop.yml allow rubocop to run successfully again.

Consider disallowing ivars in methods of any module

This is a recreation of covermymeds/issues/22 opened by @biinari on Jun 22, 2020.


As an extension to the suggestion in covermymeds/issues/4, perhaps we should flag up ivars used in methods of any module.

This would unfortunately add some false positives as modules may be included in classes, making instance methods and hence would be using instance variables rather than class instance variables.

They could be individually checked by the user and ignored with a rubocop:disable comment. Or perhaps this should be an option to the InstanceVariableInClassMethod, which may be set depending on how prevalent extending modules is in the user's codebase.

Concerns I would like to catch would be:

module Mod
  def some_method(something)
    @params = something
  end
end

module ExtMod
  extend Mod
end

class ExtClass
  extend Mod
end

ExtMod.some_method(something) # sets a class instance variable on ExtMod
ExtClass.some_method(something) # sets a class instance variable on ExtClass

False positives that would be difficult / impossible to rule out in a static analysis:

module Mod
  def some_method(something)
    @params = something
  end
end

class Includer
  include Mod
end

instance = Includer.new
instance.some_method(something) # sets an instance variable on instance

Detect class_eval as class context

This is a recreation of covermymeds/issues/33 opened by @biinari on Jun 29, 2020.


When checking for class / module context, detect class_eval, module_eval, class_exec, module_exec. The class_* variants are aliases of the module_* variants. It should however be safe to assume class_* would be called on a class and module_* would be called on a module.

I don't think it is worth looking at class_eval or module_eval when given a string argument. Just interested in when any of these are given a block.

A reduced example that inspired this thought:

class Example
  class << self
    attr_reader :separator
  end
end

def separate_with(separator)
  Example.class_eval do
    @separator = separator
  end
end

Given there are multiple cops that need to check for the first class / module context, I think it would be useful to create a mixin module to help with the search. Something like

module RuboCop
  module Cop
    module ThreadSafety
      module Mixin
        module ClassModuleContext
          # return first class or module context in node's ancestors
          def find_context(node)
            # return first node that is a class, module, class_eval, module_eval or similar
          end

          def class_context?(node)
            # return true if node is a class context
          end

          def module_context?(node)
            # return true if node is a module context
          end
        end
      end
    end
  end
end

False positive: ThreadSafety/InstanceVariableInClassMethod in anonymous classes

Summary

ThreadSafety/InstanceVariableInClassMethod rule fires when assigning an anonymous class's instance variable.

Example file

class Outer
  def self.create_anonymous_class
    Class.new do
      def initialize
        @anonymous_variable = 'hi'
      end
    end
  end
end

Expected

No errors.

Actual

Inspecting 1 file
C

Offenses:

test.rb:7:9: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
        @anonymous_variable = 'hi'
        ^^^^^^^^^^^^^^^^^^^

False Positive: ivar in dynamic method definition of Class.new

Code:

module QueryExtensions
  def self.ensure_where_not_chain(base)
    base.class_eval do
      const_get(:WhereNotChain)
    rescue NameError
      klass = Class.new {
        def initialize(scope)
          @scope = scope
        end
      }

      const_set(:WhereNotChain, klass)
    end
    base.const_get(:WhereNotChain)
  end
end

Results:

config/hooks/after_gems/03.query_extensions.rb:183:13: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
            @scope = scope
            ^^^^^^

The parser is detecting the method definition in the dynamically created class as having an instance variable in a class method. this is not the case. it is defining a method in the class and the instance variable is for an instance

False positives on inheritance

hello! πŸ‘‹πŸ»

I'm seeing something that I believe might be a false positive.

I have a base class with some instance and class methods that other classes inherit from. The class methods are used to configure behavior for the class, like, will be wrapped in a transaction or not, something very similar to this

class Parent
  class << self
    def set(val)
      puts "Value: #{val}; #{Thread.current.object_id}"
      @val = val
      puts "Setting value to #{@val}; #{Thread.current.object_id}"
    end

    attr_reader :val
  end
end

class Children1 < Parent
  set(true)

  def initialize
    puts "Val for Children1: #{self.class.val}"
  end
end

class Children2 < Parent
  set(false)

  def initialize
    puts "Val for Children2: #{self.class.val}"
  end
end

The cop tells me that I have an offense at Parent but that doesn't seem like it:

irb(main):060:0> Thread.new { Children1.new }; Thread.new { Children2.new }
=> #<Thread:0x000000010b770ce8 (irb):60 run>
Value: true; 463920
Setting value to true; 463920
Val for Children1: true
Value: false; 463940
Setting value to false; 463940
Val for Children2: false
irb(main):061:0> Thread.new { Children1.new }; Thread.new { Children2.new }
=> #<Thread:0x000000010b823708 (irb):61 run>
Val for Children1: true
Val for Children2: false
irb(main):062:0> Thread.new { Children1.new }; Thread.new { Children2.new }
=> #<Thread:0x000000010b8d8d60 (irb):62 run>
Val for Children1: true
Val for Children2: false

The first time the different threads instantiate the children, set is called and set val at the Children level. Subsequent calls do not do it anymore and self.class.val returns the expected result.

To be honest, I don't know if this is really a false positive. Seems like the exact intended outcome since Rubocop doesn't know where this class will be used and/or will be inherited. I guess my question is: is it safe to ignore this cop in this specific class and case?

Can we have a cop to recommend not using Dir.chdir?

Is your feature request related to a problem? Please describe.

I was recently bitten by the issue that Dir.chdir (including with a block) actually affects the process (rather than somehow being local to the ruby thread ) and thus is non threadsafe.

Describe the solution you'd like

A built in cop to ban Dir.chdir.
Ruby 3.0 throws an error if you try to chdir within another chdir (from another thread) https://bugs.ruby-lang.org/issues/15661

Describe alternatives you've considered

It's possible to use this code more or less as is: https://gist.github.com/masutaka/68d372b7f7910f552eeb215bb2e5d3cc

but think it would be good to have it built in. Thoughts?

Detect ivars in Rack middleware

Instance variables in Rack middleware are bad. They are not thread safe and are insidious to track down issues relating to it.

Ref:

  1. puma/puma#2001
  2. https://bernardoamc.com/rails-middleware-leak/
  3. https://crypt.codemancers.com/posts/2018-06-07-frozen-middleware-with-rack-freeze/

Since this is such a gotcha, I (via my company) would gladly sponsor development of such a cop to walk the middleware hierarchy and catch offenders which could occur at app level or third party.

Parser error when using inline helper_method

Since v0.5.0, code using inline helper_method like this breaks the parser:

class StatsController < ApplicationController
  # .... 
  helper_method def calculator
    @calculator ||= Calculator.new(timeframe)
  end
end
bin/rubocop app/controllers/stats_controller.rb
Inspecting 1 file
An error occurred while ThreadSafety/InstanceVariableInClassMethod cop was inspecting /Users/ledermann/Projects/solectrus/solectrus/app/controllers/stats_controller.rb:4:4.
To see the complete backtrace run rubocop -d.
.

1 file inspected, no offenses detected

1 error occurred:
An error occurred while ThreadSafety/InstanceVariableInClassMethod cop was inspecting /Users/ledermann/Projects/solectrus/solectrus/app/controllers/stats_controller.rb:4:4.
Errors are usually caused by RuboCop bugs.
Please, report your problems to RuboCop's issue tracker.
https://github.com/rubocop/rubocop/issues

Mention the following information in the issue report:
1.48.1 (using Parser 3.2.1.1, rubocop-ast 1.28.0, running on ruby 3.2.1) [arm64-darwin22]


bin/rubocop app/controllers/stats_controller.rb -d
For /Users/ledermann/Projects/solectrus/solectrus: configuration from /Users/ledermann/Projects/solectrus/solectrus/.rubocop.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-performance-1.16.0/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-performance-1.16.0/config/default.yml
Default configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-1.48.1/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-rails-2.18.0/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-rails-2.18.0/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-capybara-2.17.1/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-capybara-2.17.1/lib/../config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-rspec-2.19.0/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-rspec-2.19.0/config/default.yml
configuration from /Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/config/default.yml
configuration from #{path}
Inheriting configuration from /Users/ledermann/Projects/solectrus/solectrus/node_modules/@prettier/plugin-ruby/rubocop.yml
Use parallel by default.
Skipping parallel inspection: only a single file needs inspection
Inspecting 1 file
Scanning /Users/ledermann/Projects/solectrus/solectrus/app/controllers/stats_controller.rb
An error occurred while ThreadSafety/InstanceVariableInClassMethod cop was inspecting /Users/ledermann/Projects/solectrus/solectrus/app/controllers/stats_controller.rb:4:4.
undefined method `send_type?' for :helper_method:Symbol
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb:186:in `module_function_bare_access_modifier?'
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb:150:in `block in in_def_module_function?'
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb:150:in `any?'
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb:150:in `in_def_module_function?'
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb:107:in `class_method_definition?'
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-thread_safety-0.5.0/lib/rubocop/cop/thread_safety/instance_variable_in_class_method.rb:82:in `on_ivar'
/Users/ledermann/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/rubocop-1.48.1/lib/rubocop/cop/commissioner.rb:107:in `public_send'

After changing the code to this, parsing works fine without any error:

class StatsController < ApplicationController
  # ....
  def calculator
    @calculator ||= Calculator.new(timeframe)
  end

  helper_method :calculator
end

False positive: ivar in Structs

Hi,

In the following example (scaled down from real code), InstanceVariableInClassMethod's diagnostic is wrong.

$ cat struct.rb
class Foo
  def self.new_struct
    Struct.new(:foo) {
      def bar
        @bar ||= 42
      end
    }.new
  end
end

s = Foo.new_struct
puts s.bar
$ bundle exec rubocop struct.rb
Inspecting 1 file
C

Offenses:

struct.rb:5:9: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
        @bar ||= 42
        ^^^^

1 file inspected, 1 offense detected

This is version 0.4.4.

PS/ Where is the rendered documentation? I meant, there is https://docs.rubocop.org/rubocop-rails/cops_rails.html for instance, but I could not find anything comparable for Thread Safety.

Support detecting offenders in `ActiveSupport::Concern#class_methods` blocks

This is a recreation of covermymeds/issues/41 opened by @DanielGilchrist on Jul 14, 2021.


Just recently upgraded to v0.4.2 and I noticed that currently the cop doesn't pick up offenders in class_methods do...end blocks

Cases using module ClassMethods works great

module Personable
  extend ActiveSupport::Concern

  module ClassMethods
    def age
      @age ||= 33 # ThreadSafety/InstanceVariableInClassMethod error will occur here appropriately
    end
  end
end

Rails also allows us to use class_methods to achieve the same thing

module Personable
  extend ActiveSupport::Concern

  class_methods do
    def age
      @age ||= 33 # ThreadSafety/InstanceVariableInClassMethod won't detect this
    end
  end
end

It'd be awesome if we could detect cases inside class_methods blocks as well 🀩

https://api.rubyonrails.org/v6.1.3.2/classes/ActiveSupport/Concern.html#method-i-class_methods

Description/Reasoning for the current rules being enforced by default

It's not clear what the danger is for some of the rules being enforced and/or what actually is being enforced

Screenshot 2023-07-20 at 3 35 12 PM

for instance, why is plain thread.new not safe, but thread.new with an injected value "safe", there's no guarantee that's the only variable being accessed, and there are legitimate use cases for creating your own threads outside of your queuing system

can an explanation of the dangers being prevented be added somewhere? rubocop core has explanations of the reasoning behind all, or at least a lot of, their rules, like this: https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/StderrPuts

I would offer to make a PR, but i don't (yet) understand the reasoning behind items like "no ivar in class methods"; it's usually used as an inheritance method since subclasses don't inherit that value. they're set to a constant when they're accessed and then it's just there for the life of the thread. maybe I'm wrong but I don't see what thread issues would exist for class instance variables that wouldn't also exist for class variables

I'd love to understand further what situations the rules are preventing when there is only a reader for cases like that (or maybe it's just not possible to scan for when a writer is added?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.