Fix GCC linker errors not showing up in Problems View (#3950)

* gcc.ts: Replace single regex pattern with array

* CHANGELOG.md: Add GCC parsing fix

* Change parser from gnuLD to gcc for linker error diagnostics unit test

* Fix GNU LD diagnostics parser not being enabled due to inconsistency in config and in build.ts by_source strings

* Improve GCC and GNU LD diagnostics parsers

* Remove obsolete french linker error unit test

* Add gcc and gnuld diagnostics unit tests

* Clean up regexes, add unit tests

* Make gcc and gnuld parsers execution order agnostic

* Share the RegexPattern interface and the MatchType interface rather than doubly defining it

* Remove C++ template compiler error detection from gnu-ld, move common data types to util.ts

* fix extra line

* update changelog

* Remove obsolete return statement

* Add comments

---------

Co-authored-by: 0xemgy <0xemgy>
Co-authored-by: Garrett Campbell <86264750+gcampbell-msft@users.noreply.github.com>
Co-authored-by: Garrett Campbell <gcampbell@microsoft.com>
This commit is contained in:
0xemgy 2024-11-01 14:52:55 +01:00 коммит произвёл GitHub
Родитель c3a5713a69
Коммит 220ac74783
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
6 изменённых файлов: 518 добавлений и 116 удалений

Просмотреть файл

@ -17,6 +17,7 @@ Bug Fixes:
- Fix our setting of `isUserPreset` for presets, only set it to `true` if it's defined in a user presets file. [#4059](https://github.com/microsoft/vscode-cmake-tools/issues/4059)
- Fix issue where duplicate presets are being listed in dropdown. [#4104](https://github.com/microsoft/vscode-cmake-tools/issues/4104)
- Fix various GCC compiler errors and GCC linker errors not showing up in Problems View [#2864](https://github.com/microsoft/vscode-cmake-tools/issues/2864)
## 1.19.52

Просмотреть файл

@ -21,9 +21,9 @@ export class Compilers {
[compiler: string]: RawDiagnosticParser;
gcc = new gcc.Parser();
gnuld = new gnu_ld.Parser();
ghs = new ghs.Parser();
diab = new diab.Parser();
gnuLD = new gnu_ld.Parser();
msvc = new mvsc.Parser();
iar = new iar.Parser();
}
@ -82,7 +82,7 @@ export class CompileOutputConsumer implements OutputConsumer {
MSVC: this.compilers.msvc.diagnostics,
GHS: this.compilers.ghs.diagnostics,
DIAB: this.compilers.diab.diagnostics,
link: this.compilers.gnuLD.diagnostics,
GNULD: this.compilers.gnuld.diagnostics,
IAR: this.compilers.iar.diagnostics
};
const parsers = util.objectPairs(by_source)

Просмотреть файл

@ -4,9 +4,23 @@
import * as vscode from 'vscode';
import { oneLess, RawDiagnostic, RawDiagnosticParser, RawRelated, FeedLineResult } from '@cmt/diagnostics/util';
import { oneLess, RawDiagnostic, RawDiagnosticParser, RawRelated, FeedLineResult, MatchType, RegexPattern } from '@cmt/diagnostics/util';
export const REGEX = /^(.*):(\d+):(\d+):\s+(?:fatal )?(\w*)(?:\sfatale)?\s?:\s+(.*)/;
// Patterns to identify and capture GCC diagnostic messages.
const regexPatterns: RegexPattern[] = [
{ // path/to/file:line:column: severity: message
regexPattern: /^(.+):(\d+):(\d+):\s+(?:fatal\s+)?(\w+):\s+(.+)/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Line, MatchType.Column, MatchType.Severity, MatchType.Message]
},
{ // path/to/file:line: severity: message (but not starting with "path/to/ld[.exe]:")
regexPattern: /^(?!.*?ld(?:\.exe)?:)(.+):(\d+):\s+(?:fatal\s+)?(\w+):\s+(.+)/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Line, MatchType.Severity, MatchType.Message]
},
{ // path/to/cc1[.exe]|arm-none-eabi-gcc[.exe]: severity: message
regexPattern: /^(.*(?:cc1|arm-none-eabi-gcc)(?:\.exe)?):\s+(?:fatal\s+)?(\w+):\s+(.+)/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Severity, MatchType.Message]
}
];
interface PendingTemplateBacktrace {
rootInstantiation: string;
@ -19,6 +33,11 @@ export class Parser extends RawDiagnosticParser {
private _pendingTemplateError?: PendingTemplateBacktrace;
doHandleLine(line: string) {
// Detect the first line of a C++ template error
// This is a special case which consists of 3 lines:
// path/to/file: In instantiation of ...:
// path/to/file:lineno:columnno: required from here
// path/to/file:lineno:columnno: severity: message
let mat = /(.*): (In instantiation of.+)/.exec(line);
if (mat) {
const [, , message] = mat;
@ -28,8 +47,8 @@ export class Parser extends RawDiagnosticParser {
};
return FeedLineResult.Ok;
}
if (this._pendingTemplateError) {
// Detect the second line of a pending C++ template error
mat = /(.*):(\d+):(\d+):( +required from.+)/.exec(line);
if (mat) {
const [, file, linestr, column, message] = mat;
@ -43,7 +62,7 @@ export class Parser extends RawDiagnosticParser {
}
}
// Early-catch backtrace limit notes
// Detect backtrace limit notes in GCC diagnostics and append them to the previous diagnostic if one exists
mat = /note: \((.*backtrace-limit.*)\)/.exec(line);
if (mat && this._prevDiag && this._prevDiag.related.length !== 0) {
const prevRelated = this._prevDiag.related[0];
@ -55,47 +74,85 @@ export class Parser extends RawDiagnosticParser {
return FeedLineResult.Ok;
}
// Test if this is a diagnostic
mat = REGEX.exec(line);
if (!mat) {
// Nothing to see on this line of output...
// Attempt to parse a general diagnostic message using regex patterns defined in regexPatterns
let mat2 = null;
let full = "";
let file = "";
let lineno = oneLess("1");
let columnno = oneLess("1");
let severity = 'error';
let message = "";
for (const [, regexPattern] of regexPatterns.entries()) {
mat2 = line.match(regexPattern.regexPattern);
if (mat2 !== null) {
// For each matchType in the pattern, assign values accordingly
for (let i = 0; i < mat2.length; i++) {
switch (regexPattern.matchTypes[i]) {
case MatchType.Full:
full = mat2[i];
break;
case MatchType.File:
file = mat2[i];
break;
case MatchType.Line:
lineno = oneLess(mat2[i]);
break;
case MatchType.Column:
columnno = oneLess(mat2[i]);
break;
case MatchType.Severity:
severity = mat2[i];
break;
case MatchType.Message:
message = mat2[i];
break;
default:
break;
}
}
break;
}
}
if (!mat2) {
// Ignore this line because it is no matching diagnostic
return FeedLineResult.NotMine;
} else {
const [full, file, lineno_, column_, severity, message] = mat;
if (file && lineno_ && column_ && severity && message) {
const lineno = oneLess(lineno_);
const column = oneLess(column_);
if (severity === 'note' && this._prevDiag) {
this._prevDiag.related.push({
file,
location: new vscode.Range(lineno, column, lineno, 999),
message
});
return FeedLineResult.Ok;
} else {
const related: RawRelated[] = [];
const location = new vscode.Range(lineno, column, lineno, 999);
if (this._pendingTemplateError) {
related.push({
location,
file,
message: this._pendingTemplateError.rootInstantiation
});
related.push(...this._pendingTemplateError.requiredFrom);
this._pendingTemplateError = undefined;
}
return this._prevDiag = {
full,
file,
// If severity is "note", append the message to the previous diagnostic's related messages
if (severity === 'note' && this._prevDiag) {
this._prevDiag.related.push({
file,
location: new vscode.Range(lineno, columnno, lineno, 999),
message
});
return FeedLineResult.Ok;
} else {
const related: RawRelated[] = [];
const location = new vscode.Range(lineno, columnno, lineno, 999);
if (this._pendingTemplateError) {
// If the diagnostic is the third line of a pending C++ template error, finalize it here
related.push({
location,
severity,
message,
related
};
file,
message: this._pendingTemplateError.rootInstantiation
});
related.push(...this._pendingTemplateError.requiredFrom);
this._pendingTemplateError = undefined;
}
// Store and return the current diagnostic
return this._prevDiag = {
full,
file,
location,
severity,
message,
related
};
}
return FeedLineResult.NotMine;
}
}
}

Просмотреть файл

@ -4,33 +4,104 @@
import * as vscode from 'vscode';
import { FeedLineResult, oneLess, RawDiagnosticParser } from '@cmt/diagnostics/util';
import { oneLess, RawDiagnostic, RawDiagnosticParser, RawRelated, FeedLineResult, MatchType, RegexPattern } from '@cmt/diagnostics/util';
export const REGEX = /^(.*):(\d+)\s?:\s+(.*[^\]])$/;
// Patterns to identify and capture GNU linker diagnostic messages
const regexPatterns: RegexPattern[] = [
{ // path/to/ld[.exe]:[ ]path/to/file:line: severity: message
regexPattern: /^(?:.*ld(?:\.exe)?:)(?:\s*)?(.+):(\d+):\s+(?:fatal )?(\w+):\s+(.+)/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Line, MatchType.Severity, MatchType.Message]
},
{ // path/to/ld[.exe]:[ ]path/to/file:line: message
regexPattern: /^(?:.*ld(?:\.exe)?\:)(?:\s*)?(.+):(\d+):\s+(.+)/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Line, MatchType.Message]
},
{ // path/to/ld[.exe]: severity: message
regexPattern: /^(.*ld(?:\.exe)?):\s+(?:fatal )?(\w+):\s+(.+)/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Severity, MatchType.Message]
},
{ // path/to/ld[.exe]: message (without trailing colon)
regexPattern: /^(.*ld(?:\.exe)?):\s+(.+)(?<!:)$/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Message]
},
{ // /path/to/file:line: message (without "[fatal] severity:" or trailing colon)
regexPattern: /^(.+?):(\d+):\s+(?!fatal\s+\w+:)(?!\w+:)(.+)(?<!:)$/,
matchTypes: [MatchType.Full, MatchType.File, MatchType.Line, MatchType.Message]
}
];
export class Parser extends RawDiagnosticParser {
private _prevDiag?: RawDiagnostic;
doHandleLine(line: string) {
// Try to parse for GNU ld
if (line.startsWith('make')) {
// This is a Make error. It may *look* like an LD error, so we abort early
// Test if this is a diagnostic
let mat = null;
let full = "";
let file = "";
let lineno = oneLess("1");
let columnno = oneLess("1");
let severity = 'error';
let message = "foobar";
for (const [, regexPattern] of regexPatterns.entries()) {
mat = line.match(regexPattern.regexPattern);
if (mat !== null) {
// For each matchType in the pattern, assign values accordingly
for (let i = 0; i < mat.length; i++) {
switch (regexPattern.matchTypes[i]) {
case MatchType.Full:
full = mat[i];
break;
case MatchType.File:
file = mat[i];
break;
case MatchType.Line:
lineno = oneLess(mat[i]);
break;
case MatchType.Column:
columnno = oneLess(mat[i]);
break;
case MatchType.Severity:
severity = mat[i];
break;
case MatchType.Message:
message = mat[i];
break;
default:
break;
}
}
break;
}
}
if (!mat) {
// Ignore this line because it is no matching diagnostic
return FeedLineResult.NotMine;
} else {
// If severity is "note", append the message to the previous diagnostic's related messages
if (severity === 'note' && this._prevDiag) {
this._prevDiag.related.push({
file,
location: new vscode.Range(lineno, columnno, lineno, 999),
message
});
return FeedLineResult.Ok;
} else {
const related: RawRelated[] = [];
// Store and return the current diagnostic
return this._prevDiag = {
full,
file,
location: new vscode.Range(lineno, columnno, lineno, 999),
severity,
message,
related
};
}
}
const res = REGEX.exec(line);
if (!res) {
return FeedLineResult.NotMine;
}
const [full, file, lineno_, message] = res;
const lineno = oneLess(lineno_);
if (file && lineno && message) {
return {
full,
file,
location: new vscode.Range(lineno, 0, lineno, 999),
severity: 'error',
message,
related: []
};
}
return FeedLineResult.NotMine;
}
}

Просмотреть файл

@ -117,3 +117,23 @@ export abstract class RawDiagnosticParser {
*/
protected abstract doHandleLine(line: string): RawDiagnostic | FeedLineResult;
}
/**
* Match types for gcc related regex diagnostics
*/
export enum MatchType {
Full,
File,
Line,
Column,
Severity,
Message
}
/**
* Regex pattern interface for generic gcc related regex diagnostics
*/
export interface RegexPattern {
regexPattern: RegExp;
matchTypes: MatchType[];
}

Просмотреть файл

@ -206,20 +206,6 @@ suite('Diagnostics', () => {
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing fatal error diagnostics in french', () => {
const lines = ['/home/romain/TL/test/base.c:2:21: erreur fatale : bonjour.h : Aucun fichier ou dossier de ce type'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(1);
expect(diag.message).to.eq('bonjour.h : Aucun fichier ou dossier de ce type');
expect(diag.location.start.character).to.eq(20);
expect(diag.file).to.eq('/home/romain/TL/test/base.c');
expect(diag.severity).to.eq('erreur');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing warning diagnostics', () => {
const lines = ['/some/path/here:4:26: warning: unused parameter \'data\''];
feedLines(build_consumer, [], lines);
@ -246,20 +232,6 @@ suite('Diagnostics', () => {
expect(diag.message).to.eq(`unused parameter v [-Wunused-parameter]`);
expect(diag.severity).to.eq('warning');
});
test('Parsing warning diagnostics in french', () => {
const lines = ['/home/romain/TL/test/base.c:155:2: attention : déclaration implicite de la fonction create'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(154);
expect(diag.message).to.eq('déclaration implicite de la fonction create');
expect(diag.location.start.character).to.eq(1);
expect(diag.file).to.eq('/home/romain/TL/test/base.c');
expect(diag.severity).to.eq('attention');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing non-diagnostic', async () => {
const lines = ['/usr/include/c++/10/bits/stl_vector.h:98:47: optimized: basic block part vectorized using 32 byte vectors'];
feedLines(build_consumer, [], lines);
@ -267,32 +239,322 @@ suite('Diagnostics', () => {
const resolved = await build_consumer.resolveDiagnostics('dummyPath');
expect(resolved.length).to.eq(0);
});
test('Parsing linker error', () => {
const lines = ['/some/path/here:101: undefined reference to `some_function\''];
test('Parsing linker error of type "/path/to/ld:path/to/file:line: severity: message"', () => {
const lines = ['/path/to/ld:path/to/file:42: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuLD.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuLD.diagnostics[0];
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(100);
expect(diag.message).to.eq('undefined reference to `some_function\'');
expect(diag.file).to.eq('/some/path/here');
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld.exe:path/to/file:line: severity: message"', () => {
const lines = ['/path/to/ld.exe:path/to/file:42: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld: path/to/file:line: severity: message"', () => {
const lines = ['/path/to/ld: path/to/file:42: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld.exe: path/to/file:line: severity: message"', () => {
const lines = ['/path/to/ld.exe: path/to/file:42: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld:path/to/file:line: message"', () => {
const lines = ['/path/to/ld:path/to/file:42: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld.exe:path/to/file:line: message"', () => {
const lines = ['/path/to/ld.exe:path/to/file:42: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld: path/to/file:line: message"', () => {
const lines = ['/path/to/ld: path/to/file:42: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld.exe: path/to/file:line: message"', () => {
const lines = ['/path/to/ld.exe: path/to/file:42: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('path/to/file');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.false;
});
test('Parsing linker error of type "/path/to/ld: severity: message"', () => {
const lines = ['/path/to/ld: error: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/ld');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing linker error in french', () => {
const lines = ['/home/romain/TL/test/test_fa_tp4.c:9 : référence indéfinie vers « create_automaton_product56 »'];
test('Parsing linker error of type "/path/to/ld.exe: severity: message"', () => {
const lines = ['/path/to/ld.exe: warning: some message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuLD.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuLD.diagnostics[0];
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(8);
expect(diag.message).to.eq('référence indéfinie vers « create_automaton_product56 »');
expect(diag.file).to.eq('/home/romain/TL/test/test_fa_tp4.c');
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('some message');
expect(diag.file).to.eq('/path/to/ld.exe');
expect(diag.severity).to.eq('warning');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing linker error of type "/path/to/ld: message (without trailing colon)"', () => {
const lines = ['/path/to/ld: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/ld');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing linker error of type "/path/to/ld.exe: message (without trailing colon)"', () => {
const lines = ['/path/to/ld.exe: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/ld.exe');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing linker error of type "/path/to/file:line: message (without "[fatal] severity:" or trailing colon)"', () => {
const lines = ['/path/to/file:42: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gnuld.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/file');
expect(diag.severity).to.eq('error');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing gcc error of type "/path/to/file:line:column: severity: message"', () => {
const lines = ['/path/to/file:42:24: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(23);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/file');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing gcc error of type "/path/to/file:line: severity: message"', () => {
const lines = ['/path/to/file:42: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(41);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/file');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing gcc error of type "/path/to/cc1: severity: message"', () => {
const lines = ['/path/to/cc1: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/cc1');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing gcc error of type "/path/to/cc1.exe: severity: message"', () => {
const lines = ['/path/to/cc1.exe: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/cc1.exe');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing gcc error of type "/path/to/arm-none-eabi-gcc: severity: message"', () => {
const lines = ['/path/to/arm-none-eabi-gcc: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/arm-none-eabi-gcc');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parsing gcc error of type "/path/to/arm-none-eabi-gcc.exe: severity: message"', () => {
const lines = ['/path/to/arm-none-eabi-gcc.exe: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
const diag = build_consumer.compilers.gcc.diagnostics[0];
expect(diag.location.start.line).to.eq(0);
expect(diag.location.start.character).to.eq(0);
expect(diag.message).to.eq('message');
expect(diag.file).to.eq('/path/to/arm-none-eabi-gcc.exe');
expect(diag.severity).to.eq('severity');
expect(path.posix.normalize(diag.file)).to.eq(diag.file);
expect(path.posix.isAbsolute(diag.file)).to.be.true;
});
test('Parse GCC error on line zero', () => {
const lines = ['/foo.h:66:0: warning: ignoring #pragma comment [-Wunknown-pragmas]'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
expect(build_consumer.compilers.gcc.diagnostics[0].file).to.eq('/foo.h');
expect(build_consumer.compilers.gcc.diagnostics[0].location.start.line).to.eq(65);
expect(build_consumer.compilers.gcc.diagnostics[0].location.start.character).to.eq(0);
});
test('No gcc and linker error on "/path/to/ld: message:" (trailing colon)', () => {
const lines = ['/path/to/ld: message:'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(0);
});
test('No gcc and linker error on "/path/to/ld.exe: message:" (trailing colon)', () => {
const lines = ['/path/to/ld.exe: message:'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(0);
});
test('No gcc and linker error on "/path/to/file:line:column severity: message" (missing colon after column)', () => {
const lines = ['path/to/file:42:24 severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(0);
});
test('No gcc and linker error on "/path/to/file:line severity: message" (missing colon after line)', () => {
const lines = ['path/to/file:42 severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(0);
});
test('No linker error on "/path/to/file:line: severity: message" ("severity:" is gcc diagnostic)', () => {
const lines = ['/path/to/file:42: severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
});
test('No linker error on "/path/to/file:line: fatal severity: message" ("fatal severity:" is gcc diagnostic)', () => {
const lines = ['/path/to/file:42: fatal severity: message'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
});
test('No gcc and linker error on "/path/to/file:line: message:" (trailing colon)', () => {
const lines = ['/path/to/file:42: message:'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
expect(build_consumer.compilers.gnuld.diagnostics).to.have.length(0);
});
test('Parsing GHS Diagnostics', () => {
const lines = [
'"C:\\path\\source\\debug\\debug.c", line 631 (col. 3): warning #68-D: integer conversion resulted in a change of sign'
@ -400,16 +662,7 @@ suite('Diagnostics', () => {
`make: *** [Makefile:84 all] Error 2`
];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gnuLD.diagnostics).to.have.length(0);
});
test('Parse GCC error on line zero', () => {
const lines = ['/foo.h:66:0: warning: ignoring #pragma comment [-Wunknown-pragmas]'];
feedLines(build_consumer, [], lines);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(1);
expect(build_consumer.compilers.gcc.diagnostics[0].file).to.eq('/foo.h');
expect(build_consumer.compilers.gcc.diagnostics[0].location.start.line).to.eq(65);
expect(build_consumer.compilers.gcc.diagnostics[0].location.start.character).to.eq(0);
expect(build_consumer.compilers.gcc.diagnostics).to.have.length(0);
});
test('Parse MSVC single proc error', () => {