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

fix(analyze & lsp): code action and text mutation #2237

Merged
merged 9 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ our [guidelines for writing a good changelog entry](https:/biomejs/b

### Editors

#### Bug fixes

- Fix the unexpected code deletion and repetition when `quickfix.biome` is enabled and some `import`-related rules are applied ([#2222](https:/biomejs/biome/issues/2222), [#688](https:/biomejs/biome/issues/688), [#1015](https:/biomejs/biome/issues/1015)). Contributed by @Sec-ant

### Formatter

### JavaScript APIs
Expand Down
4 changes: 2 additions & 2 deletions crates/biome_analyze/src/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl<L: Language> Default for AnalyzerActionIter<L> {

impl<L: Language> From<AnalyzerAction<L>> for CodeSuggestionAdvice<MarkupBuf> {
fn from(action: AnalyzerAction<L>) -> Self {
let (_, suggestion) = action.mutation.as_text_edits().unwrap_or_default();
let (_, suggestion) = action.mutation.as_text_range_and_edit().unwrap_or_default();
CodeSuggestionAdvice {
applicability: action.applicability,
msg: action.message,
Expand All @@ -145,7 +145,7 @@ impl<L: Language> From<AnalyzerAction<L>> for CodeSuggestionAdvice<MarkupBuf> {

impl<L: Language> From<AnalyzerAction<L>> for CodeSuggestionItem {
fn from(action: AnalyzerAction<L>) -> Self {
let (range, suggestion) = action.mutation.as_text_edits().unwrap_or_default();
let (range, suggestion) = action.mutation.as_text_range_and_edit().unwrap_or_default();

CodeSuggestionItem {
rule_name: action.rule_name,
Expand Down
6 changes: 4 additions & 2 deletions crates/biome_cli/src/execute/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ pub(crate) fn run(migrate_payload: MigratePayload) -> Result<(), CliDiagnostic>

match action {
Some(action) => {
if let Some((range, _)) = action.mutation.as_text_edits() {
tree = match JsonRoot::cast(action.mutation.commit()) {
if let (root, Some((range, _))) =
action.mutation.commit_with_text_range_and_edit(true)
{
tree = match JsonRoot::cast(root) {
Some(tree) => tree,
None => return Err(CliDiagnostic::check_error(category!("migrate"))),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ file.astro:2:1 lint/suspicious/noDebugger FIXABLE ━━━━━━━━━

i Unsafe fix: Remove debugger statement

1 1 │
1 │ -
2 │ - debugger;
1 │ +
3 2 │


Expand All @@ -46,5 +47,3 @@ file.astro:2:1 lint/suspicious/noDebugger FIXABLE ━━━━━━━━━
Checked 1 file in <TIME>. No fixes needed.
Found 2 errors.
```


Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ file.vue:4:8 lint/style/noInferrableTypes FIXABLE ━━━━━━━━━

i Safe fix: Remove the type annotation.

4 │ var·foo:·string·=·"";
│ --------
2 2 │ delete a.c;
3 3 │
4 │ - var·foo:·string·=·"";
4 │ + var·foo·=·"";
5 5 │

Sec-ant marked this conversation as resolved.
Show resolved Hide resolved

```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ file.js:1:1 suppressions/deprecatedSuppressionComment FIXABLE DEPRECATED ━
i Unsafe fix: Use // biome-ignore instead

1 │ - //·rome-ignore·lint(suspicious/noDoubleEquals):·test
2 │ - a·
1 │ + //·biome-ignore·lint(suspicious/noDoubleEquals):·test
2 │ + a·==·b;
2 2 │ a == b;


```
Expand Down Expand Up @@ -65,9 +64,8 @@ file.js:1:1 suppressions/deprecatedSuppressionComment FIXABLE DEPRECATED ━
i Unsafe fix: Use // biome-ignore instead

1 │ - //·rome-ignore·lint(suspicious/noDoubleEquals):·test
2 │ - a·
1 │ + //·biome-ignore·lint(suspicious/noDoubleEquals):·test
2 │ + a·==·b;
2 2 │ a == b;


```
Expand All @@ -89,5 +87,3 @@ file.js format ━━━━━━━━━━━━━━━━━━━━━
Checked 1 file in <TIME>. No fixes needed.
Found 3 errors.
```


Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,12 @@ file.js:1:1 suppressions/deprecatedSuppressionComment FIXABLE DEPRECATED ━
i Unsafe fix: Use // biome-ignore instead

1 │ - //·rome-ignore·lint(suspicious/noDoubleEquals):·test
2 │ - a·
1 │ + //·biome-ignore·lint(suspicious/noDoubleEquals):·test
2 │ + a·==·b;
2 2 │ a == b;


```

```block
Checked 1 file in <TIME>. No fixes needed.
```


11 changes: 8 additions & 3 deletions crates/biome_css_analyze/tests/spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,17 @@ fn check_code_action(
action: &AnalyzerAction<CssLanguage>,
options: CssParserOptions,
) {
let (_, text_edit) = action.mutation.as_text_edits().unwrap_or_default();
let (new_tree, text_edit) = match action
.mutation
.clone()
.commit_with_text_range_and_edit(true)
{
(new_tree, Some((_, text_edit))) => (new_tree, text_edit),
(new_tree, None) => (new_tree, Default::default()),
};

let output = text_edit.new_string(source);

let new_tree = action.mutation.clone().commit();

// Checks that applying the text edits returned by the BatchMutation
// returns the same code as printing the modified syntax tree
assert_eq!(new_tree.to_string(), output);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{services::semantic::Semantic, utils::batch::JsBatchMutation, JsRuleAction};
use crate::{services::semantic::Semantic, JsRuleAction};
use biome_analyze::{
context::RuleContext, declare_rule, ActionCategory, FixKind, Rule, RuleDiagnostic,
};
Expand All @@ -19,6 +19,10 @@ declare_rule! {
/// The code fix can remove comments associated with an `import`.
/// See the last invalid example.
///
/// Note that the leading trivia, e.g., comments or newlines preceding
/// the unused imports will also be removed. So that comment directives
/// like `@ts-expect-error` won't be transferred to a wrong place.
///
/// ## Examples
///
/// ### Invalid
Expand Down Expand Up @@ -205,7 +209,8 @@ fn remove_import_specifier(
| AnyJsImportClause::JsImportNamespaceClause(_) => {
// Remove the entire statement
let import = clause.parent::<JsImport>()?;
mutation.transfer_leading_trivia_to_sibling(import.syntax());
// This will also remove the trivia of the node
// which is intended
mutation.remove_node(import);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{utils::batch::JsBatchMutation, JsRuleAction};
use crate::JsRuleAction;
use biome_analyze::{
context::RuleContext, declare_rule, ActionCategory, Ast, FixKind, Rule, RuleDiagnostic,
};
Expand All @@ -13,6 +13,10 @@ use biome_rowan::{declare_node_union, AstNode, BatchMutationExt};
declare_rule! {
/// Prevents from having redundant `"use strict"`.
///
/// Note that the leading trivia, e.g., comments or newlines preceding
/// the redundant `"use strict"` will also be removed. So that comment
/// directives won't be transferred to a wrong place.
///
/// ## Examples
///
/// ### Invalid
Expand Down Expand Up @@ -157,7 +161,8 @@ impl Rule for NoRedundantUseStrict {
fn action(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<JsRuleAction> {
let node = ctx.query();
let mut mutation = ctx.root().begin();
mutation.transfer_leading_trivia_to_sibling(node.syntax());
// This will also remove the trivia of the node
// which is intended
mutation.remove_node(node.clone());
Some(JsRuleAction {
category: ActionCategory::QuickFix,
Expand Down
11 changes: 8 additions & 3 deletions crates/biome_js_analyze/tests/spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,17 @@ fn check_code_action(
action: &AnalyzerAction<JsLanguage>,
options: JsParserOptions,
) {
let (_, text_edit) = action.mutation.as_text_edits().unwrap_or_default();
let (new_tree, text_edit) = match action
.mutation
.clone()
.commit_with_text_range_and_edit(true)
{
(new_tree, Some((_, text_edit))) => (new_tree, text_edit),
(new_tree, None) => (new_tree, Default::default()),
};

let output = text_edit.new_string(source);

let new_tree = action.mutation.clone().commit();

// Checks that applying the text edits returned by the BatchMutation
// returns the same code as printing the modified syntax tree
assert_eq!(new_tree.to_string(), output);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ invalid.jsx:5:9 lint/a11y/useValidAriaProps FIXABLE ━━━━━━━━
Check the list of all valid aria-* attributes.

5 │ var·a·=·<div·aria-skldjfaria-foo1="foobar"·aria-skldjfaria-foo222="foobar"·/>;
------------------------------
│ ------------------------------

```

Expand Down Expand Up @@ -176,5 +176,3 @@ invalid.jsx:5:9 lint/a11y/useValidAriaProps FIXABLE ━━━━━━━━
│ --------------------------------

```


Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,9 @@ invalid.jsonc:1:27 lint/complexity/noUselessLabel FIXABLE ━━━━━━
i Safe fix: Remove the unnecessary label.
You can achieve the same result without the label.

1 │ A:·while(true)·{·continue·A/*after*/;·}
│ --
- A:·while(true)·{·continue·A/*after*/;·}
+ A:·while(true)·{·continue/*after*/;·}
Sec-ant marked this conversation as resolved.
Show resolved Hide resolved


```

Expand All @@ -395,8 +396,10 @@ invalid.jsonc:1:24 lint/complexity/noUselessLabel FIXABLE ━━━━━━
i Safe fix: Remove the unnecessary label.
You can achieve the same result without the label.

1 │ A:·while(true)·{·break·A·//after
│ --
1 │ - A:·while(true)·{·break·A·//after
1 │ + A:·while(true)·{·break·//after
2 2 │ }


```

Expand All @@ -419,8 +422,10 @@ invalid.jsonc:1:24 lint/complexity/noUselessLabel FIXABLE ━━━━━━
i Safe fix: Remove the unnecessary label.
You can achieve the same result without the label.

1 │ A:·while(true)·{·break·A·/*after*/
│ --
1 │ - A:·while(true)·{·break·A·/*after*/
1 │ + A:·while(true)·{·break·/*after*/
2 2 │ foo() }


```

Expand Down Expand Up @@ -467,5 +472,3 @@ invalid.jsonc:1:58 lint/complexity/noUselessLabel FIXABLE ━━━━━━
│ --

```


Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,12 @@ invalid.js:24:21 lint/complexity/noUselessRename FIXABLE ━━━━━━━

i Safe fix: Remove the renaming.

24 │ export·{·/*before*/·foo·as·foo·/*after*/·}·from·"foo";
│ -------
22 22 │ export { /*before*/ foo as foo /*after*/ };
23 23 │
24 │ - export·{·/*before*/·foo·as·foo·/*after*/·}·from·"foo";
24 │ + export·{·/*before*/·foo·/*after*/·}·from·"foo";
25 25 │
26 26 │ // following cases are supported by ESLint


```


Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ invalid.js:2:2 lint/complexity/noUselessSwitchCase FIXABLE ━━━━━━

1 1 │ switch (foo) {
2 │ - → case·0:
3 │ - → default:
2 │ + → default:
3 2 │ default:
4 3 │ break;
5 4 │ case 3:


```
Expand Down Expand Up @@ -84,10 +82,8 @@ invalid.js:10:14 lint/complexity/noUselessSwitchCase FIXABLE ━━━━━
8 8 │
9 9 │ switch (foo) {
10 │ - → /*·before·*/case·0:/*·after·*/
11 │ - → //·comment·for·default
10 │ + → //·comment·for·default
11 10 │ // comment for default
12 11 │ default:
13 12 │ case 1:


```
Expand Down Expand Up @@ -118,10 +114,8 @@ invalid.js:13:2 lint/complexity/noUselessSwitchCase FIXABLE ━━━━━━
11 11 │ // comment for default
12 12 │ default:
13 │ - → case·1:
14 │ - → case·2:/*·statements·*/
13 │ + → case·2:/*·statements·*/
14 13 │ case 2:/* statements */
15 14 │ break;
16 15 │ case 3:


```
Expand Down Expand Up @@ -155,14 +149,11 @@ invalid.js:14:2 lint/complexity/noUselessSwitchCase FIXABLE ━━━━━━
10 10 │ /* before */case 0:/* after */
11 │ - → //·comment·for·default
12 │ - → default:
13 │ - → case·1:
13 11 │ case 1:
14 │ - → case·2:/*·statements·*/
11 │ + → case·1:
12 │ + → default:/*·statements·*/
15 13 │ break;
16 14 │ case 3:


```


Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,8 @@ invalid.js:5:11 lint/complexity/noUselessThisAlias FIXABLE ━━━━━━
3 3 │ function f() {
4 │ - ····//·assignment·comment
5 │ - ····const·self·=·this;
6 │ - ····return·()·=>·{
6 4 │ return () => {
7 │ - ········/*a*/self/*b*/.g();
4 │ + ····return·()·=>·{
5 │ + ········/*a*/this/*b*/.g();
8 6 │ }
9 7 │ }
Expand All @@ -147,9 +146,8 @@ invalid.js:12:9 lint/complexity/noUselessThisAlias FIXABLE ━━━━━━
10 10 │
11 11 │ function f() {
12 │ - ····let·self·=·this;
13 │ - ····return·()·=>·{
13 12 │ return () => {
14 │ - ········self.g();
12 │ + ····return·()·=>·{
13 │ + ········this.g();
15 14 │ }
16 15 │ }
Expand Down Expand Up @@ -177,9 +175,8 @@ invalid.js:19:9 lint/complexity/noUselessThisAlias FIXABLE ━━━━━━
19 │ - ····var·self;
20 │ - ····self·=·this;
21 │ - ····self·=·this;
22 │ - ····return·()·=>·{
22 19 │ return () => {
23 │ - ········self.g();
19 │ + ····return·()·=>·{
20 │ + ········this.g();
24 21 │ }
25 22 │ }
Expand Down Expand Up @@ -227,5 +224,3 @@ invalid.js:32:13 lint/complexity/noUselessThisAlias FIXABLE ━━━━━━


```


Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,7 @@ invalid.jsonc:1:26 lint/correctness/noNewSymbol FIXABLE ━━━━━━━

i Unsafe fix: Remove new.

- var·s·=·/*·prefix_cmt·*/·new·/*·suffix_cmt·*/·Symbol()·//·comment
+ var·s·=·/*·prefix_cmt·*/··/*·suffix_cmt·*/·Symbol()·//·comment

1 │ var·s·=·/*·prefix_cmt·*/·new·/*·suffix_cmt·*/·Symbol()·//·comment
│ ---

```


Loading
Loading