Skip to content

Commit 5f4937c

Browse files
committed
Refactor due to grammar update and enabled EnumOutOfPlaceDiagnostic
1 parent cf13f6c commit 5f4937c

File tree

5 files changed

+74
-56
lines changed

5 files changed

+74
-56
lines changed

package-lock.json

Lines changed: 5 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/src/capabilities/diagnostics.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,13 @@ export class MissingOptionExplicitDiagnostic extends BaseDiagnostic {
8282
constructor(range: Range) {
8383
super(range);
8484
}
85+
}
86+
87+
export class ElementOutOfPlaceDiagnostic extends BaseDiagnostic {
88+
message: string;
89+
severity = DiagnosticSeverity.Error;
90+
constructor(range: Range, elementName: string) {
91+
super(range);
92+
this.message = `${elementName}s cannot appear below a Sub, Function, or Property declaration.`
93+
}
8594
}

server/src/project/elements/memory.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ScopeElement } from './special';
88
import { VbaClassDocument, VbaModuleDocument } from '../document';
99
import { SymbolInformationFactory } from '../../capabilities/symbolInformation';
1010
import '../../extensions/parserExtensions';
11-
import { DuplicateDeclarationDiagnostic } from '../../capabilities/diagnostics';
11+
import { DuplicateDeclarationDiagnostic, ElementOutOfPlaceDiagnostic } from '../../capabilities/diagnostics';
1212

1313

1414

@@ -215,39 +215,49 @@ abstract class BaseEnumDeclarationElement extends ScopeElement implements HasSem
215215

216216
}
217217

218-
export class EnumDeclarationElement extends BaseEnumDeclarationElement implements ScopeElement {
218+
export class EnumDeclarationElement extends BaseEnumDeclarationElement implements ScopeElement, HasDiagnosticCapability {
219+
diagnostics: Diagnostic[] = [];
219220
tokenType: SemanticTokenTypes;
221+
isDeclaredAfterMethod: boolean;
222+
223+
get symbolInformation(): SymbolInformation {
224+
return SymbolInformationFactory.create(
225+
this, SymbolKind.Enum
226+
);
227+
}
220228

221-
constructor(context: EnumDeclarationContext, document: TextDocument) {
229+
constructor(context: EnumDeclarationContext, document: TextDocument, isDeclaredAfterMethod: boolean) {
222230
super(context, document);
223231
this.tokenType = SemanticTokenTypes.enum;
232+
this.isDeclaredAfterMethod = isDeclaredAfterMethod;
224233
this.identifier = new IdentifierElement(context.untypedName().ambiguousIdentifier()!, document);
225234
context.enumMemberList().enumElement().forEach(enumElementContext =>
226235
this.pushDeclaredName(new EnumMemberDeclarationElement(enumElementContext.enumMember()!, document))
227236
);
228237
}
229238

230-
get symbolInformation(): SymbolInformation {
231-
return SymbolInformationFactory.create(
232-
this, SymbolKind.Enum
233-
);
239+
evaluateDiagnostics(): void {
240+
if (this.isDeclaredAfterMethod) {
241+
this.diagnostics.push(new ElementOutOfPlaceDiagnostic(this.range, 'Enum declaration'));
242+
}
234243
}
244+
235245
}
236246

237247
class EnumMemberDeclarationElement extends BaseEnumDeclarationElement {
238248
tokenType: SemanticTokenTypes;
239249

240-
constructor(context: EnumMemberContext, document: TextDocument) {
241-
super(context, document);
242-
this.tokenType = SemanticTokenTypes.enumMember;
243-
this.identifier = new IdentifierElement(context.untypedName().ambiguousIdentifier()!, document);
244-
}
245-
246250
get symbolInformation(): SymbolInformation {
247251
return SymbolInformationFactory.create(
248252
this, SymbolKind.EnumMember
249253
);
250254
}
255+
256+
constructor(context: EnumMemberContext, document: TextDocument) {
257+
super(context, document);
258+
this.tokenType = SemanticTokenTypes.enumMember;
259+
this.identifier = new IdentifierElement(context.untypedName().ambiguousIdentifier()!, document);
260+
}
251261
}
252262

253263
abstract class BaseVariableDeclarationStatementElement extends BaseContextSyntaxElement implements HasSemanticToken, HasSymbolInformation, NamedSyntaxElement {

server/src/project/elements/module.ts

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ abstract class BaseModuleElement extends ScopeElement implements HasSymbolInform
1212
protected abstract _name: string;
1313
symbolKind: SymbolKind;
1414
diagnostics: Diagnostic[] = [];
15+
context: ProceduralModuleContext | ClassModuleContext;
1516

1617
constructor(context: ProceduralModuleContext | ClassModuleContext, document: TextDocument, symbolKind: SymbolKind) {
1718
super(context, document);
19+
this.context = context;
1820
this.symbolKind = symbolKind;
1921
}
2022

@@ -29,6 +31,32 @@ abstract class BaseModuleElement extends ScopeElement implements HasSymbolInform
2931
}
3032

3133
abstract evaluateDiagnostics(): void;
34+
35+
protected get _hasOptionExplicit(): boolean {
36+
const getCodeElements = () => {
37+
if (this._isClassModule(this.context)) {
38+
return this.context.classModuleBody().classModuleCode().classModuleCodeElement()
39+
}
40+
return this.context.proceduralModuleBody().proceduralModuleCode().proceduralModuleCodeElement();
41+
}
42+
const codeElements = getCodeElements()
43+
if (!codeElements) {
44+
return false;
45+
}
46+
47+
for (const declaration of codeElements) {
48+
const element = declaration.commonModuleCodeElement();
49+
if (element && element.commonOptionDirective()?.optionExplicitDirective()) {
50+
return true;
51+
}
52+
}
53+
54+
return false;
55+
}
56+
57+
private _isClassModule(context: ProceduralModuleContext | ClassModuleContext): context is ClassModuleContext {
58+
return 'classModuleHeader' in context;
59+
}
3260
}
3361

3462
export class ModuleElement extends BaseModuleElement {
@@ -42,7 +70,7 @@ export class ModuleElement extends BaseModuleElement {
4270
}
4371

4472
evaluateDiagnostics(): void {
45-
if (!this._hasOptionExplicit()) {
73+
if (!this._hasOptionExplicit) {
4674
const header = this.context.proceduralModuleHeader();
4775
const startLine = header.stop?.line ?? 0 + 1;
4876
this.diagnostics.push(new MissingOptionExplicitDiagnostic(
@@ -67,21 +95,6 @@ export class ModuleElement extends BaseModuleElement {
6795

6896
return name?.stripQuotes() ?? 'Unknown Module';
6997
}
70-
71-
private _hasOptionExplicit(): boolean {
72-
const moduleDeclarations = this.context.proceduralModuleBody().proceduralModuleDeclarationSection()?.proceduralModuleDeclarationElement();
73-
if (!moduleDeclarations) {
74-
return false;
75-
}
76-
77-
for (const declaration of moduleDeclarations) {
78-
if (declaration.commonOptionDirective()?.optionExplicitDirective()) {
79-
return true;
80-
}
81-
}
82-
83-
return false;
84-
}
8598
}
8699

87100
export class ClassElement extends BaseModuleElement {
@@ -95,7 +108,7 @@ export class ClassElement extends BaseModuleElement {
95108
}
96109

97110
evaluateDiagnostics(): void {
98-
if (!this._hasOptionExplicit()) {
111+
if (!this._hasOptionExplicit) {
99112
const header = this.context.classModuleHeader();
100113
const startLine = header.stop?.line ?? 0 + 1;
101114
this.diagnostics.push(new MissingOptionExplicitDiagnostic(
@@ -121,21 +134,6 @@ export class ClassElement extends BaseModuleElement {
121134
const nameAttribute = nameAttributes[0];
122135
return nameAttribute.STRINGLITERAL().getText().stripQuotes();
123136
}
124-
125-
private _hasOptionExplicit(): boolean {
126-
const moduleDeclarations = this.context.classModuleBody().classModuleDeclarationSection()?.classModuleDeclarationElement();
127-
if (!moduleDeclarations) {
128-
return false;
129-
}
130-
131-
for (const declaration of moduleDeclarations) {
132-
if (declaration.commonOptionDirective()?.optionExplicitDirective()) {
133-
return true;
134-
}
135-
}
136-
137-
return false;
138-
}
139137
}
140138

141139
export class IgnoredAttributeElement extends BaseContextSyntaxElement implements HasDiagnosticCapability {
@@ -148,7 +146,7 @@ export class IgnoredAttributeElement extends BaseContextSyntaxElement implements
148146
evaluateDiagnostics(): void {
149147
this.diagnostics.push(
150148
new IgnoredAttributeDiagnostic(this.range)
151-
)
149+
);
152150
}
153151

154152
}

server/src/project/parser/vbaSyntaxParser.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { TextDocument } from 'vscode-languageserver-textdocument';
22

33
import { vbaLexer } from '../../antlr/out/vbaLexer';
4-
import { ClassModuleContext, ConstItemContext, EnumDeclarationContext, IgnoredAttrContext, ProceduralModuleContext, ProceduralModuleDeclarationElementContext, ProcedureDeclarationContext, UdtDeclarationContext, WhileStatementContext, vbaParser } from '../../antlr/out/vbaParser';
4+
import { ClassModuleContext, ConstItemContext, EnumDeclarationContext, IgnoredAttrContext, ProceduralModuleContext, ProcedureDeclarationContext, UdtDeclarationContext, WhileStatementContext, vbaParser } from '../../antlr/out/vbaParser';
55
import { vbaListener } from '../../antlr/out/vbaListener';
66

77
import { VbaClassDocument, VbaModuleDocument } from '../document';
@@ -87,18 +87,20 @@ class VbaParser extends vbaParser {
8787

8888
class VbaListener extends vbaListener {
8989
document: VbaClassDocument | VbaModuleDocument;
90+
protected _isAfterMethodDeclaration = false;
9091

9192
constructor(document: VbaClassDocument | VbaModuleDocument) {
9293
super();
9394
this.document = document;
9495
}
9596

9697
enterEnumDeclaration = (ctx: EnumDeclarationContext) => {
97-
const element = new EnumDeclarationElement(ctx, this.document.textDocument);
98+
const element = new EnumDeclarationElement(ctx, this.document.textDocument, this._isAfterMethodDeclaration);
9899
this.document.registerFoldableElement(element)
99100
.registerScopedElement(element)
100101
.registerSemanticToken(element)
101-
.registerSymbolInformation(element);
102+
.registerSymbolInformation(element)
103+
.registerDiagnosticElement(element);
102104
element.declaredNames.forEach(names =>
103105
names.forEach(name => this.document
104106
.registerSemanticToken(name)
@@ -156,6 +158,7 @@ class VbaListener extends vbaListener {
156158
};
157159

158160
exitProcedureDeclaration = (ctx: ProcedureDeclarationContext) => {
161+
this._isAfterMethodDeclaration = true;
159162
this.document.deregisterScopedElement();
160163
};
161164

0 commit comments

Comments
 (0)