mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Remove cargo watch supporting code and tests from vscode extension
This commit is contained in:
parent
c21fbc3e87
commit
500fe46e6c
14 changed files with 0 additions and 1684 deletions
|
@ -1,110 +0,0 @@
|
|||
{
|
||||
"message": "this argument is passed by reference, but would be more efficient if passed by value",
|
||||
"code": {
|
||||
"code": "clippy::trivially_copy_pass_by_ref",
|
||||
"explanation": null
|
||||
},
|
||||
"level": "warning",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "compiler/mir/tagset.rs",
|
||||
"byte_start": 941,
|
||||
"byte_end": 946,
|
||||
"line_start": 42,
|
||||
"line_end": 42,
|
||||
"column_start": 24,
|
||||
"column_end": 29,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " pub fn is_disjoint(&self, other: Self) -> bool {",
|
||||
"highlight_start": 24,
|
||||
"highlight_end": 29
|
||||
}
|
||||
],
|
||||
"label": null,
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"message": "lint level defined here",
|
||||
"code": null,
|
||||
"level": "note",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "compiler/lib.rs",
|
||||
"byte_start": 8,
|
||||
"byte_end": 19,
|
||||
"line_start": 1,
|
||||
"line_end": 1,
|
||||
"column_start": 9,
|
||||
"column_end": 20,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": "#![warn(clippy::all)]",
|
||||
"highlight_start": 9,
|
||||
"highlight_end": 20
|
||||
}
|
||||
],
|
||||
"label": null,
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
},
|
||||
{
|
||||
"message": "#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]",
|
||||
"code": null,
|
||||
"level": "note",
|
||||
"spans": [],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
},
|
||||
{
|
||||
"message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref",
|
||||
"code": null,
|
||||
"level": "help",
|
||||
"spans": [],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
},
|
||||
{
|
||||
"message": "consider passing by value instead",
|
||||
"code": null,
|
||||
"level": "help",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "compiler/mir/tagset.rs",
|
||||
"byte_start": 941,
|
||||
"byte_end": 946,
|
||||
"line_start": 42,
|
||||
"line_end": 42,
|
||||
"column_start": 24,
|
||||
"column_end": 29,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " pub fn is_disjoint(&self, other: Self) -> bool {",
|
||||
"highlight_start": 24,
|
||||
"highlight_end": 29
|
||||
}
|
||||
],
|
||||
"label": null,
|
||||
"suggested_replacement": "self",
|
||||
"suggestion_applicability": "Unspecified",
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
}
|
||||
],
|
||||
"rendered": "warning: this argument is passed by reference, but would be more efficient if passed by value\n --> compiler/mir/tagset.rs:42:24\n |\n42 | pub fn is_disjoint(&self, other: Self) -> bool {\n | ^^^^^ help: consider passing by value instead: `self`\n |\nnote: lint level defined here\n --> compiler/lib.rs:1:9\n |\n1 | #![warn(clippy::all)]\n | ^^^^^^^^^^^\n = note: #[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref\n\n"
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
"message": "method `next` has an incompatible type for trait",
|
||||
"code": {
|
||||
"code": "E0053",
|
||||
"explanation": "\nThe parameters of any trait method must match between a trait implementation\nand the trait definition.\n\nHere are a couple examples of this error:\n\n```compile_fail,E0053\ntrait Foo {\n fn foo(x: u16);\n fn bar(&self);\n}\n\nstruct Bar;\n\nimpl Foo for Bar {\n // error, expected u16, found i16\n fn foo(x: i16) { }\n\n // error, types differ in mutability\n fn bar(&mut self) { }\n}\n```\n"
|
||||
},
|
||||
"level": "error",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "compiler/ty/list_iter.rs",
|
||||
"byte_start": 1307,
|
||||
"byte_end": 1350,
|
||||
"line_start": 52,
|
||||
"line_end": 52,
|
||||
"column_start": 5,
|
||||
"column_end": 48,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " fn next(&self) -> Option<&'list ty::Ref<M>> {",
|
||||
"highlight_start": 5,
|
||||
"highlight_end": 48
|
||||
}
|
||||
],
|
||||
"label": "types differ in mutability",
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"message": "expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`",
|
||||
"code": null,
|
||||
"level": "note",
|
||||
"spans": [],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
}
|
||||
],
|
||||
"rendered": "error[E0053]: method `next` has an incompatible type for trait\n --> compiler/ty/list_iter.rs:52:5\n |\n52 | fn next(&self) -> Option<&'list ty::Ref<M>> {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability\n |\n = note: expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`\n\n"
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
{
|
||||
"message": "this function takes 2 parameters but 3 parameters were supplied",
|
||||
"code": {
|
||||
"code": "E0061",
|
||||
"explanation": "\nThe number of arguments passed to a function must match the number of arguments\nspecified in the function signature.\n\nFor example, a function like:\n\n```\nfn f(a: u16, b: &str) {}\n```\n\nMust always be called with exactly two arguments, e.g., `f(2, \"test\")`.\n\nNote that Rust does not have a notion of optional function arguments or\nvariadic functions (except for its C-FFI).\n"
|
||||
},
|
||||
"level": "error",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "compiler/ty/select.rs",
|
||||
"byte_start": 8787,
|
||||
"byte_end": 9241,
|
||||
"line_start": 219,
|
||||
"line_end": 231,
|
||||
"column_start": 5,
|
||||
"column_end": 6,
|
||||
"is_primary": false,
|
||||
"text": [
|
||||
{
|
||||
"text": " pub fn add_evidence(",
|
||||
"highlight_start": 5,
|
||||
"highlight_end": 25
|
||||
},
|
||||
{
|
||||
"text": " &mut self,",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 19
|
||||
},
|
||||
{
|
||||
"text": " target_poly: &ty::Ref<ty::Poly>,",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 41
|
||||
},
|
||||
{
|
||||
"text": " evidence_poly: &ty::Ref<ty::Poly>,",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 43
|
||||
},
|
||||
{
|
||||
"text": " ) {",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 8
|
||||
},
|
||||
{
|
||||
"text": " match target_poly {",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 28
|
||||
},
|
||||
{
|
||||
"text": " ty::Ref::Var(tvar, _) => self.add_var_evidence(tvar, evidence_poly),",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 81
|
||||
},
|
||||
{
|
||||
"text": " ty::Ref::Fixed(target_ty) => {",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 43
|
||||
},
|
||||
{
|
||||
"text": " let evidence_ty = evidence_poly.resolve_to_ty();",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 65
|
||||
},
|
||||
{
|
||||
"text": " self.add_evidence_ty(target_ty, evidence_poly, evidence_ty)",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 76
|
||||
},
|
||||
{
|
||||
"text": " }",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 14
|
||||
},
|
||||
{
|
||||
"text": " }",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 10
|
||||
},
|
||||
{
|
||||
"text": " }",
|
||||
"highlight_start": 1,
|
||||
"highlight_end": 6
|
||||
}
|
||||
],
|
||||
"label": "defined here",
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
},
|
||||
{
|
||||
"file_name": "compiler/ty/select.rs",
|
||||
"byte_start": 4045,
|
||||
"byte_end": 4057,
|
||||
"line_start": 104,
|
||||
"line_end": 104,
|
||||
"column_start": 18,
|
||||
"column_end": 30,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " self.add_evidence(target_fixed, evidence_fixed, false);",
|
||||
"highlight_start": 18,
|
||||
"highlight_end": 30
|
||||
}
|
||||
],
|
||||
"label": "expected 2 parameters",
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"rendered": "error[E0061]: this function takes 2 parameters but 3 parameters were supplied\n --> compiler/ty/select.rs:104:18\n |\n104 | self.add_evidence(target_fixed, evidence_fixed, false);\n | ^^^^^^^^^^^^ expected 2 parameters\n...\n219 | / pub fn add_evidence(\n220 | | &mut self,\n221 | | target_poly: &ty::Ref<ty::Poly>,\n222 | | evidence_poly: &ty::Ref<ty::Poly>,\n... |\n230 | | }\n231 | | }\n | |_____- defined here\n\n"
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
{
|
||||
"rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n",
|
||||
"children": [
|
||||
{
|
||||
"children": [],
|
||||
"code": null,
|
||||
"level": "help",
|
||||
"message": "the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
|
||||
"rendered": null,
|
||||
"spans": []
|
||||
}
|
||||
],
|
||||
"code": {
|
||||
"code": "E0277",
|
||||
"explanation": "\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail,E0277\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func<T: Foo>(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func<T: Foo>(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n\n```compile_fail,E0277\nfn some_func<T>(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func<T: fmt::Debug>(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n```\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n"
|
||||
},
|
||||
"level": "error",
|
||||
"message": "can't compare `{integer}` with `&str`",
|
||||
"spans": [
|
||||
{
|
||||
"byte_end": 155,
|
||||
"byte_start": 153,
|
||||
"column_end": 33,
|
||||
"column_start": 31,
|
||||
"expansion": {
|
||||
"def_site_span": {
|
||||
"byte_end": 940,
|
||||
"byte_start": 0,
|
||||
"column_end": 6,
|
||||
"column_start": 1,
|
||||
"expansion": null,
|
||||
"file_name": "<::core::macros::assert_eq macros>",
|
||||
"is_primary": false,
|
||||
"label": null,
|
||||
"line_end": 36,
|
||||
"line_start": 1,
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"text": [
|
||||
{
|
||||
"highlight_end": 35,
|
||||
"highlight_start": 1,
|
||||
"text": "($ left : expr, $ right : expr) =>"
|
||||
},
|
||||
{
|
||||
"highlight_end": 3,
|
||||
"highlight_start": 1,
|
||||
"text": "({"
|
||||
},
|
||||
{
|
||||
"highlight_end": 33,
|
||||
"highlight_start": 1,
|
||||
"text": " match (& $ left, & $ right)"
|
||||
},
|
||||
{
|
||||
"highlight_end": 7,
|
||||
"highlight_start": 1,
|
||||
"text": " {"
|
||||
},
|
||||
{
|
||||
"highlight_end": 34,
|
||||
"highlight_start": 1,
|
||||
"text": " (left_val, right_val) =>"
|
||||
},
|
||||
{
|
||||
"highlight_end": 11,
|
||||
"highlight_start": 1,
|
||||
"text": " {"
|
||||
},
|
||||
{
|
||||
"highlight_end": 46,
|
||||
"highlight_start": 1,
|
||||
"text": " if ! (* left_val == * right_val)"
|
||||
},
|
||||
{
|
||||
"highlight_end": 15,
|
||||
"highlight_start": 1,
|
||||
"text": " {"
|
||||
},
|
||||
{
|
||||
"highlight_end": 25,
|
||||
"highlight_start": 1,
|
||||
"text": " panic !"
|
||||
},
|
||||
{
|
||||
"highlight_end": 57,
|
||||
"highlight_start": 1,
|
||||
"text": " (r#\"assertion failed: `(left == right)`"
|
||||
},
|
||||
{
|
||||
"highlight_end": 16,
|
||||
"highlight_start": 1,
|
||||
"text": " left: `{:?}`,"
|
||||
},
|
||||
{
|
||||
"highlight_end": 18,
|
||||
"highlight_start": 1,
|
||||
"text": " right: `{:?}`\"#,"
|
||||
},
|
||||
{
|
||||
"highlight_end": 47,
|
||||
"highlight_start": 1,
|
||||
"text": " & * left_val, & * right_val)"
|
||||
},
|
||||
{
|
||||
"highlight_end": 15,
|
||||
"highlight_start": 1,
|
||||
"text": " }"
|
||||
},
|
||||
{
|
||||
"highlight_end": 11,
|
||||
"highlight_start": 1,
|
||||
"text": " }"
|
||||
},
|
||||
{
|
||||
"highlight_end": 7,
|
||||
"highlight_start": 1,
|
||||
"text": " }"
|
||||
},
|
||||
{
|
||||
"highlight_end": 42,
|
||||
"highlight_start": 1,
|
||||
"text": " }) ; ($ left : expr, $ right : expr,) =>"
|
||||
},
|
||||
{
|
||||
"highlight_end": 49,
|
||||
"highlight_start": 1,
|
||||
"text": "({ $ crate :: assert_eq ! ($ left, $ right) }) ;"
|
||||
},
|
||||
{
|
||||
"highlight_end": 53,
|
||||
"highlight_start": 1,
|
||||
"text": "($ left : expr, $ right : expr, $ ($ arg : tt) +) =>"
|
||||
},
|
||||
{
|
||||
"highlight_end": 3,
|
||||
"highlight_start": 1,
|
||||
"text": "({"
|
||||
},
|
||||
{
|
||||
"highlight_end": 37,
|
||||
"highlight_start": 1,
|
||||
"text": " match (& ($ left), & ($ right))"
|
||||
},
|
||||
{
|
||||
"highlight_end": 7,
|
||||
"highlight_start": 1,
|
||||
"text": " {"
|
||||
},
|
||||
{
|
||||
"highlight_end": 34,
|
||||
"highlight_start": 1,
|
||||
"text": " (left_val, right_val) =>"
|
||||
},
|
||||
{
|
||||
"highlight_end": 11,
|
||||
"highlight_start": 1,
|
||||
"text": " {"
|
||||
},
|
||||
{
|
||||
"highlight_end": 46,
|
||||
"highlight_start": 1,
|
||||
"text": " if ! (* left_val == * right_val)"
|
||||
},
|
||||
{
|
||||
"highlight_end": 15,
|
||||
"highlight_start": 1,
|
||||
"text": " {"
|
||||
},
|
||||
{
|
||||
"highlight_end": 25,
|
||||
"highlight_start": 1,
|
||||
"text": " panic !"
|
||||
},
|
||||
{
|
||||
"highlight_end": 57,
|
||||
"highlight_start": 1,
|
||||
"text": " (r#\"assertion failed: `(left == right)`"
|
||||
},
|
||||
{
|
||||
"highlight_end": 16,
|
||||
"highlight_start": 1,
|
||||
"text": " left: `{:?}`,"
|
||||
},
|
||||
{
|
||||
"highlight_end": 22,
|
||||
"highlight_start": 1,
|
||||
"text": " right: `{:?}`: {}\"#,"
|
||||
},
|
||||
{
|
||||
"highlight_end": 72,
|
||||
"highlight_start": 1,
|
||||
"text": " & * left_val, & * right_val, $ crate :: format_args !"
|
||||
},
|
||||
{
|
||||
"highlight_end": 33,
|
||||
"highlight_start": 1,
|
||||
"text": " ($ ($ arg) +))"
|
||||
},
|
||||
{
|
||||
"highlight_end": 15,
|
||||
"highlight_start": 1,
|
||||
"text": " }"
|
||||
},
|
||||
{
|
||||
"highlight_end": 11,
|
||||
"highlight_start": 1,
|
||||
"text": " }"
|
||||
},
|
||||
{
|
||||
"highlight_end": 7,
|
||||
"highlight_start": 1,
|
||||
"text": " }"
|
||||
},
|
||||
{
|
||||
"highlight_end": 6,
|
||||
"highlight_start": 1,
|
||||
"text": " }) ;"
|
||||
}
|
||||
]
|
||||
},
|
||||
"macro_decl_name": "assert_eq!",
|
||||
"span": {
|
||||
"byte_end": 38,
|
||||
"byte_start": 16,
|
||||
"column_end": 27,
|
||||
"column_start": 5,
|
||||
"expansion": null,
|
||||
"file_name": "src/main.rs",
|
||||
"is_primary": false,
|
||||
"label": null,
|
||||
"line_end": 2,
|
||||
"line_start": 2,
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"text": [
|
||||
{
|
||||
"highlight_end": 27,
|
||||
"highlight_start": 5,
|
||||
"text": " assert_eq!(1, \"love\");"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"file_name": "<::core::macros::assert_eq macros>",
|
||||
"is_primary": true,
|
||||
"label": "no implementation for `{integer} == &str`",
|
||||
"line_end": 7,
|
||||
"line_start": 7,
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"text": [
|
||||
{
|
||||
"highlight_end": 33,
|
||||
"highlight_start": 31,
|
||||
"text": " if ! (* left_val == * right_val)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"message": "mismatched types",
|
||||
"code": {
|
||||
"code": "E0308",
|
||||
"explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"
|
||||
},
|
||||
"level": "error",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "runtime/compiler_support.rs",
|
||||
"byte_start": 1589,
|
||||
"byte_end": 1594,
|
||||
"line_start": 48,
|
||||
"line_end": 48,
|
||||
"column_start": 65,
|
||||
"column_end": 70,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " let layout = alloc::Layout::from_size_align_unchecked(size, align);",
|
||||
"highlight_start": 65,
|
||||
"highlight_end": 70
|
||||
}
|
||||
],
|
||||
"label": "expected usize, found u32",
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"rendered": "error[E0308]: mismatched types\n --> runtime/compiler_support.rs:48:65\n |\n48 | let layout = alloc::Layout::from_size_align_unchecked(size, align);\n | ^^^^^ expected usize, found u32\n\n"
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
"message": "unused variable: `foo`",
|
||||
"code": {
|
||||
"code": "unused_variables",
|
||||
"explanation": null
|
||||
},
|
||||
"level": "warning",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "driver/subcommand/repl.rs",
|
||||
"byte_start": 9228,
|
||||
"byte_end": 9231,
|
||||
"line_start": 291,
|
||||
"line_end": 291,
|
||||
"column_start": 9,
|
||||
"column_end": 12,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " let foo = 42;",
|
||||
"highlight_start": 9,
|
||||
"highlight_end": 12
|
||||
}
|
||||
],
|
||||
"label": null,
|
||||
"suggested_replacement": null,
|
||||
"suggestion_applicability": null,
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"message": "#[warn(unused_variables)] on by default",
|
||||
"code": null,
|
||||
"level": "note",
|
||||
"spans": [],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
},
|
||||
{
|
||||
"message": "consider prefixing with an underscore",
|
||||
"code": null,
|
||||
"level": "help",
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "driver/subcommand/repl.rs",
|
||||
"byte_start": 9228,
|
||||
"byte_end": 9231,
|
||||
"line_start": 291,
|
||||
"line_end": 291,
|
||||
"column_start": 9,
|
||||
"column_end": 12,
|
||||
"is_primary": true,
|
||||
"text": [
|
||||
{
|
||||
"text": " let foo = 42;",
|
||||
"highlight_start": 9,
|
||||
"highlight_end": 12
|
||||
}
|
||||
],
|
||||
"label": null,
|
||||
"suggested_replacement": "_foo",
|
||||
"suggestion_applicability": "MachineApplicable",
|
||||
"expansion": null
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"rendered": null
|
||||
}
|
||||
],
|
||||
"rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { SuggestionApplicability } from '../../../utils/diagnostics/rust';
|
||||
import SuggestedFix from '../../../utils/diagnostics/SuggestedFix';
|
||||
|
||||
const location1 = new vscode.Location(
|
||||
vscode.Uri.file('/file/1'),
|
||||
new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4)),
|
||||
);
|
||||
|
||||
const location2 = new vscode.Location(
|
||||
vscode.Uri.file('/file/2'),
|
||||
new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8)),
|
||||
);
|
||||
|
||||
describe('SuggestedFix', () => {
|
||||
describe('isEqual', () => {
|
||||
it('should treat identical instances as equal', () => {
|
||||
const suggestion1 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
const suggestion2 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
assert(suggestion1.isEqual(suggestion2));
|
||||
});
|
||||
|
||||
it('should treat instances with different titles as inequal', () => {
|
||||
const suggestion1 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
const suggestion2 = new SuggestedFix(
|
||||
'Not the same title!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
assert(!suggestion1.isEqual(suggestion2));
|
||||
});
|
||||
|
||||
it('should treat instances with different replacements as inequal', () => {
|
||||
const suggestion1 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
const suggestion2 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With something else!',
|
||||
);
|
||||
|
||||
assert(!suggestion1.isEqual(suggestion2));
|
||||
});
|
||||
|
||||
it('should treat instances with different locations as inequal', () => {
|
||||
const suggestion1 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
const suggestion2 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location2,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
assert(!suggestion1.isEqual(suggestion2));
|
||||
});
|
||||
|
||||
it('should treat instances with different applicability as inequal', () => {
|
||||
const suggestion1 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
SuggestionApplicability.MachineApplicable,
|
||||
);
|
||||
|
||||
const suggestion2 = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location2,
|
||||
'With this!',
|
||||
SuggestionApplicability.HasPlaceholders,
|
||||
);
|
||||
|
||||
assert(!suggestion1.isEqual(suggestion2));
|
||||
});
|
||||
});
|
||||
|
||||
describe('toCodeAction', () => {
|
||||
it('should map a simple suggestion', () => {
|
||||
const suggestion = new SuggestedFix(
|
||||
'Replace me!',
|
||||
location1,
|
||||
'With this!',
|
||||
);
|
||||
|
||||
const codeAction = suggestion.toCodeAction();
|
||||
assert.strictEqual(codeAction.kind, vscode.CodeActionKind.QuickFix);
|
||||
assert.strictEqual(codeAction.title, 'Replace me!');
|
||||
assert.strictEqual(codeAction.isPreferred, false);
|
||||
|
||||
const edit = codeAction.edit;
|
||||
if (!edit) {
|
||||
assert.fail('Code Action edit unexpectedly missing');
|
||||
return;
|
||||
}
|
||||
|
||||
const editEntries = edit.entries();
|
||||
assert.strictEqual(editEntries.length, 1);
|
||||
|
||||
const [[editUri, textEdits]] = editEntries;
|
||||
assert.strictEqual(editUri.toString(), location1.uri.toString());
|
||||
|
||||
assert.strictEqual(textEdits.length, 1);
|
||||
const [textEdit] = textEdits;
|
||||
|
||||
assert(textEdit.range.isEqual(location1.range));
|
||||
assert.strictEqual(textEdit.newText, 'With this!');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,127 +0,0 @@
|
|||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import SuggestedFix from '../../../utils/diagnostics/SuggestedFix';
|
||||
import SuggestedFixCollection from '../../../utils/diagnostics/SuggestedFixCollection';
|
||||
|
||||
const uri1 = vscode.Uri.file('/file/1');
|
||||
const uri2 = vscode.Uri.file('/file/2');
|
||||
|
||||
const mockDocument1 = ({
|
||||
uri: uri1,
|
||||
} as unknown) as vscode.TextDocument;
|
||||
|
||||
const mockDocument2 = ({
|
||||
uri: uri2,
|
||||
} as unknown) as vscode.TextDocument;
|
||||
|
||||
const range1 = new vscode.Range(
|
||||
new vscode.Position(1, 2),
|
||||
new vscode.Position(3, 4),
|
||||
);
|
||||
const range2 = new vscode.Range(
|
||||
new vscode.Position(5, 6),
|
||||
new vscode.Position(7, 8),
|
||||
);
|
||||
|
||||
const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic');
|
||||
const diagnostic2 = new vscode.Diagnostic(range2, 'Second diagnostic');
|
||||
|
||||
// This is a mutable object so return a fresh instance every time
|
||||
function suggestion1(): SuggestedFix {
|
||||
return new SuggestedFix(
|
||||
'Replace me!',
|
||||
new vscode.Location(uri1, range1),
|
||||
'With this!',
|
||||
);
|
||||
}
|
||||
|
||||
describe('SuggestedFixCollection', () => {
|
||||
it('should add a suggestion then return it as a code action', () => {
|
||||
const suggestedFixes = new SuggestedFixCollection();
|
||||
suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
|
||||
|
||||
// Specify the document and range that exactly matches
|
||||
const codeActions = suggestedFixes.provideCodeActions(
|
||||
mockDocument1,
|
||||
range1,
|
||||
);
|
||||
|
||||
assert.strictEqual(codeActions.length, 1);
|
||||
const [codeAction] = codeActions;
|
||||
assert.strictEqual(codeAction.title, suggestion1().title);
|
||||
|
||||
const { diagnostics } = codeAction;
|
||||
if (!diagnostics) {
|
||||
assert.fail('Diagnostics unexpectedly missing');
|
||||
return;
|
||||
}
|
||||
|
||||
assert.strictEqual(diagnostics.length, 1);
|
||||
assert.strictEqual(diagnostics[0], diagnostic1);
|
||||
});
|
||||
|
||||
it('should not return code actions for different ranges', () => {
|
||||
const suggestedFixes = new SuggestedFixCollection();
|
||||
suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
|
||||
|
||||
const codeActions = suggestedFixes.provideCodeActions(
|
||||
mockDocument1,
|
||||
range2,
|
||||
);
|
||||
|
||||
assert(!codeActions || codeActions.length === 0);
|
||||
});
|
||||
|
||||
it('should not return code actions for different documents', () => {
|
||||
const suggestedFixes = new SuggestedFixCollection();
|
||||
suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
|
||||
|
||||
const codeActions = suggestedFixes.provideCodeActions(
|
||||
mockDocument2,
|
||||
range1,
|
||||
);
|
||||
|
||||
assert(!codeActions || codeActions.length === 0);
|
||||
});
|
||||
|
||||
it('should not return code actions that have been cleared', () => {
|
||||
const suggestedFixes = new SuggestedFixCollection();
|
||||
suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
|
||||
suggestedFixes.clear();
|
||||
|
||||
const codeActions = suggestedFixes.provideCodeActions(
|
||||
mockDocument1,
|
||||
range1,
|
||||
);
|
||||
|
||||
assert(!codeActions || codeActions.length === 0);
|
||||
});
|
||||
|
||||
it('should merge identical suggestions together', () => {
|
||||
const suggestedFixes = new SuggestedFixCollection();
|
||||
|
||||
// Add the same suggestion for two diagnostics
|
||||
suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
|
||||
suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic2);
|
||||
|
||||
const codeActions = suggestedFixes.provideCodeActions(
|
||||
mockDocument1,
|
||||
range1,
|
||||
);
|
||||
|
||||
assert.strictEqual(codeActions.length, 1);
|
||||
const [codeAction] = codeActions;
|
||||
const { diagnostics } = codeAction;
|
||||
|
||||
if (!diagnostics) {
|
||||
assert.fail('Diagnostics unexpectedly missing');
|
||||
return;
|
||||
}
|
||||
|
||||
// We should be associated with both diagnostics
|
||||
assert.strictEqual(diagnostics.length, 2);
|
||||
assert.strictEqual(diagnostics[0], diagnostic1);
|
||||
assert.strictEqual(diagnostics[1], diagnostic2);
|
||||
});
|
||||
});
|
|
@ -1,236 +0,0 @@
|
|||
import * as assert from 'assert';
|
||||
import * as fs from 'fs';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import {
|
||||
MappedRustDiagnostic,
|
||||
mapRustDiagnosticToVsCode,
|
||||
RustDiagnostic,
|
||||
SuggestionApplicability,
|
||||
} from '../../../utils/diagnostics/rust';
|
||||
|
||||
function loadDiagnosticFixture(name: string): RustDiagnostic {
|
||||
const jsonText = fs
|
||||
.readFileSync(
|
||||
// We're actually in our JavaScript output directory, climb out
|
||||
`${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json`,
|
||||
)
|
||||
.toString();
|
||||
|
||||
return JSON.parse(jsonText);
|
||||
}
|
||||
|
||||
function mapFixtureToVsCode(name: string): MappedRustDiagnostic {
|
||||
const rd = loadDiagnosticFixture(name);
|
||||
const mapResult = mapRustDiagnosticToVsCode(rd);
|
||||
|
||||
if (!mapResult) {
|
||||
return assert.fail('Mapping unexpectedly failed');
|
||||
}
|
||||
return mapResult;
|
||||
}
|
||||
|
||||
describe('mapRustDiagnosticToVsCode', () => {
|
||||
it('should map an incompatible type for trait error', () => {
|
||||
const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
|
||||
'error/E0053',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
diagnostic.severity,
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
assert.strictEqual(diagnostic.source, 'rustc');
|
||||
assert.strictEqual(
|
||||
diagnostic.message,
|
||||
[
|
||||
`method \`next\` has an incompatible type for trait`,
|
||||
`expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``,
|
||||
` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\``,
|
||||
].join('\n'),
|
||||
);
|
||||
assert.strictEqual(diagnostic.code, 'E0053');
|
||||
assert.deepStrictEqual(diagnostic.tags, []);
|
||||
|
||||
// No related information
|
||||
assert.deepStrictEqual(diagnostic.relatedInformation, []);
|
||||
|
||||
// There are no suggested fixes
|
||||
assert.strictEqual(suggestedFixes.length, 0);
|
||||
});
|
||||
|
||||
it('should map an unused variable warning', () => {
|
||||
const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
|
||||
'warning/unused_variables',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
diagnostic.severity,
|
||||
vscode.DiagnosticSeverity.Warning,
|
||||
);
|
||||
assert.strictEqual(
|
||||
diagnostic.message,
|
||||
[
|
||||
'unused variable: `foo`',
|
||||
'#[warn(unused_variables)] on by default',
|
||||
].join('\n'),
|
||||
);
|
||||
assert.strictEqual(diagnostic.code, 'unused_variables');
|
||||
assert.strictEqual(diagnostic.source, 'rustc');
|
||||
assert.deepStrictEqual(diagnostic.tags, [
|
||||
vscode.DiagnosticTag.Unnecessary,
|
||||
]);
|
||||
|
||||
// No related information
|
||||
assert.deepStrictEqual(diagnostic.relatedInformation, []);
|
||||
|
||||
// One suggested fix available to prefix the variable
|
||||
assert.strictEqual(suggestedFixes.length, 1);
|
||||
const [suggestedFix] = suggestedFixes;
|
||||
assert.strictEqual(
|
||||
suggestedFix.title,
|
||||
'consider prefixing with an underscore: `_foo`',
|
||||
);
|
||||
assert.strictEqual(
|
||||
suggestedFix.applicability,
|
||||
SuggestionApplicability.MachineApplicable,
|
||||
);
|
||||
});
|
||||
|
||||
it('should map a wrong number of parameters error', () => {
|
||||
const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
|
||||
'error/E0061',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
diagnostic.severity,
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
assert.strictEqual(
|
||||
diagnostic.message,
|
||||
[
|
||||
'this function takes 2 parameters but 3 parameters were supplied',
|
||||
'expected 2 parameters',
|
||||
].join('\n'),
|
||||
);
|
||||
assert.strictEqual(diagnostic.code, 'E0061');
|
||||
assert.strictEqual(diagnostic.source, 'rustc');
|
||||
assert.deepStrictEqual(diagnostic.tags, []);
|
||||
|
||||
// One related information for the original definition
|
||||
const relatedInformation = diagnostic.relatedInformation;
|
||||
if (!relatedInformation) {
|
||||
assert.fail('Related information unexpectedly undefined');
|
||||
return;
|
||||
}
|
||||
assert.strictEqual(relatedInformation.length, 1);
|
||||
const [related] = relatedInformation;
|
||||
assert.strictEqual(related.message, 'defined here');
|
||||
|
||||
// There are no suggested fixes
|
||||
assert.strictEqual(suggestedFixes.length, 0);
|
||||
});
|
||||
|
||||
it('should map a Clippy copy pass by ref warning', () => {
|
||||
const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
|
||||
'clippy/trivially_copy_pass_by_ref',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
diagnostic.severity,
|
||||
vscode.DiagnosticSeverity.Warning,
|
||||
);
|
||||
assert.strictEqual(diagnostic.source, 'clippy');
|
||||
assert.strictEqual(
|
||||
diagnostic.message,
|
||||
[
|
||||
'this argument is passed by reference, but would be more efficient if passed by value',
|
||||
'#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]',
|
||||
'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref',
|
||||
].join('\n'),
|
||||
);
|
||||
assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref');
|
||||
assert.deepStrictEqual(diagnostic.tags, []);
|
||||
|
||||
// One related information for the lint definition
|
||||
const relatedInformation = diagnostic.relatedInformation;
|
||||
if (!relatedInformation) {
|
||||
assert.fail('Related information unexpectedly undefined');
|
||||
return;
|
||||
}
|
||||
assert.strictEqual(relatedInformation.length, 1);
|
||||
const [related] = relatedInformation;
|
||||
assert.strictEqual(related.message, 'lint level defined here');
|
||||
|
||||
// One suggested fix to pass by value
|
||||
assert.strictEqual(suggestedFixes.length, 1);
|
||||
const [suggestedFix] = suggestedFixes;
|
||||
assert.strictEqual(
|
||||
suggestedFix.title,
|
||||
'consider passing by value instead: `self`',
|
||||
);
|
||||
// Clippy does not mark this with any applicability
|
||||
assert.strictEqual(
|
||||
suggestedFix.applicability,
|
||||
SuggestionApplicability.Unspecified,
|
||||
);
|
||||
});
|
||||
|
||||
it('should map a mismatched type error', () => {
|
||||
const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
|
||||
'error/E0308',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
diagnostic.severity,
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
assert.strictEqual(
|
||||
diagnostic.message,
|
||||
['mismatched types', 'expected usize, found u32'].join('\n'),
|
||||
);
|
||||
assert.strictEqual(diagnostic.code, 'E0308');
|
||||
assert.strictEqual(diagnostic.source, 'rustc');
|
||||
assert.deepStrictEqual(diagnostic.tags, []);
|
||||
|
||||
// No related information
|
||||
assert.deepStrictEqual(diagnostic.relatedInformation, []);
|
||||
|
||||
// There are no suggested fixes
|
||||
assert.strictEqual(suggestedFixes.length, 0);
|
||||
});
|
||||
|
||||
it('should map a macro invocation location to normal file path', () => {
|
||||
const { location, diagnostic, suggestedFixes } = mapFixtureToVsCode(
|
||||
'error/E0277',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
diagnostic.severity,
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
assert.strictEqual(
|
||||
diagnostic.message,
|
||||
[
|
||||
"can't compare `{integer}` with `&str`",
|
||||
'the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`',
|
||||
].join('\n'),
|
||||
);
|
||||
assert.strictEqual(diagnostic.code, 'E0277');
|
||||
assert.strictEqual(diagnostic.source, 'rustc');
|
||||
assert.deepStrictEqual(diagnostic.tags, []);
|
||||
|
||||
// No related information
|
||||
assert.deepStrictEqual(diagnostic.relatedInformation, []);
|
||||
|
||||
// There are no suggested fixes
|
||||
assert.strictEqual(suggestedFixes.length, 0);
|
||||
|
||||
// The file url should be normal file
|
||||
// Ignore the first part because it depends on vs workspace location
|
||||
assert.strictEqual(
|
||||
location.uri.path.substr(-'src/main.rs'.length),
|
||||
'src/main.rs',
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,98 +0,0 @@
|
|||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { areDiagnosticsEqual } from '../../../utils/diagnostics/vscode';
|
||||
|
||||
const range1 = new vscode.Range(
|
||||
new vscode.Position(1, 2),
|
||||
new vscode.Position(3, 4),
|
||||
);
|
||||
|
||||
const range2 = new vscode.Range(
|
||||
new vscode.Position(5, 6),
|
||||
new vscode.Position(7, 8),
|
||||
);
|
||||
|
||||
describe('areDiagnosticsEqual', () => {
|
||||
it('should treat identical diagnostics as equal', () => {
|
||||
const diagnostic1 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
const diagnostic2 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
assert(areDiagnosticsEqual(diagnostic1, diagnostic2));
|
||||
});
|
||||
|
||||
it('should treat diagnostics with different sources as inequal', () => {
|
||||
const diagnostic1 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
diagnostic1.source = 'rustc';
|
||||
|
||||
const diagnostic2 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
diagnostic2.source = 'clippy';
|
||||
|
||||
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
|
||||
});
|
||||
|
||||
it('should treat diagnostics with different ranges as inequal', () => {
|
||||
const diagnostic1 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
const diagnostic2 = new vscode.Diagnostic(
|
||||
range2,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
|
||||
});
|
||||
|
||||
it('should treat diagnostics with different messages as inequal', () => {
|
||||
const diagnostic1 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
const diagnostic2 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Goodbye!, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
|
||||
});
|
||||
|
||||
it('should treat diagnostics with different severities as inequal', () => {
|
||||
const diagnostic1 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Warning,
|
||||
);
|
||||
|
||||
const diagnostic2 = new vscode.Diagnostic(
|
||||
range1,
|
||||
'Hello, world!',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
|
||||
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
|
||||
});
|
||||
});
|
|
@ -1,67 +0,0 @@
|
|||
import * as vscode from 'vscode';
|
||||
|
||||
import { SuggestionApplicability } from './rust';
|
||||
|
||||
/**
|
||||
* Model object for text replacements suggested by the Rust compiler
|
||||
*
|
||||
* This is an intermediate form between the raw `rustc` JSON and a
|
||||
* `vscode.CodeAction`. It's optimised for the use-cases of
|
||||
* `SuggestedFixCollection`.
|
||||
*/
|
||||
export default class SuggestedFix {
|
||||
public readonly title: string;
|
||||
public readonly location: vscode.Location;
|
||||
public readonly replacement: string;
|
||||
public readonly applicability: SuggestionApplicability;
|
||||
|
||||
/**
|
||||
* Diagnostics this suggested fix could resolve
|
||||
*/
|
||||
public diagnostics: vscode.Diagnostic[];
|
||||
|
||||
constructor(
|
||||
title: string,
|
||||
location: vscode.Location,
|
||||
replacement: string,
|
||||
applicability: SuggestionApplicability = SuggestionApplicability.Unspecified,
|
||||
) {
|
||||
this.title = title;
|
||||
this.location = location;
|
||||
this.replacement = replacement;
|
||||
this.applicability = applicability;
|
||||
this.diagnostics = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this suggested fix is equivalent to another instance
|
||||
*/
|
||||
public isEqual(other: SuggestedFix): boolean {
|
||||
return (
|
||||
this.title === other.title &&
|
||||
this.location.range.isEqual(other.location.range) &&
|
||||
this.replacement === other.replacement &&
|
||||
this.applicability === other.applicability
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this suggested fix to a VS Code Quick Fix code action
|
||||
*/
|
||||
public toCodeAction(): vscode.CodeAction {
|
||||
const codeAction = new vscode.CodeAction(
|
||||
this.title,
|
||||
vscode.CodeActionKind.QuickFix,
|
||||
);
|
||||
|
||||
const edit = new vscode.WorkspaceEdit();
|
||||
edit.replace(this.location.uri, this.location.range, this.replacement);
|
||||
codeAction.edit = edit;
|
||||
|
||||
codeAction.isPreferred =
|
||||
this.applicability === SuggestionApplicability.MachineApplicable;
|
||||
|
||||
codeAction.diagnostics = [...this.diagnostics];
|
||||
return codeAction;
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
import * as vscode from 'vscode';
|
||||
import SuggestedFix from './SuggestedFix';
|
||||
|
||||
/**
|
||||
* Collection of suggested fixes across multiple documents
|
||||
*
|
||||
* This stores `SuggestedFix` model objects and returns them via the
|
||||
* `vscode.CodeActionProvider` interface.
|
||||
*/
|
||||
export default class SuggestedFixCollection
|
||||
implements vscode.CodeActionProvider {
|
||||
public static PROVIDED_CODE_ACTION_KINDS = [vscode.CodeActionKind.QuickFix];
|
||||
|
||||
/**
|
||||
* Map of document URI strings to suggested fixes
|
||||
*/
|
||||
private suggestedFixes: Map<string, SuggestedFix[]>;
|
||||
|
||||
constructor() {
|
||||
this.suggestedFixes = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all suggested fixes across all documents
|
||||
*/
|
||||
public clear(): void {
|
||||
this.suggestedFixes = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a suggested fix for the given diagnostic
|
||||
*
|
||||
* Some suggested fixes will appear in multiple diagnostics. For example,
|
||||
* forgetting a `mut` on a variable will suggest changing the delaration on
|
||||
* every mutable usage site. If the suggested fix has already been added
|
||||
* this method will instead associate the existing fix with the new
|
||||
* diagnostic.
|
||||
*/
|
||||
public addSuggestedFixForDiagnostic(
|
||||
suggestedFix: SuggestedFix,
|
||||
diagnostic: vscode.Diagnostic,
|
||||
): void {
|
||||
const fileUriString = suggestedFix.location.uri.toString();
|
||||
const fileSuggestions = this.suggestedFixes.get(fileUriString) || [];
|
||||
|
||||
const existingSuggestion = fileSuggestions.find(s =>
|
||||
s.isEqual(suggestedFix),
|
||||
);
|
||||
|
||||
if (existingSuggestion) {
|
||||
// The existing suggestion also applies to this new diagnostic
|
||||
existingSuggestion.diagnostics.push(diagnostic);
|
||||
} else {
|
||||
// We haven't seen this suggestion before
|
||||
suggestedFix.diagnostics.push(diagnostic);
|
||||
fileSuggestions.push(suggestedFix);
|
||||
}
|
||||
|
||||
this.suggestedFixes.set(fileUriString, fileSuggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters suggested fixes by their document and range and converts them to
|
||||
* code actions
|
||||
*/
|
||||
public provideCodeActions(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range,
|
||||
): vscode.CodeAction[] {
|
||||
const documentUriString = document.uri.toString();
|
||||
|
||||
const suggestedFixes = this.suggestedFixes.get(documentUriString);
|
||||
return (suggestedFixes || [])
|
||||
.filter(({ location }) => location.range.intersection(range))
|
||||
.map(suggestedEdit => suggestedEdit.toCodeAction());
|
||||
}
|
||||
}
|
|
@ -1,299 +0,0 @@
|
|||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import SuggestedFix from './SuggestedFix';
|
||||
|
||||
export enum SuggestionApplicability {
|
||||
MachineApplicable = 'MachineApplicable',
|
||||
HasPlaceholders = 'HasPlaceholders',
|
||||
MaybeIncorrect = 'MaybeIncorrect',
|
||||
Unspecified = 'Unspecified',
|
||||
}
|
||||
|
||||
export interface RustDiagnosticSpanMacroExpansion {
|
||||
span: RustDiagnosticSpan;
|
||||
macro_decl_name: string;
|
||||
def_site_span?: RustDiagnosticSpan;
|
||||
}
|
||||
|
||||
// Reference:
|
||||
// https://github.com/rust-lang/rust/blob/master/src/libsyntax/json.rs
|
||||
export interface RustDiagnosticSpan {
|
||||
line_start: number;
|
||||
line_end: number;
|
||||
column_start: number;
|
||||
column_end: number;
|
||||
is_primary: boolean;
|
||||
file_name: string;
|
||||
label?: string;
|
||||
expansion?: RustDiagnosticSpanMacroExpansion;
|
||||
suggested_replacement?: string;
|
||||
suggestion_applicability?: SuggestionApplicability;
|
||||
}
|
||||
|
||||
export interface RustDiagnostic {
|
||||
spans: RustDiagnosticSpan[];
|
||||
rendered: string;
|
||||
message: string;
|
||||
level: string;
|
||||
code?: {
|
||||
code: string;
|
||||
};
|
||||
children: RustDiagnostic[];
|
||||
}
|
||||
|
||||
export interface MappedRustDiagnostic {
|
||||
location: vscode.Location;
|
||||
diagnostic: vscode.Diagnostic;
|
||||
suggestedFixes: SuggestedFix[];
|
||||
}
|
||||
|
||||
interface MappedRustChildDiagnostic {
|
||||
related?: vscode.DiagnosticRelatedInformation;
|
||||
suggestedFix?: SuggestedFix;
|
||||
messageLine?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Rust level string to a VsCode severity
|
||||
*/
|
||||
function mapLevelToSeverity(s: string): vscode.DiagnosticSeverity {
|
||||
if (s === 'error') {
|
||||
return vscode.DiagnosticSeverity.Error;
|
||||
}
|
||||
if (s.startsWith('warn')) {
|
||||
return vscode.DiagnosticSeverity.Warning;
|
||||
}
|
||||
return vscode.DiagnosticSeverity.Information;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a file name is from macro invocation
|
||||
*/
|
||||
function isFromMacro(fileName: string): boolean {
|
||||
return fileName.startsWith('<') && fileName.endsWith('>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Rust macro span to a VsCode location recursively
|
||||
*/
|
||||
function mapMacroSpanToLocation(
|
||||
spanMacro: RustDiagnosticSpanMacroExpansion,
|
||||
): vscode.Location | undefined {
|
||||
if (!isFromMacro(spanMacro.span.file_name)) {
|
||||
return mapSpanToLocation(spanMacro.span);
|
||||
}
|
||||
|
||||
if (spanMacro.span.expansion) {
|
||||
return mapMacroSpanToLocation(spanMacro.span.expansion);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Rust span to a VsCode location
|
||||
*/
|
||||
function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
|
||||
if (isFromMacro(span.file_name) && span.expansion) {
|
||||
const macroLoc = mapMacroSpanToLocation(span.expansion);
|
||||
if (macroLoc) {
|
||||
return macroLoc;
|
||||
}
|
||||
}
|
||||
|
||||
const fileName = path.join(vscode.workspace.rootPath || '', span.file_name);
|
||||
const fileUri = vscode.Uri.file(fileName);
|
||||
|
||||
const range = new vscode.Range(
|
||||
new vscode.Position(span.line_start - 1, span.column_start - 1),
|
||||
new vscode.Position(span.line_end - 1, span.column_end - 1),
|
||||
);
|
||||
|
||||
return new vscode.Location(fileUri, range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a secondary Rust span to a VsCode related information
|
||||
*
|
||||
* If the span is unlabelled this will return `undefined`.
|
||||
*/
|
||||
function mapSecondarySpanToRelated(
|
||||
span: RustDiagnosticSpan,
|
||||
): vscode.DiagnosticRelatedInformation | undefined {
|
||||
if (!span.label) {
|
||||
// Nothing to label this with
|
||||
return;
|
||||
}
|
||||
|
||||
const location = mapSpanToLocation(span);
|
||||
return new vscode.DiagnosticRelatedInformation(location, span.label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if diagnostic is related to unused code
|
||||
*/
|
||||
function isUnusedOrUnnecessary(rd: RustDiagnostic): boolean {
|
||||
if (!rd.code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'dead_code',
|
||||
'unknown_lints',
|
||||
'unreachable_code',
|
||||
'unused_attributes',
|
||||
'unused_imports',
|
||||
'unused_macros',
|
||||
'unused_variables',
|
||||
].includes(rd.code.code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if diagnostic is related to deprecated code
|
||||
*/
|
||||
function isDeprecated(rd: RustDiagnostic): boolean {
|
||||
if (!rd.code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ['deprecated'].includes(rd.code.code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Rust child diagnostic to a VsCode related information
|
||||
*
|
||||
* This can have three outcomes:
|
||||
*
|
||||
* 1. If this is no primary span this will return a `noteLine`
|
||||
* 2. If there is a primary span with a suggested replacement it will return a
|
||||
* `codeAction`.
|
||||
* 3. If there is a primary span without a suggested replacement it will return
|
||||
* a `related`.
|
||||
*/
|
||||
function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
|
||||
const span = rd.spans.find(s => s.is_primary);
|
||||
|
||||
if (!span) {
|
||||
// `rustc` uses these spanless children as a way to print multi-line
|
||||
// messages
|
||||
return { messageLine: rd.message };
|
||||
}
|
||||
|
||||
// If we have a primary span use its location, otherwise use the parent
|
||||
const location = mapSpanToLocation(span);
|
||||
|
||||
// We need to distinguish `null` from an empty string
|
||||
if (span && typeof span.suggested_replacement === 'string') {
|
||||
// Include our replacement in the title unless it's empty
|
||||
const title = span.suggested_replacement
|
||||
? `${rd.message}: \`${span.suggested_replacement}\``
|
||||
: rd.message;
|
||||
|
||||
return {
|
||||
suggestedFix: new SuggestedFix(
|
||||
title,
|
||||
location,
|
||||
span.suggested_replacement,
|
||||
span.suggestion_applicability,
|
||||
),
|
||||
};
|
||||
} else {
|
||||
const related = new vscode.DiagnosticRelatedInformation(
|
||||
location,
|
||||
rd.message,
|
||||
);
|
||||
|
||||
return { related };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Rust root diagnostic to VsCode form
|
||||
*
|
||||
* This flattens the Rust diagnostic by:
|
||||
*
|
||||
* 1. Creating a `vscode.Diagnostic` with the root message and primary span.
|
||||
* 2. Adding any labelled secondary spans to `relatedInformation`
|
||||
* 3. Categorising child diagnostics as either `SuggestedFix`es,
|
||||
* `relatedInformation` or additional message lines.
|
||||
*
|
||||
* If the diagnostic has no primary span this will return `undefined`
|
||||
*/
|
||||
export function mapRustDiagnosticToVsCode(
|
||||
rd: RustDiagnostic,
|
||||
): MappedRustDiagnostic | undefined {
|
||||
const primarySpan = rd.spans.find(s => s.is_primary);
|
||||
if (!primarySpan) {
|
||||
return;
|
||||
}
|
||||
|
||||
const location = mapSpanToLocation(primarySpan);
|
||||
const secondarySpans = rd.spans.filter(s => !s.is_primary);
|
||||
|
||||
const severity = mapLevelToSeverity(rd.level);
|
||||
let primarySpanLabel = primarySpan.label;
|
||||
|
||||
const vd = new vscode.Diagnostic(location.range, rd.message, severity);
|
||||
|
||||
let source = 'rustc';
|
||||
let code = rd.code && rd.code.code;
|
||||
if (code) {
|
||||
// See if this is an RFC #2103 scoped lint (e.g. from Clippy)
|
||||
const scopedCode = code.split('::');
|
||||
if (scopedCode.length === 2) {
|
||||
[source, code] = scopedCode;
|
||||
}
|
||||
}
|
||||
|
||||
vd.source = source;
|
||||
vd.code = code;
|
||||
vd.relatedInformation = [];
|
||||
vd.tags = [];
|
||||
|
||||
for (const secondarySpan of secondarySpans) {
|
||||
const related = mapSecondarySpanToRelated(secondarySpan);
|
||||
if (related) {
|
||||
vd.relatedInformation.push(related);
|
||||
}
|
||||
}
|
||||
|
||||
const suggestedFixes = [];
|
||||
for (const child of rd.children) {
|
||||
const { related, suggestedFix, messageLine } = mapRustChildDiagnostic(
|
||||
child,
|
||||
);
|
||||
|
||||
if (related) {
|
||||
vd.relatedInformation.push(related);
|
||||
}
|
||||
if (suggestedFix) {
|
||||
suggestedFixes.push(suggestedFix);
|
||||
}
|
||||
if (messageLine) {
|
||||
vd.message += `\n${messageLine}`;
|
||||
|
||||
// These secondary messages usually duplicate the content of the
|
||||
// primary span label.
|
||||
primarySpanLabel = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (primarySpanLabel) {
|
||||
vd.message += `\n${primarySpanLabel}`;
|
||||
}
|
||||
|
||||
if (isUnusedOrUnnecessary(rd)) {
|
||||
vd.tags.push(vscode.DiagnosticTag.Unnecessary);
|
||||
}
|
||||
|
||||
if (isDeprecated(rd)) {
|
||||
vd.tags.push(vscode.DiagnosticTag.Deprecated);
|
||||
}
|
||||
|
||||
return {
|
||||
location,
|
||||
diagnostic: vd,
|
||||
suggestedFixes,
|
||||
};
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import * as vscode from 'vscode';
|
||||
|
||||
/** Compares two `vscode.Diagnostic`s for equality */
|
||||
export function areDiagnosticsEqual(
|
||||
left: vscode.Diagnostic,
|
||||
right: vscode.Diagnostic,
|
||||
): boolean {
|
||||
return (
|
||||
left.source === right.source &&
|
||||
left.severity === right.severity &&
|
||||
left.range.isEqual(right.range) &&
|
||||
left.message === right.message
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue