Skip to content

Commit 0fd2785

Browse files
committed
Fixes #371
1 parent 212a1ba commit 0fd2785

File tree

2 files changed

+49
-31
lines changed

2 files changed

+49
-31
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Fix issue [#366](https://github.com/intersystems/language-server/issues/366): Language Server can return invalid DocumentSymbols in some rare circumstances
55
- Fix issue [#367](https://github.com/intersystems/language-server/issues/367): Support `objectscript.multilineMethodArgs` being set per workspace folder
66
- Fix issue [#370](https://github.com/intersystems/language-server/issues/370): Infinite recursion when a variable is set to the result of one of its instance methods
7+
- Fix issue [#371](https://github.com/intersystems/language-server/issues/371): Don't report problems for code enclosed in `#if 0` blocks
78
- Parser changes:
89
- DP-438845, DP-440271: Support new keywords for deferred filing of indices and computed fields
910

server/src/providers/diagnostic.ts

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
208208
}
209209
}
210210

211-
const startline: number = (firstlineisroutine) ? 1 : 0;
211+
const startline = firstlineisroutine ? 1 : 0;
212212

213213
// Store the name, class and ranges for all class members that we see if settings.diagnostics.deprecation is true
214214
// Map keys are of the form "class:::member", except for classes
@@ -231,15 +231,40 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
231231
// try to combine error tokens that aren't for the same underlying error.
232232
let lastErrWasWhitespace = false;
233233

234+
// Don't report diagnostics in a #if 0 block, and
235+
// mark all of the code in the block as "unused"
236+
let ifZeroStartPos: Position;
237+
const ifZeroStart = /^\s*#if\s+(?:0|"0")(?:$|\s)/i;
238+
const ifZeroEnd = /^\s*#elseif\s+|(?:#else|#endif)(?:$|\s)/i;
239+
234240
// Loop through the parsed document to find errors and warnings
235241
for (let i = startline; i < parsed.length; i++) {
236242

243+
const lineText = doc.getText(Range.create(i,0,i+1,0));
244+
if (doc.languageId != "objectscript-int" && !ifZeroStartPos) {
245+
const ifZeroStartMatch = lineText.match(ifZeroStart);
246+
if (ifZeroStartMatch) {
247+
ifZeroStartPos = Position.create(i,ifZeroStartMatch[0].length);
248+
continue; // No more diagnostics on this line
249+
}
250+
} else if (ifZeroStartPos && ifZeroEnd.test(lineText)) {
251+
if (i > (ifZeroStartPos.line + 1)) diagnostics.push({
252+
severity: DiagnosticSeverity.Hint,
253+
range: Range.create(ifZeroStartPos,Position.create(i,0)),
254+
message: "Unused code detected",
255+
tags: [DiagnosticTag.Unnecessary],
256+
source: 'InterSystems Language Server'
257+
});
258+
ifZeroStartPos = undefined;
259+
continue; // No more diagnostics on this line
260+
}
261+
237262
// Loop through the line's tokens
238263
for (let j = 0; j < parsed[i].length; j++) {
239264
const symbolstart: number = parsed[i][j].p;
240265
const symbolend: number = parsed[i][j].p + parsed[i][j].c;
241266

242-
if (j > 0 && parsed[i][j].l === parsed[i][j-1].l && parsed[i][j].s === parsed[i][j-1].s) {
267+
if (j > 0 && parsed[i][j].l === parsed[i][j-1].l && parsed[i][j].s === parsed[i][j-1].s && !ifZeroStartPos) {
243268
// This token is the same as the last
244269

245270
if (parsed[i][j].s === ld.error_attrindex && reportSyntaxErrors(parsed[i][j].l)) {
@@ -274,7 +299,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
274299
}
275300
}
276301
else {
277-
if (parsed[i][j].s === ld.error_attrindex && reportSyntaxErrors(parsed[i][j].l)) {
302+
if (parsed[i][j].s === ld.error_attrindex && reportSyntaxErrors(parsed[i][j].l) && !ifZeroStartPos) {
278303
// This is an error token
279304
const errorRange = Range.create(i,symbolstart,i,symbolend);
280305
// Don't create a diagnostic for this error if it's just whitespace.
@@ -296,17 +321,17 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
296321
else if (
297322
parsed[i][j].l == ld.cos_langindex &&
298323
parsed[i][j].s == ld.cos_otw_attrindex &&
299-
settings.diagnostics.undefinedVariables
324+
settings.diagnostics.undefinedVariables &&
325+
!ifZeroStartPos
300326
) {
301327
// This is an OptionTrackWarning (unset local variable)
302328
const varrange = Range.create(Position.create(i,symbolstart),Position.create(i,symbolend));
303-
let diagnostic: Diagnostic = {
329+
diagnostics.push({
304330
severity: DiagnosticSeverity.Warning,
305331
range: varrange,
306332
message: `Local variable "${doc.getText(varrange)}" may be undefined`,
307333
source: 'InterSystems Language Server'
308-
};
309-
diagnostics.push(diagnostic);
334+
});
310335
}
311336
else if (
312337
parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_clsname_attrindex &&
@@ -393,13 +418,12 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
393418
const thistypedoc = parameterTypes.find((typedoc) => typedoc.name === tokentext);
394419
if (thistypedoc === undefined) {
395420
// The type is invalid
396-
let diagnostic: Diagnostic = {
421+
diagnostics.push({
397422
severity: DiagnosticSeverity.Warning,
398423
range: tokenrange,
399424
message: "Invalid parameter type",
400425
source: 'InterSystems Language Server'
401-
};
402-
diagnostics.push(diagnostic);
426+
});
403427
}
404428
else {
405429
// The type is valid
@@ -504,10 +528,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
504528
else {
505529
diagnostics.push({
506530
severity: DiagnosticSeverity.Error,
507-
range: {
508-
start: Position.create(i,parsed[i][ptkn].p),
509-
end: Position.create(i,parsed[i][ptkn].p+parsed[i][ptkn].c)
510-
},
531+
range: Range.create(i,parsed[i][ptkn].p,i,parsed[i][ptkn].p+parsed[i][ptkn].c),
511532
message: errorDesc,
512533
source: 'InterSystems Language Server'
513534
});
@@ -529,8 +550,8 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
529550
if (parsed[i][imptkn].s == ld.error_attrindex && reportSyntaxErrors(parsed[i][j].l)) {
530551
if (
531552
parsed[i][imptkn-1].s == ld.error_attrindex && !doc.getText(Range.create(
532-
Position.create(i,parsed[i][imptkn].p-1),
533-
Position.create(i,parsed[i][imptkn].p)
553+
i,parsed[i][imptkn].p-1,
554+
i,parsed[i][imptkn].p
534555
)).trim()
535556
) {
536557
// The previous token is an error without a space in between, so extend the existing syntax error Diagnostic to cover this token
@@ -539,10 +560,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
539560
else {
540561
diagnostics.push({
541562
severity: DiagnosticSeverity.Error,
542-
range: {
543-
start: Position.create(i,parsed[i][imptkn].p),
544-
end: Position.create(i,parsed[i][imptkn].p+parsed[i][imptkn].c)
545-
},
563+
range: Range.create(i,parsed[i][imptkn].p,i,parsed[i][imptkn].p+parsed[i][imptkn].c),
546564
message: syntaxError,
547565
source: 'InterSystems Language Server'
548566
});
@@ -562,7 +580,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
562580
diagnostics.push({
563581
severity: DiagnosticSeverity.Error,
564582
range: pkgrange,
565-
message: `No classes with package "${pkg}" exist in namespace "${baseNs}"`,
583+
message: `Package "${pkg}" does not exist in namespace "${baseNs}"`,
566584
source: 'InterSystems Language Server'
567585
});
568586
}
@@ -576,16 +594,16 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
576594
files.length > 0 &&
577595
((parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_clsname_attrindex) ||
578596
(parsed[i][j].l == ld.cos_langindex && parsed[i][j].s == ld.cos_clsname_attrindex)) &&
579-
(settings.diagnostics.classes || settings.diagnostics.deprecation)
597+
(settings.diagnostics.classes || settings.diagnostics.deprecation) && !ifZeroStartPos
580598
) {
581599
// This is a class name
582600

583601
// Don't validate a class name that follows the "Class" keyword
584602
if (j !== 0 && parsed[i][j-1].l == ld.cls_langindex && parsed[i][j-1].s == ld.cls_keyword_attrindex) {
585603
// The previous token is a UDL keyword
586604
const prevkeytext = doc.getText(Range.create(
587-
Position.create(i,parsed[i][j-1].p),
588-
Position.create(i,parsed[i][j-1].p+parsed[i][j-1].c)
605+
i,parsed[i][j-1].p,
606+
i,parsed[i][j-1].p+parsed[i][j-1].c
589607
)).toLowerCase();
590608
if (prevkeytext === "class") {
591609
continue;
@@ -598,19 +616,18 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
598616
if (word.charAt(0) === ".") {
599617
// This might be $SYSTEM.ClassName
600618
const prevseven = doc.getText(Range.create(
601-
Position.create(i,wordrange.start.character-7),
602-
Position.create(i,wordrange.start.character)
619+
i,wordrange.start.character-7,
620+
i,wordrange.start.character
603621
));
604622
if (prevseven.toUpperCase() !== "$SYSTEM") {
605623
// This classname is invalid
606624
if (settings.diagnostics.classes) {
607-
let diagnostic: Diagnostic = {
625+
diagnostics.push({
608626
severity: DiagnosticSeverity.Error,
609627
range: wordrange,
610628
message: "Invalid class name",
611629
source: 'InterSystems Language Server'
612-
};
613-
diagnostics.push(diagnostic);
630+
});
614631
}
615632
continue;
616633
}
@@ -682,7 +699,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
682699
files.length > 0 &&
683700
((parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_rtnname_attrindex) ||
684701
(parsed[i][j].l == ld.cos_langindex && parsed[i][j].s == ld.cos_rtnname_attrindex)) &&
685-
settings.diagnostics.routines
702+
settings.diagnostics.routines && !ifZeroStartPos
686703
) {
687704
// This is a routine name
688705

@@ -798,7 +815,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
798815
}
799816
}
800817
else if (
801-
settings.diagnostics.zutil && parsed[i][j].l == ld.cos_langindex && parsed[i][j].s == ld.cos_sysf_attrindex &&
818+
settings.diagnostics.zutil && !ifZeroStartPos && parsed[i][j].l == ld.cos_langindex && parsed[i][j].s == ld.cos_sysf_attrindex &&
802819
/^\$zu(til)?$/i.test(doc.getText(Range.create(i,parsed[i][j].p,i,parsed[i][j].p+parsed[i][j].c))) && j < parsed[i].length - 1
803820
) {
804821
// This is a $ZUTIL call

0 commit comments

Comments
 (0)