@@ -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 * # i f \s + (?: 0 | " 0 " ) (?: $ | \s ) / i;
238+ const ifZeroEnd = / ^ \s * # e l s e i f \s + | (?: # e l s e | # e n d i f ) (?: $ | \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 / ^ \$ z u ( t i l ) ? $ / 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