Skip to content

Commit 5cf032a

Browse files
committed
Fixes #387
1 parent dedde3f commit 5cf032a

File tree

3 files changed

+53
-32
lines changed

3 files changed

+53
-32
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## [2.8.1] - 2025-XX-XX
44
- Fix issue [#381](https://github.com/intersystems/language-server/issues/381): Fix extension crashes due to request forwarding
55
- Fix issue [#386](https://github.com/intersystems/language-server/issues/386): No folding range added for methods with `Language = python` on Windows
6+
- Fix issue [#387](https://github.com/intersystems/language-server/issues/387): Add warning Diagnostic when value of the DEFAULTGLOBAL Parameter in a persistent class is not a valid global name prefixed by a caret
67

78
## [2.8.0] - 2025-07-28
89
- Fix issue [#378](https://github.com/intersystems/language-server/issues/378): Remove `intersystems.language-server.completion.showInternal` setting

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This is a [LSP](https://microsoft.github.io/language-server-protocol/) compliant
2626
- Classes, Methods, Parameters and Properties that are [Deprecated](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=ROBJ_method_deprecated).
2727
- `$ZUTIL` functions that [are deprecated or have been superseded](https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_replacements).
2828
- [SQL reserved words](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RSQL_reservedwords) used in class and property names of persistent classes.
29+
- The value of the DEFAULTGLOBAL Parameter in a persistent class is not a valid global name prefixed by a caret.
2930
- [Folding Ranges](https://code.visualstudio.com/docs/editor/codebasics#_folding) for the following:
3031
- ObjectScript code blocks (If/ElseIf/Else, Try/Catch, For, While, etc.)
3132
- Class members

server/src/providers/diagnostic.ts

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
337337
else if (
338338
parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_clsname_attrindex &&
339339
j !== 0 && parsed[i][j-1].l == ld.cls_langindex && parsed[i][j-1].s == ld.cls_keyword_attrindex &&
340-
doc.getText(Range.create(
341-
Position.create(i,parsed[i][j-1].p),
342-
Position.create(i,parsed[i][j-1].p+parsed[i][j-1].c)
343-
)).toLowerCase() === "class"
340+
doc.getText(Range.create(i,parsed[i][j-1].p,i,parsed[i][j-1].p+parsed[i][j-1].c)).toLowerCase() === "class"
344341
) {
345342
// This is the class name in the class definition line
346343

@@ -404,17 +401,50 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
404401
}
405402
else if (
406403
j === 0 && parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_keyword_attrindex &&
407-
doc.getText(Range.create(Position.create(i,0),Position.create(i,9))).toLowerCase() === "parameter" &&
404+
doc.getText(Range.create(i,parsed[i][j].p,i,parsed[i][j].p+parsed[i][j].c)).toLowerCase() === "parameter" &&
408405
settings.diagnostics.parameters
409406
) {
410407
// This line is a UDL Parameter definition
408+
409+
const endsWithSemi =
410+
parsed[i][parsed[i].length-1].l == ld.cls_langindex &&
411+
parsed[i][parsed[i].length-1].s == ld.cls_delim_attrindex &&
412+
doc.getText(Range.create(i,parsed[i][parsed[i].length-1].p,i,parsed[i][parsed[i].length-1].p+parsed[i][parsed[i].length-1].c)) == ";";
413+
if (isPersistent && parsed[i].length > 3 && doc.getText(Range.create(i,parsed[i][1].p,i,parsed[i][1].p+parsed[i][1].c)) == "DEFAULTGLOBAL") {
414+
// Check if the provided value is a valid global name, with leading caret
415+
let inKeywords = false;
416+
for (let tkn = 2; tkn < parsed[i].length; tkn++) {
417+
if (parsed[i][tkn].l == ld.cls_langindex && parsed[i][tkn].s == ld.cls_delim_attrindex) {
418+
const delim = doc.getText(Range.create(i,parsed[i][tkn].p,i,parsed[i][tkn].p+parsed[i][tkn].c));
419+
if (inKeywords && delim == "]") {
420+
inKeywords = false;
421+
} else if (!inKeywords && delim == "[") {
422+
inKeywords = true;
423+
} else if (!inKeywords && delim == "=" && tkn < (parsed[i].length - 1)) {
424+
const valueEndTkn = parsed[i].length - (endsWithSemi ? 2 : 1);
425+
const valueRange = Range.create(i,parsed[i][tkn+1].p,i,parsed[i][valueEndTkn].p+parsed[i][valueEndTkn].c);
426+
const valueText = doc.getText(valueRange);
427+
if (!valueText.startsWith("{") && !/^"\^[%\x41-\xFF]([\x41-\xFF\d.]*[\x41-\xFF\d])?"$/.test(valueText)) {
428+
// The value is neither a valid global name nor a compile-time expression
429+
diagnostics.push({
430+
severity: DiagnosticSeverity.Warning,
431+
range: valueRange,
432+
message: "DEFAULTGLOBAL Parameter value should be a valid global name prefixed by a caret",
433+
source: 'InterSystems Language Server'
434+
});
435+
}
436+
break;
437+
}
438+
}
439+
}
440+
}
411441
if (
412442
parsed[i].length > 3 &&
413443
parsed[i][2].l == ld.cls_langindex && parsed[i][2].s === ld.cls_keyword_attrindex &&
414-
doc.getText(Range.create(Position.create(i,parsed[i][2].p),Position.create(i,parsed[i][2].p+parsed[i][2].c))).toLowerCase() === "as"
444+
doc.getText(Range.create(i,parsed[i][2].p,i,parsed[i][2].p+parsed[i][2].c)).toLowerCase() === "as"
415445
) {
416446
// This Parameter has a type
417-
const tokenrange = Range.create(Position.create(i,parsed[i][3].p),Position.create(i,parsed[i][3].p+parsed[i][3].c));
447+
const tokenrange = Range.create(i,parsed[i][3].p,i,parsed[i][3].p+parsed[i][3].c);
418448
const tokentext = doc.getText(tokenrange).toUpperCase();
419449
const thistypedoc = parameterTypes.find((typedoc) => typedoc.name === tokentext);
420450
if (thistypedoc === undefined) {
@@ -426,39 +456,28 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
426456
source: 'InterSystems Language Server'
427457
});
428458
}
429-
else {
459+
else if (parsed[i].length > 4) {
430460
// The type is valid
431461

432462
// See if this Parameter has a value
433-
if (parsed[i].length <= 4) {
434-
continue;
435-
}
436-
var valuetkn = -1;
437-
const delimtext = doc.getText(Range.create(Position.create(i,parsed[i][4].p),Position.create(i,parsed[i][4].p+parsed[i][4].c)));
463+
let valuetkn: number;
464+
const delimtext = doc.getText(Range.create(i,parsed[i][4].p,i,parsed[i][4].p+parsed[i][4].c));
438465
if (delimtext === "[") {
439466
// Loop through the line to find the closing brace
440-
441-
var closingtkn = -1;
467+
let closingtkn: number;
442468
for (let ptkn = 5; ptkn < parsed[i].length; ptkn++) {
443469
if (
444470
parsed[i][ptkn].l == ld.cls_langindex && parsed[i][ptkn].s === ld.cls_delim_attrindex &&
445-
doc.getText(Range.create(
446-
Position.create(i,parsed[i][ptkn].p),
447-
Position.create(i,parsed[i][ptkn].p+parsed[i][ptkn].c)
448-
)) === "]"
471+
doc.getText(Range.create(i,parsed[i][ptkn].p,i,parsed[i][ptkn].p+parsed[i][ptkn].c)) === "]"
449472
) {
450473
closingtkn = ptkn;
451474
break;
452475
}
453476
}
454-
455477
// Check if the token following the closing brace is =
456478
if (
457-
closingtkn !== -1 && parsed[i].length > closingtkn &&
458-
doc.getText(Range.create(
459-
Position.create(i,parsed[i][closingtkn+1].p),
460-
Position.create(i,parsed[i][closingtkn+1].p+parsed[i][closingtkn+1].c)
461-
)) === "="
479+
closingtkn && parsed[i].length > closingtkn &&
480+
doc.getText(Range.create(i,parsed[i][closingtkn+1].p,i,parsed[i][closingtkn+1].p+parsed[i][closingtkn+1].c)) === "="
462481
) {
463482
// There is a value following the =
464483
valuetkn = closingtkn + 2;
@@ -472,9 +491,10 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
472491
// Delimiter is a ; so there isn't a value to evaluate
473492
}
474493

475-
if (valuetkn !== -1 && parsed[i].length > valuetkn+1) {
476-
const valtext = doc.getText(Range.create(Position.create(i,parsed[i][valuetkn].p),Position.create(i,parsed[i][valuetkn].p+parsed[i][valuetkn].c)));
477-
const valrange = Range.create(Position.create(i,parsed[i][valuetkn].p),Position.create(i,parsed[i][parsed[i].length-2].p+parsed[i][parsed[i].length-2].c));
494+
if (valuetkn && parsed[i].length > valuetkn+1) {
495+
const valueEndTkn = parsed[i].length - (endsWithSemi ? 2 : 1);
496+
const valtext = doc.getText(Range.create(i,parsed[i][valuetkn].p,i,parsed[i][valuetkn].p+parsed[i][valuetkn].c));
497+
const valrange = Range.create(i,parsed[i][valuetkn].p,i,parsed[i][valueEndTkn].p+parsed[i][valueEndTkn].c);
478498
if (
479499
(thistypedoc.name === "STRING" && (parsed[i][valuetkn].l !== ld.cls_langindex || parsed[i][valuetkn].s !== ld.cls_str_attrindex)) ||
480500
(thistypedoc.name === "COSEXPRESSION" && (parsed[i][valuetkn].l !== ld.cls_langindex || parsed[i][valuetkn].s !== ld.cls_str_attrindex)) ||
@@ -541,7 +561,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
541561
}
542562
else if (
543563
j === 0 && parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_keyword_attrindex &&
544-
doc.getText(Range.create(Position.create(i,0),Position.create(i,6))).toLowerCase() === "import"
564+
doc.getText(Range.create(i,parsed[i][j].p,i,parsed[i][j].p+parsed[i][j].c)).toLowerCase() === "import"
545565
) {
546566
// This is the UDL Import line
547567

@@ -1033,9 +1053,8 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise<D
10331053
}
10341054
else if (
10351055
j == 0 && parsed[i][j].l == ld.cls_langindex && parsed[i][j].s == ld.cls_keyword_attrindex &&
1036-
isPersistent && parsed[i].length > 2 && (
1037-
doc.getText(Range.create(i,0,i,8)).toLowerCase() == "property" ||
1038-
doc.getText(Range.create(i,0,i,12)).toLowerCase() == "relationship"
1056+
isPersistent && parsed[i].length > 2 && ["property","relationship"].includes(
1057+
doc.getText(Range.create(i,parsed[i][j].p,i,parsed[i][j].p+parsed[i][j].c)).toLowerCase()
10391058
)
10401059
) {
10411060
// This is the start of a UDL Property definition

0 commit comments

Comments
 (0)