Repository: Shopify/ruby-lsp (Ruby)

Issue:
No RuboCop autocorrect lens if autocorrect is contextual
### Description

This method returns `:unsupported`: https://github.com/rubocop/rubocop/blob/967fe88135188c9d74494cbd4355180c140c4a1a/lib/rubocop/cop/base.rb#L424-L432

In line 427:
* A `corrector` is present
* `always_autocorrect?` is false
* `contextual_autocorrect?` is true
* `LSP.enabled?` is true

So, no autocorrect lense for you.

The following snippet reproduces:

```rb
1.times do
  do_something(t)
end
```

You can only disable this, even though autocorrect is possible:
![grafik](https://github.com/Shopify/ruby-lsp/assets/14981592/8c48b304-82a9-43a1-a562-afcbbc6a4076)

I haven't yet thought about how to fix this. Maybe it is enough to somehow disable LSP mode for the `diagnostic_runner` only, though I believe that state is global so maybe not that easy


Discussion:
Ah, I see this was brought up in the PR to enable the LSP mode. https://github.com/Shopify/ruby-lsp/pull/1453#issuecomment-1979585290



Patch:
diff --git a/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb b/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
index f5a81de270..3a9c7026e3 100644
--- a/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
+++ b/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
@@ -42,7 +42,7 @@ def initialize(document, offense, uri)
         def to_lsp_code_actions
           code_actions = []
 
-          code_actions << autocorrect_action if @offense.correctable?
+          code_actions << autocorrect_action if correctable?
           code_actions << disable_line_action
 
           code_actions
@@ -70,7 +70,7 @@ def to_lsp_diagnostic(config)
               ),
             ),
             data: {
-              correctable: @offense.correctable?,
+              correctable: correctable?,
               code_actions: to_lsp_code_actions,
             },
           )
@@ -81,7 +81,7 @@ def to_lsp_diagnostic(config)
         sig { returns(String) }
         def message
           message  = @offense.message
-          message += "\n\nThis offense is not auto-correctable.\n" unless @offense.correctable?
+          message += "\n\nThis offense is not auto-correctable.\n" unless correctable?
           message
         end
 
@@ -115,7 +115,7 @@ def autocorrect_action
                     uri: @uri.to_s,
                     version: nil,
                   ),
-                  edits: @offense.correctable? ? offense_replacements : [],
+                  edits: correctable? ? offense_replacements : [],
                 ),
               ],
             ),
@@ -193,6 +193,14 @@ def length_of_line(line)
             line.length
           end
         end
+
+        # When `RuboCop::LSP.enable` is called, contextual autocorrect will not offer itself
+        # as `correctable?` to prevent annoying changes while typing. Instead check if
+        # a corrector is present. If it is, then that means some code transformation can be applied.
+        sig { returns(T::Boolean) }
+        def correctable?
+          !@offense.corrector.nil?
+        end
       end
     end
   end


Test patch:
diff --git a/test/expectations/diagnostics/rubocop_contextual_autocorrect.exp.json b/test/expectations/diagnostics/rubocop_contextual_autocorrect.exp.json
new file mode 100644
index 0000000000..0d85158f84
--- /dev/null
+++ b/test/expectations/diagnostics/rubocop_contextual_autocorrect.exp.json
@@ -0,0 +1,102 @@
+{
+  "result": [
+    {
+      "range": {
+        "start": {
+          "line": 4,
+          "character": 2
+        },
+        "end": {
+          "line": 4,
+          "character": 5
+        }
+      },
+      "severity": 2,
+      "source": "Prism",
+      "message": "assigned but unused variable - foo"
+    },
+    {
+      "range": {
+        "start": {
+          "line": 4,
+          "character": 2
+        },
+        "end": {
+          "line": 4,
+          "character": 5
+        }
+      },
+      "severity": 2,
+      "code": "Lint/UselessAssignment",
+      "codeDescription": {
+        "href": "https://docs.rubocop.org/rubocop/cops_lint.html#lintuselessassignment"
+      },
+      "source": "RuboCop",
+      "message": "Lint/UselessAssignment: Useless assignment to variable - `foo`.",
+      "data": {
+        "correctable": true,
+        "code_actions": [
+          {
+            "title": "Autocorrect Lint/UselessAssignment",
+            "kind": "quickfix",
+            "isPreferred": true,
+            "edit": {
+              "documentChanges": [
+                {
+                  "textDocument": {
+                    "uri": "file:///fake",
+                    "version": null
+                  },
+                  "edits": [
+                    {
+                      "range": {
+                        "start": {
+                          "line": 4,
+                          "character": 2
+                        },
+                        "end": {
+                          "line": 4,
+                          "character": 13
+                        }
+                      },
+                      "newText": "\"bar\""
+                    }
+                  ]
+                }
+              ]
+            }
+          },
+          {
+            "title": "Disable Lint/UselessAssignment for this line",
+            "kind": "quickfix",
+            "edit": {
+              "documentChanges": [
+                {
+                  "textDocument": {
+                    "uri": "file:///fake",
+                    "version": null
+                  },
+                  "edits": [
+                    {
+                      "range": {
+                        "start": {
+                          "line": 4,
+                          "character": 13
+                        },
+                        "end": {
+                          "line": 4,
+                          "character": 13
+                        }
+                      },
+                      "newText": " # rubocop:disable Lint/UselessAssignment"
+                    }
+                  ]
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/test/fixtures/rubocop_contextual_autocorrect.rb b/test/fixtures/rubocop_contextual_autocorrect.rb
new file mode 100644
index 0000000000..8fe67de804
--- /dev/null
+++ b/test/fixtures/rubocop_contextual_autocorrect.rb
@@ -0,0 +1,7 @@
+# typed: strict
+# frozen_string_literal: true
+
+def useless_assignment
+  foo = "bar"
+  baz
+end