11import { TextDocument } from 'vscode-languageserver-textdocument' ;
2- import { SemanticTokenModifiers , SemanticTokenTypes , SymbolInformation , SymbolKind } from 'vscode-languageserver' ;
2+ import { Diagnostic , SemanticTokenModifiers , SemanticTokenTypes , SymbolInformation , SymbolKind } from 'vscode-languageserver' ;
33import { AmbiguousIdentifierContext , ConstItemContext , EnumDeclarationContext , EnumMemberContext , FunctionDeclarationContext , ProcedureDeclarationContext , PropertyGetDeclarationContext , PropertySetDeclarationContext , ReservedMemberNameContext , SubroutineDeclarationContext , UdtDeclarationContext , UdtElementContext , UntypedNameContext , VariableDclContext } from '../../antlr/out/vbaParser' ;
44
5- import { BaseContextSyntaxElement , HasSemanticToken , HasSymbolInformation , IdentifiableSyntaxElement , NamedSyntaxElement } from './base' ;
5+ import { BaseContextSyntaxElement , HasDiagnosticCapability , HasSemanticToken , HasSymbolInformation , IdentifiableSyntaxElement , NamedSyntaxElement } from './base' ;
66
77import { ScopeElement } from './special' ;
8- import { VbaClassDocument , VbaModuleDocument } from '../document' ;
8+ import { BaseProjectDocument , VbaClassDocument , VbaModuleDocument } from '../document' ;
99import { SymbolInformationFactory } from '../../capabilities/symbolInformation' ;
1010import '../../extensions/parserExtensions' ;
11+ import { DuplicateDeclarationDiagnostic } from '../../capabilities/diagnostics' ;
1112
1213
1314
@@ -17,44 +18,59 @@ export class IdentifierElement extends BaseContextSyntaxElement {
1718 }
1819}
1920
20- export abstract class DeclarationElement extends ScopeElement {
21+ export abstract class DeclarationElement extends ScopeElement implements HasDiagnosticCapability {
22+ abstract diagnostics : Diagnostic [ ] ;
2123 abstract identifier : IdentifierElement ;
2224
2325 constructor ( context : ProcedureDeclarationContext , document : TextDocument ) {
2426 super ( context , document ) ;
2527 }
28+
29+ evaluateDiagnostics ( ) : void {
30+ return ;
31+ }
32+
2633 get name ( ) : string {
2734 throw new Error ( 'Method not implemented.' ) ;
2835 }
2936
3037 static create ( context : ProcedureDeclarationContext , document : VbaClassDocument | VbaModuleDocument ) {
3138 let methodContext : SubroutineDeclarationContext | FunctionDeclarationContext | PropertyGetDeclarationContext | null ;
39+
40+ // Create a sub if we have one.
3241 methodContext = context . subroutineDeclaration ( ) ;
3342 if ( methodContext ) {
3443 return new SubDeclarationElement ( context , document . textDocument , methodContext ) ;
3544 }
3645
46+ // Create a function if we have one.
3747 methodContext = context . functionDeclaration ( ) ;
3848 if ( methodContext ) {
3949 return new FunctionDeclarationElement ( context , document . textDocument , methodContext ) ;
4050 }
4151
52+ // Check if we already have a property with this name.
4253 const propertyDeclaration = new PropertyDeclarationElement ( context , document . textDocument ) ;
43- const predeclaredElements = document . currentScopeElement ?. declaredNames . get ( propertyDeclaration . identifier . text ) ;
44- predeclaredElements ?. forEach ( predeclaredElement => {
45- if ( predeclaredElement && isPropertyDeclarationElement ( predeclaredElement ) ) {
46- predeclaredElement . addPropertyDeclaration ( context , document . textDocument ) ;
47- return predeclaredElement ;
54+ const identifierText = propertyDeclaration . identifier . text ;
55+ const predeclaredElements = document . currentScopeElement ?. declaredNames . get ( identifierText ) ?? [ ] ;
56+
57+ // Add to an existing property rather than creating.
58+ for ( const element of predeclaredElements ) {
59+ if ( element . isPropertyElement ( ) && element . identifier . text === identifierText ) {
60+ element . addPropertyDeclaration ( context , document . textDocument ) ;
61+ return element ;
4862 }
49- } ) ;
63+ }
64+
65+ // Return a new property.
5066 return propertyDeclaration ;
5167 }
52-
5368}
5469
5570export class SubDeclarationElement extends DeclarationElement implements HasSymbolInformation {
5671 identifier : IdentifierElement ;
5772 symbolInformation : SymbolInformation ;
73+ diagnostics : Diagnostic [ ] = [ ] ;
5874
5975 constructor ( context : ProcedureDeclarationContext , document : TextDocument , methodContext : SubroutineDeclarationContext ) {
6076 super ( context , document ) ;
@@ -73,6 +89,7 @@ export class SubDeclarationElement extends DeclarationElement implements HasSymb
7389export class FunctionDeclarationElement extends DeclarationElement implements HasSymbolInformation {
7490 identifier : IdentifierElement ;
7591 symbolInformation : SymbolInformation ;
92+ diagnostics : Diagnostic [ ] = [ ] ;
7693
7794 constructor ( context : ProcedureDeclarationContext , document : TextDocument , methodContext : FunctionDeclarationContext ) {
7895 super ( context , document ) ;
@@ -89,11 +106,18 @@ export class FunctionDeclarationElement extends DeclarationElement implements Ha
89106
90107export class PropertyDeclarationElement extends DeclarationElement implements HasSymbolInformation {
91108 identifier : IdentifierElement ;
109+ diagnostics : Diagnostic [ ] = [ ] ;
92110 symbolInformation : SymbolInformation ;
93111 getDeclarations : PropertyGetDeclarationElement [ ] = [ ] ;
94112 letDeclarations : PropertyLetDeclarationElement [ ] = [ ] ;
95113 setDeclarations : PropertyLetDeclarationElement [ ] = [ ] ;
96114
115+ get countDeclarations ( ) : number {
116+ return this . getDeclarations . length
117+ + this . letDeclarations . length
118+ + this . setDeclarations . length ;
119+ }
120+
97121 constructor ( context : ProcedureDeclarationContext , document : TextDocument ) {
98122 super ( context , document ) ;
99123 this . identifier = this . addPropertyDeclaration ( context , document ) ;
@@ -105,6 +129,10 @@ export class PropertyDeclarationElement extends DeclarationElement implements Ha
105129 ) ;
106130 }
107131
132+ evaluateDiagnostics ( ) : void {
133+ this . _evaluateDuplicateDeclarationsDiagnostics ( ) ;
134+ }
135+
108136 addPropertyDeclaration ( context : ProcedureDeclarationContext , document : TextDocument ) {
109137 switch ( true ) {
110138 case ! ! context . propertyGetDeclaration ( ) :
@@ -121,10 +149,19 @@ export class PropertyDeclarationElement extends DeclarationElement implements Ha
121149 return this . setDeclarations [ 0 ] . identifier ;
122150 }
123151 }
152+
153+ private _evaluateDuplicateDeclarationsDiagnostics ( ) : void {
154+ [ this . getDeclarations , this . letDeclarations , this . setDeclarations ] . forEach ( declarations => {
155+ declarations . forEach ( ( declaration , i ) => {
156+ if ( i > 0 ) this . diagnostics . push ( new DuplicateDeclarationDiagnostic ( declaration . identifier . range ) ) ;
157+ } ) ;
158+ } ) ;
159+ }
124160}
125161
126162class PropertyGetDeclarationElement extends DeclarationElement {
127163 identifier : IdentifierElement ;
164+ diagnostics : Diagnostic [ ] = [ ] ;
128165
129166 constructor ( context : ProcedureDeclarationContext , document : TextDocument , getContext : PropertyGetDeclarationContext ) {
130167 super ( context , document ) ;
@@ -134,6 +171,7 @@ class PropertyGetDeclarationElement extends DeclarationElement {
134171
135172class PropertyLetDeclarationElement extends DeclarationElement {
136173 identifier : IdentifierElement ;
174+ diagnostics : Diagnostic [ ] = [ ] ;
137175
138176 constructor ( context : ProcedureDeclarationContext , document : TextDocument , setContext : PropertySetDeclarationContext ) {
139177 super ( context , document ) ;
@@ -143,17 +181,14 @@ class PropertyLetDeclarationElement extends DeclarationElement {
143181
144182class PropertySetDeclarationElement extends DeclarationElement {
145183 identifier : IdentifierElement ;
184+ diagnostics : Diagnostic [ ] = [ ] ;
146185
147186 constructor ( context : ProcedureDeclarationContext , document : TextDocument , setContext : PropertySetDeclarationContext ) {
148187 super ( context , document ) ;
149188 this . identifier = new IdentifierElement ( setContext . subroutineName ( ) ! . ambiguousIdentifier ( ) ! , document ) ;
150189 }
151190}
152191
153- function isPropertyDeclarationElement ( element : IdentifiableSyntaxElement ) : element is PropertyDeclarationElement {
154- return 'getDeclarations' in element ;
155- }
156-
157192abstract class BaseEnumDeclarationElement extends ScopeElement implements HasSemanticToken , HasSymbolInformation {
158193 identifier : IdentifierElement ;
159194 tokenModifiers : SemanticTokenModifiers [ ] = [ ] ;
@@ -181,7 +216,7 @@ export class EnumDeclarationElement extends BaseEnumDeclarationElement implement
181216 this . tokenType = SemanticTokenTypes . enum ;
182217 this . identifier = new IdentifierElement ( context . untypedName ( ) . ambiguousIdentifier ( ) ! , document ) ;
183218 context . enumMemberList ( ) . enumElement ( ) . forEach ( enumElementContext =>
184- this . _pushDeclaredName ( new EnumMemberDeclarationElement ( enumElementContext . enumMember ( ) ! , document ) )
219+ this . pushDeclaredName ( new EnumMemberDeclarationElement ( enumElementContext . enumMember ( ) ! , document ) )
185220 ) ;
186221 }
187222
@@ -228,6 +263,10 @@ abstract class BaseVariableDeclarationStatementElement extends BaseContextSyntax
228263 ) ;
229264 }
230265
266+ isPropertyElement ( ) : this is PropertyDeclarationElement {
267+ return false ;
268+ }
269+
231270 constructor ( context : VariableDclContext | ConstItemContext | UdtElementContext , document : TextDocument , tokenType : SemanticTokenTypes , symbolKind : SymbolKind ) {
232271 super ( context , document ) ;
233272 this . tokenType = tokenType ;
@@ -262,7 +301,7 @@ export class TypeDeclarationElement extends ScopeElement implements HasSemantic
262301 this . tokenType = SemanticTokenTypes . struct ;
263302 this . identifier = new IdentifierElement ( context . untypedName ( ) , document ) ;
264303 context . udtMemberList ( ) . udtElement ( ) . forEach ( member =>
265- this . _pushDeclaredName ( new TypeMemberDeclarationElement ( member , document ) )
304+ this . pushDeclaredName ( new TypeMemberDeclarationElement ( member , document ) )
266305 ) ;
267306 }
268307
0 commit comments