Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ForbidIncludeConstLiteral #153

Merged
merged 1 commit into from
Oct 13, 2023

Conversation

sambostock
Copy link
Contributor

This makes the following changes:

  • Migrates from deprecated Cop parent class to Base
  • Improves the offense message
  • Removes the unused used_names accessor and initialization
  • Renames and alters the node matcher to describe what it matches, not what it doesn't
  • Extracts named helpers to clarify the code's logic
  • Leverages the expect_correction test helpers and replaces the autocorrection specific tests.

@sambostock sambostock requested a review from a team as a code owner February 21, 2023 15:55
return unless within_onymous_module?(node)

add_offense(node, message: format(MSG, inclusion_method: inclusion_method)) do |corrector|
explicit_receiver = receiver&.source || 'self'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a bug-fix so I think we have no test cases for the explicit receiver not being self. Can we add one or two cases for that as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

I did some digging, and it looks like Sorbet doesn't handle include with an explicit receiver.

# typed: strict

module M
  extend T::Sig
  sig { void }
  def m; end
end

class C1
  include M
end

C1.new.m

class C2; end
C2.include M

C2.new.m
#      ^ Method m does not exist on C2

That said, it seems like a reasonable thing that might end up supported eventually (I'm not sure why it isn't already, if the receiver is a constant).

So I could:

  • Simplify the code, by only looking for include, extend, & prepend with implicit receivers, or
  • Keep the cop "smarter than (current) Sorbet", and add tests.

What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! I would go for keeping the refactored implementation and add tests for those cases. After all, dynamic or not, those includes are not going to work with Sorbet either way. We could at least push people to use less dynamic mixins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added tests, although I should note that they look like

module M
  M.include(dynamic)
end

which this implementation detects, not

M.include(dynamic)

which this implementation does not detect. Do we want to do that? I'm unsure about false positives.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think my implementation introduces a false positive bug. Neither of these should be flagged, because we can't be sure they're operating on a module.

Config = []
Config.prepend(1)

class MyClass
  Config.prepend(2)
end

I think that is why in my example above Sorbet doesn't handle C2.include M. 🤔

I'm going to add test cases for this (and the equivalent include and extend cases) and make them pass.

@sambostock sambostock force-pushed the refactor-forbid-include-const-literal branch from 7a57aa3 to 240a904 Compare February 21, 2023 21:47
@github-actions
Copy link

This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale label Mar 24, 2023
@github-actions github-actions bot closed this Mar 31, 2023
@sambostock sambostock reopened this Oct 12, 2023
@sambostock sambostock force-pushed the refactor-forbid-include-const-literal branch from 240a904 to e3d676f Compare October 12, 2023 19:38
@sambostock sambostock force-pushed the refactor-forbid-include-const-literal branch from e3d676f to 09a959c Compare October 12, 2023 19:47
@sambostock sambostock force-pushed the refactor-forbid-include-const-literal branch 2 times, most recently from 4e38682 to 9083997 Compare October 12, 2023 20:12
@sambostock sambostock removed the stale label Oct 12, 2023
Comment on lines +177 to +213
it "adds no offense when an explicit constant receiver includes a send node" do
expect_no_offenses(<<~RUBY)
module MyModule
MyModule.include Rails.application.routes.url_helpers
end
RUBY
end

it "adds no offense when an explicit constant receiver extends a send node" do
expect_no_offenses(<<~RUBY)
module MyModule
MyModule.extend Rails.application.routes.url_helpers
end
RUBY
end

it "adds no offense when an explicit constant receiver prepends a send node" do
expect_no_offenses(<<~RUBY)
module MyModule
MyModule.prepend Rails.application.routes.url_helpers
end
RUBY
end

it "does not add offense when prepend used with array" do
expect_no_offenses(<<~RUBY)
Config = []
Config.prepend(one)

module MyModule
Config.prepend(two)
end

class MyClass
Config.prepend(three)
end
RUBY
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paracycle I've added these tests as per #153 (comment) to cover the edge cases you pointed out, and adjusted the implementation accordingly.

This makes the following changes:

- Migrates from deprecated `Cop` parent class to `Base`
- Improves the offense message
- Removes the unused `used_names` accessor and initialization
- Renames and alters the node matcher to describe what it matches, not
  what it doesn't
- Extracts named helpers to clarify the code's logic
- Leverages the `expect_correction` test helpers and replaces the
  autocorrection specific tests.
@sambostock sambostock force-pushed the refactor-forbid-include-const-literal branch from 9083997 to 876e1c4 Compare October 13, 2023 16:02
@sambostock sambostock merged commit e8a047d into main Oct 13, 2023
10 checks passed
@sambostock sambostock deleted the refactor-forbid-include-const-literal branch October 13, 2023 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants