diff --git a/lib/utils.ts b/lib/utils.ts index 1ebf6ca5c..d5501e828 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -255,6 +255,7 @@ export function parseOutput( } export function parseRustOutput(lines: string, inputFilename?: string, pathPrefix?: string) { + const inputBasename = inputFilename ? path.basename(inputFilename) : undefined; const quickfixes: {re: RegExp; makeFix: (match: string[]) => Fix}[] = [ { re: / *help: add `#!\[feature\((.*?)\)]`/, @@ -288,7 +289,7 @@ export function parseRustOutput(lines: string, inputFilename?: string, pathPrefi }, ]; - const re = /^\s+-->\s+[(:](\d+)(:?,?(\d+):?)?[):]*\s*(.*)/; + const re = /^\s+-->\s+(?.*):(?\d+):(?\d+)/; const result: ResultLine[] = []; let currentDiagnostic: ResultLine | undefined; eachLine(lines, line => { @@ -298,14 +299,17 @@ export function parseRustOutput(lines: string, inputFilename?: string, pathPrefi const filteredLine = filterEscapeSequences(line); const match = filteredLine.match(re); - if (match) { - const line = Number.parseInt(match[1], 10); - const column = Number.parseInt(match[3] || '0', 10); + if (match?.groups) { + const file = + match.groups.filename === '' ? inputBasename : path.basename(match.groups.filename); + const line = Number.parseInt(match.groups.line, 10); + const column = Number.parseInt(match.groups.column, 10); currentDiagnostic = result.pop(); if (currentDiagnostic !== undefined) { const text = filterEscapeSequences(currentDiagnostic.text); currentDiagnostic.tag = { + file, line, column, text, @@ -316,6 +320,7 @@ export function parseRustOutput(lines: string, inputFilename?: string, pathPrefi } lineObj.tag = { + file, line, column, text: '', // Left empty so that it does not show up in the editor diff --git a/test/utils-tests.ts b/test/utils-tests.ts index 60027d28b..eccd5c560 100644 --- a/test/utils-tests.ts +++ b/test/utils-tests.ts @@ -247,49 +247,49 @@ describe('Pascal compiler output', () => { describe('Rust compiler output', () => { it('handles simple cases', () => { expect(utils.parseRustOutput('Line one\nLine two', 'bob.rs')).toEqual([{text: 'Line one'}, {text: 'Line two'}]); - expect(utils.parseRustOutput('Unrelated\nLine one\n --> bob.rs:1\nUnrelated', 'bob.rs')).toEqual([ + expect(utils.parseRustOutput('Unrelated\nLine one\n --> bob.rs:1:0\nUnrelated', 'bob.rs')).toEqual([ {text: 'Unrelated'}, { - tag: {column: 0, line: 1, text: 'Line one', severity: 3, fixes: []}, + tag: {file: 'bob.rs', column: 0, line: 1, text: 'Line one', severity: 3, fixes: []}, text: 'Line one', }, { - tag: {column: 0, line: 1, text: '', severity: 3}, - text: ' --> :1', + tag: {file: 'bob.rs', column: 0, line: 1, text: '', severity: 3}, + text: ' --> :1:0', }, {text: 'Unrelated'}, ]); expect(utils.parseRustOutput('Line one\n --> bob.rs:1:5', 'bob.rs')).toEqual([ { - tag: {column: 5, line: 1, text: 'Line one', severity: 3, fixes: []}, + tag: {file: 'bob.rs', column: 5, line: 1, text: 'Line one', severity: 3, fixes: []}, text: 'Line one', }, { - tag: {column: 5, line: 1, text: '', severity: 3}, + tag: {file: 'bob.rs', column: 5, line: 1, text: '', severity: 3}, text: ' --> :1:5', }, ]); expect(utils.parseRustOutput('Multiple spaces\n --> bob.rs:1:5', 'bob.rs')).toEqual([ { - tag: {column: 5, line: 1, text: 'Multiple spaces', severity: 3, fixes: []}, + tag: {file: 'bob.rs', column: 5, line: 1, text: 'Multiple spaces', severity: 3, fixes: []}, text: 'Multiple spaces', }, { - tag: {column: 5, line: 1, text: '', severity: 3}, + tag: {file: 'bob.rs', column: 5, line: 1, text: '', severity: 3}, text: ' --> :1:5', }, ]); }); it('replaces all references to input source', () => { - expect(utils.parseRustOutput('error: Error in bob.rs\n --> bob.rs:1', 'bob.rs')).toEqual([ + expect(utils.parseRustOutput('error: Error in bob.rs\n --> bob.rs:1:42', 'bob.rs')).toEqual([ { - tag: {column: 0, line: 1, text: 'error: Error in ', severity: 3, fixes: []}, + tag: {file: 'bob.rs', column: 42, line: 1, text: 'error: Error in ', severity: 3, fixes: []}, text: 'error: Error in ', }, { - tag: {column: 0, line: 1, text: '', severity: 3}, - text: ' --> :1', + tag: {file: 'bob.rs', column: 42, line: 1, text: '', severity: 3}, + text: ' --> :1:42', }, ]); }); @@ -297,11 +297,11 @@ describe('Rust compiler output', () => { it('treats as if it were the compiler source', () => { expect(utils.parseRustOutput('error: is sad\n --> :120:25', 'bob.rs')).toEqual([ { - tag: {column: 25, line: 120, text: 'error: is sad', severity: 3, fixes: []}, + tag: {file: 'bob.rs', column: 25, line: 120, text: 'error: is sad', severity: 3, fixes: []}, text: 'error: is sad', }, { - tag: {column: 25, line: 120, text: '', severity: 3}, + tag: {file: 'bob.rs', column: 25, line: 120, text: '', severity: 3}, text: ' --> :120:25', }, ]); @@ -412,6 +412,68 @@ describe('Rust compiler output', () => { {text: ' = help: add `#![feature(num_midpoint_signed)]` to the crate attributes to enable'}, ]); }); + + it('attaches filenames to errors from multiple files', () => { + // https://godbolt.org/z/nWE3PTeGf + expect( + utils.parseRustOutput( + `warning: function \`f1\` is never used + --> :3:4 + +warning: function \`f2\` is never used + --> /app/m.rs:1:4 + +warning: 2 warnings emitted`, + 'example.rs', + ), + ).toEqual([ + { + text: 'warning: function `f1` is never used', + tag: { + line: 3, + column: 4, + file: 'example.rs', + severity: 2, + text: 'warning: function `f1` is never used', + fixes: [], + }, + }, + { + text: ' --> :3:4', + tag: { + line: 3, + column: 4, + file: 'example.rs', + severity: 3, + text: '', + }, + }, + {text: ''}, + { + text: 'warning: function `f2` is never used', + tag: { + line: 1, + column: 4, + file: 'm.rs', + severity: 2, + text: 'warning: function `f2` is never used', + fixes: [], + }, + }, + { + text: ' --> /app/m.rs:1:4', + tag: { + line: 1, + column: 4, + file: 'm.rs', + severity: 3, + text: '', + }, + }, + {text: ''}, + {text: 'warning: 2 warnings emitted'}, + ]); + }); }); describe('Tool output', () => {