Skip to content

Commit 8652645

Browse files
committed
allow for problem patterns that address whole files
1 parent 36680ab commit 8652645

2 files changed

Lines changed: 334 additions & 7 deletions

File tree

src/vs/platform/markers/common/problemMatcher.ts

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,30 @@ export module FileLocationKind {
4242
}
4343
}
4444

45+
46+
export enum ProblemLocationKind {
47+
File,
48+
Location
49+
}
50+
51+
export module ProblemLocationKind {
52+
export function fromString(value: string): ProblemLocationKind {
53+
value = value.toLowerCase();
54+
if (value === 'file') {
55+
return ProblemLocationKind.File;
56+
} else if (value === 'location') {
57+
return ProblemLocationKind.Location;
58+
} else {
59+
return undefined;
60+
}
61+
}
62+
}
63+
4564
export interface ProblemPattern {
4665
regexp: RegExp;
4766

67+
kind?: ProblemLocationKind;
68+
4869
file?: number;
4970

5071
message?: number;
@@ -138,6 +159,7 @@ interface Location {
138159
}
139160

140161
interface ProblemData {
162+
kind?: ProblemLocationKind;
141163
file?: string;
142164
location?: string;
143165
line?: string;
@@ -353,6 +375,9 @@ class SingleLineMatcher extends AbstractLineMatcher {
353375
public handle(lines: string[], start: number = 0): HandleResult {
354376
Assert.ok(lines.length - start === 1);
355377
let data: ProblemData = Object.create(null);
378+
if (this.pattern.kind) {
379+
data.kind = this.pattern.kind;
380+
}
356381
let matches = this.pattern.regexp.exec(lines[start]);
357382
if (matches) {
358383
this.fillProblemData(data, this.pattern, matches);
@@ -387,6 +412,7 @@ class MultiLineMatcher extends AbstractLineMatcher {
387412
Assert.ok(lines.length - start === this.patterns.length);
388413
this.data = Object.create(null);
389414
let data = this.data;
415+
data.kind = this.patterns[0].kind;
390416
for (let i = 0; i < this.patterns.length; i++) {
391417
let pattern = this.patterns[i];
392418
let matches = pattern.regexp.exec(lines[i + start]);
@@ -431,6 +457,14 @@ export namespace Config {
431457
*/
432458
regexp?: string;
433459

460+
/**
461+
* Whether the pattern matches a whole file, or a location (file/line)
462+
*
463+
* The default is to match for a location. Only valid on the
464+
* first problem pattern in a multi line problem matcher.
465+
*/
466+
kind?: string;
467+
434468
/**
435469
* The match group index of the filename.
436470
* If omitted 1 is used.
@@ -696,7 +730,7 @@ export namespace Config {
696730
}
697731
}
698732

699-
class ProblemPatternParser extends Parser {
733+
export class ProblemPatternParser extends Parser {
700734

701735
constructor(logger: IProblemReporter) {
702736
super(logger);
@@ -724,6 +758,9 @@ class ProblemPatternParser extends Parser {
724758

725759
private createSingleProblemPattern(value: Config.ProblemPattern): ProblemPattern {
726760
let result = this.doCreateSingleProblemPattern(value, true);
761+
if (result.kind === undefined) {
762+
result.kind = ProblemLocationKind.Location;
763+
}
727764
return this.validateProblemPattern([result]) ? result : null;
728765
}
729766

@@ -748,13 +785,19 @@ class ProblemPatternParser extends Parser {
748785
}
749786
result.push(pattern);
750787
}
788+
if (result[0].kind === undefined) {
789+
result[0].kind = ProblemLocationKind.Location;
790+
}
751791
return this.validateProblemPattern(result) ? result : null;
752792
}
753793

754794
private doCreateSingleProblemPattern(value: Config.ProblemPattern, setDefaults: boolean): ProblemPattern {
755795
let result: ProblemPattern = {
756-
regexp: this.createRegularExpression(value.regexp)
796+
regexp: this.createRegularExpression(value.regexp),
757797
};
798+
if (value.kind) {
799+
result.kind = ProblemLocationKind.fromString(value.kind);
800+
}
758801

759802
function copyProperty(result: ProblemPattern, source: Config.ProblemPattern, resultKey: keyof ProblemPattern, sourceKey: keyof Config.ProblemPattern) {
760803
let value = source[sourceKey];
@@ -775,7 +818,7 @@ class ProblemPatternParser extends Parser {
775818
result.loop = value.loop;
776819
}
777820
if (setDefaults) {
778-
if (result.location) {
821+
if (result.location || result.kind === ProblemLocationKind.File) {
779822
let defaultValue: Partial<ProblemPattern> = {
780823
file: 1,
781824
message: 0
@@ -797,7 +840,12 @@ class ProblemPatternParser extends Parser {
797840
private validateProblemPattern(values: ProblemPattern[]): boolean {
798841
let file: boolean, message: boolean, location: boolean, line: boolean;
799842
let regexp: number = 0;
800-
values.forEach(pattern => {
843+
let locationKind = (values[0].kind === undefined) ? ProblemLocationKind.Location : values[0].kind;
844+
845+
values.forEach((pattern, i) => {
846+
if (i !== 0 && pattern.kind) {
847+
this.error(localize('ProblemPatternParser.problemPattern.kindProperty.notFirst', 'The problem pattern is invalid. The kind property must be provided only in the first element'));
848+
}
801849
file = file || !Types.isUndefined(pattern.file);
802850
message = message || !Types.isUndefined(pattern.message);
803851
location = location || !Types.isUndefined(pattern.location);
@@ -810,8 +858,12 @@ class ProblemPatternParser extends Parser {
810858
this.error(localize('ProblemPatternParser.problemPattern.missingRegExp', 'The problem pattern is missing a regular expression.'));
811859
return false;
812860
}
813-
if (!(file && message && (location || line))) {
814-
this.error(localize('ProblemPatternParser.problemPattern.missingProperty', 'The problem pattern is invalid. It must have at least a file, message and line or location match group.'));
861+
if (!(file && message)) {
862+
this.error(localize('ProblemPatternParser.problemPattern.missingProperty', 'The problem pattern is invalid. It must have at least have a file and a message.'));
863+
return false;
864+
}
865+
if (locationKind === ProblemLocationKind.Location && !(location || line)) {
866+
this.error(localize('ProblemPatternParser.problemPattern.missingLocation', 'The problem pattern is invalid. It must either have kind: "file" or have a line or location match group.'));
815867
return false;
816868
}
817869
return true;
@@ -876,6 +928,10 @@ export namespace Schemas {
876928
type: 'string',
877929
description: localize('ProblemPatternSchema.regexp', 'The regular expression to find an error, warning or info in the output.')
878930
},
931+
kind: {
932+
type: 'string',
933+
description: localize('ProblemPatternSchema.kind', 'whether the pattern matches a location (file and line) or only a file.')
934+
},
879935
file: {
880936
type: 'integer',
881937
description: localize('ProblemPatternSchema.file', 'The match group index of the filename. If omitted 1 is used.')
@@ -1026,6 +1082,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10261082
private fillDefaults(): void {
10271083
this.add('msCompile', {
10281084
regexp: /^(?:\s+\d+\>)?([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\)\s*:\s+(error|warning|info)\s+(\w{1,2}\d+)\s*:\s*(.*)$/,
1085+
kind: ProblemLocationKind.Location,
10291086
file: 1,
10301087
location: 2,
10311088
severity: 3,
@@ -1034,13 +1091,15 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10341091
});
10351092
this.add('gulp-tsc', {
10361093
regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(\d+)\s+(.*)$/,
1094+
kind: ProblemLocationKind.Location,
10371095
file: 1,
10381096
location: 2,
10391097
code: 3,
10401098
message: 4
10411099
});
10421100
this.add('cpp', {
10431101
regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(error|warning|info)\s+(C\d+)\s*:\s*(.*)$/,
1102+
kind: ProblemLocationKind.Location,
10441103
file: 1,
10451104
location: 2,
10461105
severity: 3,
@@ -1049,6 +1108,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10491108
});
10501109
this.add('csc', {
10511110
regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(error|warning|info)\s+(CS\d+)\s*:\s*(.*)$/,
1111+
kind: ProblemLocationKind.Location,
10521112
file: 1,
10531113
location: 2,
10541114
severity: 3,
@@ -1057,6 +1117,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10571117
});
10581118
this.add('vb', {
10591119
regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(error|warning|info)\s+(BC\d+)\s*:\s*(.*)$/,
1120+
kind: ProblemLocationKind.Location,
10601121
file: 1,
10611122
location: 2,
10621123
severity: 3,
@@ -1065,12 +1126,14 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10651126
});
10661127
this.add('lessCompile', {
10671128
regexp: /^\s*(.*) in file (.*) line no. (\d+)$/,
1129+
kind: ProblemLocationKind.Location,
10681130
message: 1,
10691131
file: 2,
10701132
line: 3
10711133
});
10721134
this.add('jshint', {
10731135
regexp: /^(.*):\s+line\s+(\d+),\s+col\s+(\d+),\s(.+?)(?:\s+\((\w)(\d+)\))?$/,
1136+
kind: ProblemLocationKind.Location,
10741137
file: 1,
10751138
line: 2,
10761139
character: 3,
@@ -1081,6 +1144,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10811144
this.add('jshint-stylish', [
10821145
{
10831146
regexp: /^(.+)$/,
1147+
kind: ProblemLocationKind.Location,
10841148
file: 1
10851149
},
10861150
{
@@ -1096,6 +1160,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
10961160
this.add('eslint-compact', {
10971161
regexp: /^(.+):\sline\s(\d+),\scol\s(\d+),\s(Error|Warning|Info)\s-\s(.+)\s\((.+)\)$/,
10981162
file: 1,
1163+
kind: ProblemLocationKind.Location,
10991164
line: 2,
11001165
character: 3,
11011166
severity: 4,
@@ -1105,6 +1170,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
11051170
this.add('eslint-stylish', [
11061171
{
11071172
regexp: /^([^\s].*)$/,
1173+
kind: ProblemLocationKind.Location,
11081174
file: 1
11091175
},
11101176
{
@@ -1119,6 +1185,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry {
11191185
]);
11201186
this.add('go', {
11211187
regexp: /^([^:]*: )?((.:)?[^:]*):(\d+)(:(\d+))?: (.*)$/,
1188+
kind: ProblemLocationKind.Location,
11221189
file: 2,
11231190
line: 4,
11241191
character: 6,
@@ -1369,7 +1436,7 @@ export namespace Schemas {
13691436
description: localize('PatternTypeSchema.name', 'The name of a contributed or predefined pattern')
13701437
},
13711438
Schemas.ProblemPattern,
1372-
Schemas.MultLileProblemPattern
1439+
Schemas.MultiLineProblemPattern
13731440
],
13741441
description: localize('PatternTypeSchema.description', 'A problem pattern or the name of a contributed or predefined problem pattern. Can be omitted if base is specified.')
13751442
};

0 commit comments

Comments
 (0)