mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Merge #2575
2575: [VS Code Extension] Remap error location if it extracted inside macros r=edwin0cheng a=edwin0cheng It should fix for #2569 Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
commit
46ca40ccfc
261
editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
vendored
Normal file
261
editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
{
|
||||
"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)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -199,4 +199,38 @@ describe('mapRustDiagnosticToVsCode', () => {
|
||||
// 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',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -10,6 +10,12 @@ export enum SuggestionApplicability {
|
||||
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 {
|
||||
@ -20,6 +26,7 @@ export interface RustDiagnosticSpan {
|
||||
is_primary: boolean;
|
||||
file_name: string;
|
||||
label?: string;
|
||||
expansion?: RustDiagnosticSpanMacroExpansion;
|
||||
suggested_replacement?: string;
|
||||
suggestion_applicability?: SuggestionApplicability;
|
||||
}
|
||||
@ -60,10 +67,41 @@ function mapLevelToSeverity(s: string): vscode.DiagnosticSeverity {
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user