brighterscript 1.0.0-alpha.27 → 1.0.0-alpha.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/README.md +1 -1
- package/dist/AstValidationSegmenter.d.ts +12 -2
- package/dist/AstValidationSegmenter.js +74 -16
- package/dist/AstValidationSegmenter.js.map +1 -1
- package/dist/DependencyGraph.d.ts +4 -0
- package/dist/DependencyGraph.js +19 -0
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticFilterer.d.ts +7 -4
- package/dist/DiagnosticFilterer.js +67 -37
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +1 -1
- package/dist/PluginInterface.js +1 -1
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +19 -15
- package/dist/Program.js +153 -88
- package/dist/Program.js.map +1 -1
- package/dist/Scope.d.ts +27 -28
- package/dist/Scope.js +174 -361
- package/dist/Scope.js.map +1 -1
- package/dist/Stopwatch.d.ts +4 -0
- package/dist/Stopwatch.js +7 -0
- package/dist/Stopwatch.js.map +1 -1
- package/dist/SymbolTable.d.ts +2 -1
- package/dist/SymbolTable.js +26 -0
- package/dist/SymbolTable.js.map +1 -1
- package/dist/{SymbolTableFlag.js → SymbolTypeFlag.js} +1 -1
- package/dist/SymbolTypeFlag.js.map +1 -0
- package/dist/XmlScope.d.ts +0 -8
- package/dist/XmlScope.js +0 -77
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/CachedLookups.js +4 -8
- package/dist/astUtils/CachedLookups.js.map +1 -1
- package/dist/astUtils/creators.d.ts +1 -0
- package/dist/astUtils/creators.js +3 -2
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/creators.spec.js +0 -10
- package/dist/astUtils/creators.spec.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +4 -4
- package/dist/astUtils/reflection.js +8 -7
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +10 -15
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +1 -2
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +1 -5
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +3 -1
- package/dist/bscPlugin/BscPlugin.js +10 -0
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/SignatureHelpUtil.js +4 -3
- package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js +31 -11
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +39 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/hover/HoverProcessor.js +5 -5
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
- package/dist/bscPlugin/hover/HoverProcessor.spec.js +51 -5
- package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
- package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
- package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +1 -1
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileAfterValidatior.d.ts +7 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidatior.js +18 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidatior.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +17 -10
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +37 -1
- package/dist/bscPlugin/validation/ScopeValidator.js +434 -25
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +91 -4
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +11 -4
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +23 -5
- package/dist/files/BrsFile.js +189 -51
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +589 -97
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/BscFile.d.ts +2 -1
- package/dist/files/BscFile.js.map +1 -1
- package/dist/files/XmlFile.d.ts +2 -2
- package/dist/files/XmlFile.js +2 -2
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +43 -4
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Lexer.d.ts +9 -3
- package/dist/lexer/Lexer.js +36 -15
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +76 -38
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/Token.js +1 -1
- package/dist/lexer/Token.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +1 -0
- package/dist/lexer/TokenKind.js +4 -1
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/AstNode.d.ts +1 -2
- package/dist/parser/AstNode.js +0 -1
- package/dist/parser/AstNode.js.map +1 -1
- package/dist/parser/BrsTranspileState.d.ts +1 -1
- package/dist/parser/Expression.d.ts +77 -47
- package/dist/parser/Expression.js +162 -88
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.d.ts +7 -2
- package/dist/parser/Parser.js +40 -90
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +21 -44
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGTypes.js +5 -5
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/Statement.d.ts +92 -84
- package/dist/parser/Statement.js +199 -133
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +0 -13
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +17 -8
- package/dist/parser/TranspileState.js +67 -8
- package/dist/parser/TranspileState.js.map +1 -1
- package/dist/parser/tests/Parser.spec.d.ts +1 -1
- package/dist/parser/tests/Parser.spec.js +1 -2
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +1 -3
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +44 -0
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +6 -6
- package/dist/parser/tests/expression/TernaryExpression.spec.js +47 -0
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/ConstStatement.spec.js +2 -2
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +8 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +25 -5
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/preprocessor/Chunk.js +1 -2
- package/dist/preprocessor/Chunk.js.map +1 -1
- package/dist/preprocessor/PreprocessorParser.js +2 -1
- package/dist/preprocessor/PreprocessorParser.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +3 -0
- package/dist/types/AssociativeArrayType.js +9 -0
- package/dist/types/AssociativeArrayType.js.map +1 -1
- package/dist/types/BscType.d.ts +1 -1
- package/dist/types/BscType.js +1 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/ComponentType.d.ts +1 -1
- package/dist/types/ReferenceType.d.ts +9 -1
- package/dist/types/ReferenceType.js +45 -1
- package/dist/types/ReferenceType.js.map +1 -1
- package/dist/types/ReferenceType.spec.js +15 -0
- package/dist/types/ReferenceType.spec.js.map +1 -1
- package/dist/util.d.ts +23 -9
- package/dist/util.js +115 -21
- package/dist/util.js.map +1 -1
- package/package.json +6 -3
- package/dist/SymbolTableFlag.js.map +0 -1
- /package/dist/{SymbolTableFlag.d.ts → SymbolTypeFlag.d.ts} +0 -0
package/dist/Scope.js
CHANGED
|
@@ -4,23 +4,17 @@ exports.Scope = void 0;
|
|
|
4
4
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const chalk_1 = require("chalk");
|
|
7
|
-
const DiagnosticMessages_1 = require("./DiagnosticMessages");
|
|
8
7
|
const interfaces_1 = require("./interfaces");
|
|
9
|
-
const ClassValidator_1 = require("./validators/ClassValidator");
|
|
10
8
|
const Parser_1 = require("./parser/Parser");
|
|
11
9
|
const util_1 = require("./util");
|
|
12
|
-
const globalCallables_1 = require("./globalCallables");
|
|
13
10
|
const Cache_1 = require("./Cache");
|
|
14
|
-
const vscode_uri_1 = require("vscode-uri");
|
|
15
11
|
const Logger_1 = require("./Logger");
|
|
16
12
|
const reflection_1 = require("./astUtils/reflection");
|
|
17
13
|
const SymbolTable_1 = require("./SymbolTable");
|
|
18
|
-
const NamespaceType_1 = require("./types/NamespaceType");
|
|
19
14
|
const ReferenceType_1 = require("./types/ReferenceType");
|
|
20
15
|
const UnionType_1 = require("./types/UnionType");
|
|
21
16
|
const AssociativeArrayType_1 = require("./types/AssociativeArrayType");
|
|
22
|
-
const
|
|
23
|
-
const visitors_1 = require("./astUtils/visitors");
|
|
17
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
24
18
|
/**
|
|
25
19
|
* Assign some few factories to the SymbolTable to prevent cyclical imports. This file seems like the most intuitive place to do the linking
|
|
26
20
|
* since Scope will be used by pretty much everything
|
|
@@ -36,10 +30,15 @@ class Scope {
|
|
|
36
30
|
this.program = program;
|
|
37
31
|
this._dependencyGraphKey = _dependencyGraphKey;
|
|
38
32
|
this.cache = new Cache_1.Cache();
|
|
33
|
+
this.useFileCachesForFileLinkLookups = false;
|
|
39
34
|
/**
|
|
40
35
|
* The list of diagnostics found specifically for this scope. Individual file diagnostics are stored on the files themselves.
|
|
41
36
|
*/
|
|
42
37
|
this.diagnostics = [];
|
|
38
|
+
this.validationMetrics = {
|
|
39
|
+
linkTime: 0,
|
|
40
|
+
validationTime: 0
|
|
41
|
+
};
|
|
43
42
|
/**
|
|
44
43
|
* A list of functions that will be called whenever `unlinkSymbolTable` is called
|
|
45
44
|
*/
|
|
@@ -104,6 +103,17 @@ class Scope {
|
|
|
104
103
|
const nsList = lookupKeys.filter(key => key === lookupName).map(key => lookup.get(key));
|
|
105
104
|
return nsList;
|
|
106
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Get a NamespaceContainer by its name, looking for a fully qualified version first, then global version next if not found
|
|
108
|
+
*/
|
|
109
|
+
getFirstNamespaceWithRoot(rootName, containingNamespace) {
|
|
110
|
+
const nameLower = rootName === null || rootName === void 0 ? void 0 : rootName.toLowerCase();
|
|
111
|
+
let lookupName = nameLower;
|
|
112
|
+
if (containingNamespace) {
|
|
113
|
+
lookupName = `${containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()}.${nameLower}`;
|
|
114
|
+
}
|
|
115
|
+
return this.namespaceLookup.get(lookupName);
|
|
116
|
+
}
|
|
107
117
|
/**
|
|
108
118
|
* Get the class with the specified name.
|
|
109
119
|
* @param className - The class name, including the namespace of the class if possible
|
|
@@ -131,18 +141,48 @@ class Scope {
|
|
|
131
141
|
var _a;
|
|
132
142
|
return (_a = this.getEnumFileLink(enumName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.item;
|
|
133
143
|
}
|
|
144
|
+
getFileLinkFromFileMap(cachedMapName, itemName, containingNamespace) {
|
|
145
|
+
var _a;
|
|
146
|
+
let result;
|
|
147
|
+
const fullNameLower = (_a = util_1.util.getFullyQualifiedClassName(itemName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
148
|
+
const itemNameLower = itemName === null || itemName === void 0 ? void 0 : itemName.toLowerCase();
|
|
149
|
+
if (fullNameLower) {
|
|
150
|
+
this.enumerateBrsFilesWithBreak((file) => {
|
|
151
|
+
let stmt = file['_cachedLookups'][cachedMapName].get(fullNameLower);
|
|
152
|
+
if (stmt) {
|
|
153
|
+
result = { item: stmt, file: file };
|
|
154
|
+
}
|
|
155
|
+
return !!stmt;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (!result && itemNameLower && fullNameLower !== itemNameLower) {
|
|
159
|
+
this.enumerateBrsFilesWithBreak((file) => {
|
|
160
|
+
let stmt = file['_cachedLookups'][cachedMapName].get(itemNameLower);
|
|
161
|
+
if (stmt) {
|
|
162
|
+
result = { item: stmt, file: file };
|
|
163
|
+
}
|
|
164
|
+
return !!stmt;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
134
169
|
/**
|
|
135
170
|
* Get a class and its containing file by the class name
|
|
136
171
|
* @param className - The class name, including the namespace of the class if possible
|
|
137
172
|
* @param containingNamespace - The namespace used to resolve relative class names. (i.e. the namespace around the current statement trying to find a class)
|
|
138
173
|
*/
|
|
139
174
|
getClassFileLink(className, containingNamespace) {
|
|
140
|
-
|
|
175
|
+
var _a;
|
|
176
|
+
if (this.useFileCachesForFileLinkLookups) {
|
|
177
|
+
return this.getFileLinkFromFileMap('classStatementMap', className, containingNamespace);
|
|
178
|
+
}
|
|
179
|
+
const lowerName = className === null || className === void 0 ? void 0 : className.toLowerCase();
|
|
180
|
+
const fullNameLower = (_a = util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
141
181
|
const classMap = this.getClassMap();
|
|
142
|
-
let cls = classMap.get(
|
|
182
|
+
let cls = classMap.get(fullNameLower);
|
|
143
183
|
//if we couldn't find the class by its full namespaced name, look for a global class with that name
|
|
144
|
-
if (!cls) {
|
|
145
|
-
cls = classMap.get(
|
|
184
|
+
if (!cls && lowerName && lowerName !== fullNameLower) {
|
|
185
|
+
cls = classMap.get(lowerName);
|
|
146
186
|
}
|
|
147
187
|
return cls;
|
|
148
188
|
}
|
|
@@ -152,11 +192,16 @@ class Scope {
|
|
|
152
192
|
* @param containingNamespace - The namespace used to resolve relative interface names. (i.e. the namespace around the current statement trying to find a interface)
|
|
153
193
|
*/
|
|
154
194
|
getInterfaceFileLink(ifaceName, containingNamespace) {
|
|
195
|
+
var _a;
|
|
196
|
+
if (this.useFileCachesForFileLinkLookups) {
|
|
197
|
+
return this.getFileLinkFromFileMap('interfaceStatementMap', ifaceName, containingNamespace);
|
|
198
|
+
}
|
|
155
199
|
const lowerName = ifaceName === null || ifaceName === void 0 ? void 0 : ifaceName.toLowerCase();
|
|
200
|
+
const fullNameLower = (_a = util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
156
201
|
const ifaceMap = this.getInterfaceMap();
|
|
157
|
-
let iface = ifaceMap.get(
|
|
202
|
+
let iface = ifaceMap.get(fullNameLower);
|
|
158
203
|
//if we couldn't find the iface by its full namespaced name, look for a global class with that name
|
|
159
|
-
if (!iface) {
|
|
204
|
+
if (!iface && lowerName && lowerName !== fullNameLower) {
|
|
160
205
|
iface = ifaceMap.get(lowerName);
|
|
161
206
|
}
|
|
162
207
|
return iface;
|
|
@@ -167,11 +212,16 @@ class Scope {
|
|
|
167
212
|
* @param containingNamespace - The namespace used to resolve relative enum names. (i.e. the namespace around the current statement trying to find a enum)
|
|
168
213
|
*/
|
|
169
214
|
getEnumFileLink(enumName, containingNamespace) {
|
|
215
|
+
var _a;
|
|
216
|
+
if (this.useFileCachesForFileLinkLookups) {
|
|
217
|
+
return this.getFileLinkFromFileMap('enumStatementMap', enumName, containingNamespace);
|
|
218
|
+
}
|
|
170
219
|
const lowerName = enumName === null || enumName === void 0 ? void 0 : enumName.toLowerCase();
|
|
220
|
+
const fullNameLower = (_a = util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
171
221
|
const enumMap = this.getEnumMap();
|
|
172
|
-
let enumeration = enumMap.get(
|
|
222
|
+
let enumeration = enumMap.get(fullNameLower);
|
|
173
223
|
//if we couldn't find the enum by its full namespaced name, look for a global enum with that name
|
|
174
|
-
if (!enumeration) {
|
|
224
|
+
if (!enumeration && lowerName && lowerName !== fullNameLower) {
|
|
175
225
|
enumeration = enumMap.get(lowerName);
|
|
176
226
|
}
|
|
177
227
|
return enumeration;
|
|
@@ -185,7 +235,7 @@ class Scope {
|
|
|
185
235
|
var _a, _b;
|
|
186
236
|
let lowerNameParts = (_a = enumMemberName === null || enumMemberName === void 0 ? void 0 : enumMemberName.toLowerCase()) === null || _a === void 0 ? void 0 : _a.split('.');
|
|
187
237
|
let memberName = (_b = lowerNameParts === null || lowerNameParts === void 0 ? void 0 : lowerNameParts.splice(lowerNameParts.length - 1, 1)) === null || _b === void 0 ? void 0 : _b[0];
|
|
188
|
-
let lowerName = lowerNameParts === null || lowerNameParts === void 0 ? void 0 : lowerNameParts.join('.');
|
|
238
|
+
let lowerName = lowerNameParts === null || lowerNameParts === void 0 ? void 0 : lowerNameParts.join('.').toLowerCase();
|
|
189
239
|
const enumMap = this.getEnumMap();
|
|
190
240
|
let enumeration = enumMap.get(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
|
|
191
241
|
//if we couldn't find the enum by its full namespaced name, look for a global enum with that name
|
|
@@ -203,30 +253,37 @@ class Scope {
|
|
|
203
253
|
* @param containingNamespace - The namespace used to resolve relative constant names. (i.e. the namespace around the current statement trying to find a constant)
|
|
204
254
|
*/
|
|
205
255
|
getConstFileLink(constName, containingNamespace) {
|
|
256
|
+
var _a;
|
|
257
|
+
if (this.useFileCachesForFileLinkLookups) {
|
|
258
|
+
return this.getFileLinkFromFileMap('constStatementMap', constName, containingNamespace);
|
|
259
|
+
}
|
|
206
260
|
const lowerName = constName === null || constName === void 0 ? void 0 : constName.toLowerCase();
|
|
261
|
+
const fullNameLower = (_a = util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
207
262
|
const constMap = this.getConstMap();
|
|
208
|
-
let result = constMap.get(
|
|
263
|
+
let result = constMap.get(fullNameLower);
|
|
209
264
|
//if we couldn't find the constant by its full namespaced name, look for a global constant with that name
|
|
210
|
-
if (!result) {
|
|
265
|
+
if (!result && lowerName !== fullNameLower) {
|
|
211
266
|
result = constMap.get(lowerName);
|
|
212
267
|
}
|
|
213
268
|
return result;
|
|
214
269
|
}
|
|
215
|
-
getAllFileLinks(name, containingNamespace) {
|
|
216
|
-
var _a
|
|
270
|
+
getAllFileLinks(name, containingNamespace, includeNamespaces = false, includeNameShadowsOutsideNamespace = false) {
|
|
271
|
+
var _a;
|
|
217
272
|
let links = [];
|
|
218
|
-
links.push(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
273
|
+
links.push(this.getClassFileLink(name, containingNamespace), this.getInterfaceFileLink(name, containingNamespace), this.getConstFileLink(name, containingNamespace), this.getEnumFileLink(name, containingNamespace));
|
|
274
|
+
if (includeNameShadowsOutsideNamespace && containingNamespace) {
|
|
275
|
+
links.push(this.getClassFileLink(name), this.getInterfaceFileLink(name), this.getConstFileLink(name), this.getEnumFileLink(name));
|
|
276
|
+
}
|
|
277
|
+
if (includeNamespaces) {
|
|
278
|
+
const nameSpaceContainer = this.getFirstNamespaceWithRoot(name, containingNamespace);
|
|
279
|
+
if (nameSpaceContainer) {
|
|
280
|
+
links.push({ item: (_a = nameSpaceContainer.namespaceStatements) === null || _a === void 0 ? void 0 : _a[0], file: nameSpaceContainer === null || nameSpaceContainer === void 0 ? void 0 : nameSpaceContainer.file });
|
|
224
281
|
}
|
|
225
282
|
}
|
|
226
283
|
const fullNameLower = (containingNamespace ? `${containingNamespace}.${name}` : name).toLowerCase();
|
|
227
284
|
const callable = this.getCallableByName(name);
|
|
228
285
|
if (callable) {
|
|
229
|
-
if (!callable.hasNamespace || callable.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === fullNameLower) {
|
|
286
|
+
if ((!callable.hasNamespace && includeNameShadowsOutsideNamespace) || callable.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === fullNameLower) {
|
|
230
287
|
// this callable has no namespace, or has same namespace
|
|
231
288
|
links.push({ item: callable.functionStatement, file: callable.file });
|
|
232
289
|
}
|
|
@@ -446,7 +503,7 @@ class Scope {
|
|
|
446
503
|
for (let dependency of dependencies) {
|
|
447
504
|
//load components by their name
|
|
448
505
|
if (dependency.startsWith('component:')) {
|
|
449
|
-
let comp = this.program.getComponent(dependency.replace(
|
|
506
|
+
let comp = this.program.getComponent(dependency.replace(/^component:/, ''));
|
|
450
507
|
if (comp) {
|
|
451
508
|
result.push(comp.file);
|
|
452
509
|
}
|
|
@@ -462,6 +519,36 @@ class Scope {
|
|
|
462
519
|
return result;
|
|
463
520
|
});
|
|
464
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Gets a list of all files in this scope, but not imported files, and not from ancestor scopes
|
|
524
|
+
*/
|
|
525
|
+
getImmediateFiles() {
|
|
526
|
+
return this.cache.getOrAdd('getImmediateFiles', () => {
|
|
527
|
+
let result = [];
|
|
528
|
+
if ((0, reflection_1.isXmlScope)(this)) {
|
|
529
|
+
result.push(this.xmlFile);
|
|
530
|
+
}
|
|
531
|
+
let dependencies = this.dependencyGraph.getImmediateDependencies(this.dependencyGraphKey);
|
|
532
|
+
for (let dependency of dependencies) {
|
|
533
|
+
//load components by their name
|
|
534
|
+
if (dependency.startsWith('component:')) {
|
|
535
|
+
let comp = this.program.getComponent(dependency.replace(/^component:/, ''));
|
|
536
|
+
if (comp) {
|
|
537
|
+
result.push(...comp.scope.getImmediateFiles());
|
|
538
|
+
result.push(comp.file);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
let file = this.program.getFile(dependency);
|
|
543
|
+
if (file) {
|
|
544
|
+
result.push(file);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
this.logDebug('getImmediateFiles', () => result.map(x => x.destPath));
|
|
549
|
+
return result;
|
|
550
|
+
});
|
|
551
|
+
}
|
|
465
552
|
/**
|
|
466
553
|
* Get the list of errors for this scope. It's calculated on the fly, so call this sparingly.
|
|
467
554
|
*/
|
|
@@ -516,6 +603,13 @@ class Scope {
|
|
|
516
603
|
return result;
|
|
517
604
|
});
|
|
518
605
|
}
|
|
606
|
+
getCallableContainerMap() {
|
|
607
|
+
return this.cache.getOrAdd('callableContainerMap', () => {
|
|
608
|
+
let callables = this.getAllCallables();
|
|
609
|
+
//get a list of all callables, indexed by their lower case names
|
|
610
|
+
return util_1.util.getCallableContainersByLowerName(callables);
|
|
611
|
+
});
|
|
612
|
+
}
|
|
519
613
|
/**
|
|
520
614
|
* Iterate over Brs files not shadowed by typedefs
|
|
521
615
|
*/
|
|
@@ -528,6 +622,20 @@ class Scope {
|
|
|
528
622
|
}
|
|
529
623
|
}
|
|
530
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Iterate over Brs files not shadowed by typedefs
|
|
627
|
+
*/
|
|
628
|
+
enumerateBrsFilesWithBreak(callback) {
|
|
629
|
+
const files = this.getAllFiles();
|
|
630
|
+
for (const file of files) {
|
|
631
|
+
//only brs files without a typedef
|
|
632
|
+
if ((0, reflection_1.isBrsFile)(file) && !file.hasTypedef) {
|
|
633
|
+
if (callback(file)) {
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
531
639
|
/**
|
|
532
640
|
* Call a function for each file directly included in this scope (excluding files found only in parent scopes).
|
|
533
641
|
*/
|
|
@@ -600,11 +708,28 @@ class Scope {
|
|
|
600
708
|
this.program.logger.debug(this._debugLogComponentName, ...args);
|
|
601
709
|
}
|
|
602
710
|
validate(validationOptions = { force: false }) {
|
|
711
|
+
var _a, _b;
|
|
603
712
|
//if this scope is already validated, no need to revalidate
|
|
604
713
|
if (this.isValidated === true && !validationOptions.force) {
|
|
605
714
|
this.logDebug('validate(): already validated');
|
|
606
|
-
return;
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
const hasChangedSymbols = ((_a = validationOptions.changedSymbols) === null || _a === void 0 ? void 0 : _a.get(1 /* SymbolTypeFlag.runtime */).size) > 0 || ((_b = validationOptions.changedSymbols) === null || _b === void 0 ? void 0 : _b.get(2 /* SymbolTypeFlag.typetime */).size) > 0;
|
|
718
|
+
let immediateFileChanged = false;
|
|
719
|
+
if (!validationOptions.initialValidation && validationOptions.changedSymbols && !hasChangedSymbols && validationOptions.changedFiles) {
|
|
720
|
+
for (let file of this.getImmediateFiles()) {
|
|
721
|
+
if (validationOptions.changedFiles.includes(file)) {
|
|
722
|
+
immediateFileChanged = true;
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (!immediateFileChanged) {
|
|
727
|
+
// There was no need to validate this scope.
|
|
728
|
+
this.isValidated = true;
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
607
731
|
}
|
|
732
|
+
this.useFileCachesForFileLinkLookups = !validationOptions.initialValidation;
|
|
608
733
|
this.program.logger.time(Logger_1.LogLevel.debug, [this._debugLogComponentName, 'validate()'], () => {
|
|
609
734
|
let parentScope = this.getParentScope();
|
|
610
735
|
//validate our parent before we validate ourself
|
|
@@ -614,63 +739,26 @@ class Scope {
|
|
|
614
739
|
}
|
|
615
740
|
//clear the scope's errors list (we will populate them from this method)
|
|
616
741
|
this.clearScopeLevelDiagnostics();
|
|
617
|
-
let callables = this.getAllCallables();
|
|
618
|
-
//sort the callables by filepath and then method name, so the errors will be consistent
|
|
619
|
-
// eslint-disable-next-line prefer-arrow-callback
|
|
620
|
-
callables = callables.sort((a, b) => {
|
|
621
|
-
const pathA = a.callable.file.srcPath;
|
|
622
|
-
const pathB = b.callable.file.srcPath;
|
|
623
|
-
//sort by path
|
|
624
|
-
if (pathA < pathB) {
|
|
625
|
-
return -1;
|
|
626
|
-
}
|
|
627
|
-
else if (pathA > pathB) {
|
|
628
|
-
return 1;
|
|
629
|
-
}
|
|
630
|
-
//sort by function name
|
|
631
|
-
const funcA = b.callable.name;
|
|
632
|
-
const funcB = b.callable.name;
|
|
633
|
-
if (funcA < funcB) {
|
|
634
|
-
return -1;
|
|
635
|
-
}
|
|
636
|
-
else if (funcA > funcB) {
|
|
637
|
-
return 1;
|
|
638
|
-
}
|
|
639
|
-
return 0;
|
|
640
|
-
});
|
|
641
|
-
//get a list of all callables, indexed by their lower case names
|
|
642
|
-
let callableContainerMap = util_1.util.getCallableContainersByLowerName(callables);
|
|
643
742
|
//Since statements from files are shared across multiple scopes, we need to link those statements to the current scope
|
|
743
|
+
let t0 = perf_hooks_1.performance.now();
|
|
644
744
|
this.linkSymbolTable();
|
|
745
|
+
this.validationMetrics.linkTime = perf_hooks_1.performance.now() - t0;
|
|
645
746
|
const scopeValidateEvent = {
|
|
646
747
|
program: this.program,
|
|
647
748
|
scope: this,
|
|
648
749
|
changedFiles: validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.changedFiles,
|
|
649
750
|
changedSymbols: validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.changedSymbols
|
|
650
751
|
};
|
|
752
|
+
t0 = perf_hooks_1.performance.now();
|
|
651
753
|
this.program.plugins.emit('beforeScopeValidate', scopeValidateEvent);
|
|
652
754
|
this.program.plugins.emit('onScopeValidate', scopeValidateEvent);
|
|
653
|
-
this.
|
|
755
|
+
this.validationMetrics.validationTime = perf_hooks_1.performance.now() - t0;
|
|
654
756
|
this.program.plugins.emit('afterScopeValidate', scopeValidateEvent);
|
|
655
757
|
//unlink all symbol tables from this scope (so they don't accidentally stick around)
|
|
656
758
|
this.unlinkSymbolTable();
|
|
657
759
|
this.isValidated = true;
|
|
658
760
|
});
|
|
659
|
-
|
|
660
|
-
_validate(callableContainerMap) {
|
|
661
|
-
//find all duplicate function declarations
|
|
662
|
-
this.diagnosticFindDuplicateFunctionDeclarations(callableContainerMap);
|
|
663
|
-
//detect missing and incorrect-case script imports
|
|
664
|
-
this.diagnosticValidateScriptImportPaths();
|
|
665
|
-
//enforce a series of checks on the bodies of class methods
|
|
666
|
-
this.validateClasses();
|
|
667
|
-
//do many per-file checks
|
|
668
|
-
this.enumerateBrsFiles((file) => {
|
|
669
|
-
this.diagnosticDetectShadowedLocalVars(file, callableContainerMap);
|
|
670
|
-
this.diagnosticDetectFunctionCollisions(file);
|
|
671
|
-
this.detectVariableNamespaceCollisions(file);
|
|
672
|
-
this.detectNameCollisions(file);
|
|
673
|
-
});
|
|
761
|
+
return true;
|
|
674
762
|
}
|
|
675
763
|
clearAstSegmentDiagnostics(astSegment) {
|
|
676
764
|
this.diagnostics = this.diagnostics.filter(diag => !(diag.origin === interfaces_1.DiagnosticOrigin.ASTSegment && diag.astSegment === astSegment));
|
|
@@ -703,6 +791,9 @@ class Scope {
|
|
|
703
791
|
return result;
|
|
704
792
|
});
|
|
705
793
|
}
|
|
794
|
+
get allNamespaceTypeTable() {
|
|
795
|
+
return this._allNamespaceTypeTable;
|
|
796
|
+
}
|
|
706
797
|
/**
|
|
707
798
|
* Builds the current symbol table for the scope, by merging the tables for all the files in this scope.
|
|
708
799
|
* Also links all file symbols tables to this new table
|
|
@@ -723,64 +814,29 @@ class Scope {
|
|
|
723
814
|
* ```
|
|
724
815
|
*/
|
|
725
816
|
linkSymbolTable() {
|
|
726
|
-
var _a;
|
|
727
817
|
SymbolTable_1.SymbolTable.cacheVerifier.generateToken();
|
|
818
|
+
this._allNamespaceTypeTable = new SymbolTable_1.SymbolTable(`Scope NamespaceTypes ${this.name}`);
|
|
728
819
|
for (const file of this.getAllFiles()) {
|
|
729
820
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
730
821
|
this.linkSymbolTableDisposables.push(file.parser.symbolTable.pushParentProvider(() => this.symbolTable));
|
|
731
822
|
}
|
|
732
823
|
}
|
|
733
|
-
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (!nsContainer.isTopLevel) {
|
|
742
|
-
parentNSType = namespaceTypesKnown.get(nsContainer.parentNameLower);
|
|
743
|
-
if (!parentNSType) {
|
|
744
|
-
// we don't know about the parent namespace... uh, oh!
|
|
745
|
-
this.program.logger.error(`Unable to find parent namespace type for namespace ${nsName}`);
|
|
746
|
-
break;
|
|
747
|
-
}
|
|
748
|
-
currentNSType = parentNSType.getMemberType(nsContainer.fullNameLower, getTypeOptions);
|
|
749
|
-
}
|
|
750
|
-
else {
|
|
751
|
-
currentNSType = this.symbolTable.getSymbolType(nsContainer.fullNameLower, getTypeOptions);
|
|
752
|
-
}
|
|
753
|
-
if (!(0, reflection_1.isNamespaceType)(currentNSType)) {
|
|
754
|
-
if (!currentNSType || (0, reflection_1.isReferenceType)(currentNSType) || (0, reflection_1.isCallableType)(currentNSType)) {
|
|
755
|
-
currentNSType = existingNsStmt
|
|
756
|
-
? existingNsStmt.getType(getTypeOptions)
|
|
757
|
-
: new NamespaceType_1.NamespaceType(nsName);
|
|
758
|
-
if (parentNSType) {
|
|
759
|
-
// adding as a member of existing NS
|
|
760
|
-
parentNSType.addMember(nsContainer.lastPartName, { definingNode: existingNsStmt }, currentNSType, getTypeOptions.flags);
|
|
761
|
-
this.symbolsAddedDuringLinking.push({ symbolTable: parentNSType.getMemberTable(), name: nsContainer.lastPartName, flags: getTypeOptions.flags });
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
this.symbolTable.addSymbol(nsContainer.lastPartName, { definingNode: existingNsStmt }, currentNSType, getTypeOptions.flags);
|
|
765
|
-
this.symbolsAddedDuringLinking.push({ symbolTable: this.symbolTable, name: nsContainer.lastPartName, flags: getTypeOptions.flags });
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
else {
|
|
769
|
-
this.program.logger.error(`Invalid existing type for namespace ${nsName} - ${currentNSType.toString()}`);
|
|
770
|
-
continue;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
else {
|
|
774
|
-
// Existing known namespace
|
|
775
|
-
}
|
|
776
|
-
if (!namespaceTypesKnown.has(nsName)) {
|
|
777
|
-
namespaceTypesKnown.set(nsName, currentNSType);
|
|
824
|
+
const directFiles = this.getImmediateFiles();
|
|
825
|
+
for (const file of directFiles) {
|
|
826
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
827
|
+
const namespaceTypes = file.getNamespaceSymbolTable();
|
|
828
|
+
this.linkSymbolTableDisposables.push(...this._allNamespaceTypeTable.mergeNamespaceSymbolTables(namespaceTypes));
|
|
829
|
+
/* this.linkSymbolTableDisposables.push(
|
|
830
|
+
() => file.unlinkNamespaceSymbolTables()
|
|
831
|
+
);*/
|
|
778
832
|
}
|
|
833
|
+
}
|
|
834
|
+
for (const [_, nsContainer] of this.namespaceLookup) {
|
|
779
835
|
for (let nsStmt of nsContainer.namespaceStatements) {
|
|
780
836
|
this.linkSymbolTableDisposables.push(nsStmt === null || nsStmt === void 0 ? void 0 : nsStmt.getSymbolTable().addSibling(nsContainer.symbolTable));
|
|
781
837
|
}
|
|
782
|
-
this.linkSymbolTableDisposables.push(currentNSType.memberTable.addSibling(nsContainer.symbolTable));
|
|
783
838
|
}
|
|
839
|
+
this.linkSymbolTableDisposables.push(this.symbolTable.addSibling(this._allNamespaceTypeTable));
|
|
784
840
|
}
|
|
785
841
|
unlinkSymbolTable() {
|
|
786
842
|
for (const symbolToRemove of this.symbolsAddedDuringLinking) {
|
|
@@ -792,220 +848,6 @@ class Scope {
|
|
|
792
848
|
}
|
|
793
849
|
this.linkSymbolTableDisposables = [];
|
|
794
850
|
}
|
|
795
|
-
detectVariableNamespaceCollisions(file) {
|
|
796
|
-
var _a, _b;
|
|
797
|
-
//find all function parameters
|
|
798
|
-
for (let func of file['_cachedLookups'].functionExpressions) {
|
|
799
|
-
for (let param of func.parameters) {
|
|
800
|
-
let lowerParamName = param.tokens.name.text.toLowerCase();
|
|
801
|
-
let namespace = this.getNamespace(lowerParamName, (_a = param.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
802
|
-
//see if the param matches any starting namespace part
|
|
803
|
-
if (namespace) {
|
|
804
|
-
this.diagnostics.push(Object.assign(Object.assign({ origin: interfaces_1.DiagnosticOrigin.Scope, file: file }, DiagnosticMessages_1.DiagnosticMessages.parameterMayNotHaveSameNameAsNamespace(param.tokens.name.text)), { range: param.tokens.name.range, relatedInformation: [{
|
|
805
|
-
message: 'Namespace declared here',
|
|
806
|
-
location: util_1.util.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
|
|
807
|
-
}] }));
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
for (let assignment of file['_cachedLookups'].assignmentStatements) {
|
|
812
|
-
let lowerAssignmentName = assignment.tokens.name.text.toLowerCase();
|
|
813
|
-
let namespace = this.getNamespace(lowerAssignmentName, (_b = assignment.findAncestor(reflection_1.isNamespaceStatement)) === null || _b === void 0 ? void 0 : _b.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
814
|
-
//see if the param matches any starting namespace part
|
|
815
|
-
if (namespace) {
|
|
816
|
-
this.diagnostics.push(Object.assign(Object.assign({ origin: interfaces_1.DiagnosticOrigin.Scope, file: file }, DiagnosticMessages_1.DiagnosticMessages.variableMayNotHaveSameNameAsNamespace(assignment.tokens.name.text)), { range: assignment.tokens.name.range, relatedInformation: [{
|
|
817
|
-
message: 'Namespace declared here',
|
|
818
|
-
location: util_1.util.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
|
|
819
|
-
}] }));
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
/**
|
|
824
|
-
* Find various function collisions
|
|
825
|
-
*/
|
|
826
|
-
diagnosticDetectFunctionCollisions(file) {
|
|
827
|
-
for (let func of file.callables) {
|
|
828
|
-
const funcName = func.getName(Parser_1.ParseMode.BrighterScript);
|
|
829
|
-
const lowerFuncName = funcName === null || funcName === void 0 ? void 0 : funcName.toLowerCase();
|
|
830
|
-
if (lowerFuncName) {
|
|
831
|
-
//find function declarations with the same name as a stdlib function
|
|
832
|
-
if (globalCallables_1.globalCallableMap.has(lowerFuncName)) {
|
|
833
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scopeFunctionShadowedByBuiltInFunction()), { range: func.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
834
|
-
}
|
|
835
|
-
//find any functions that have the same name as a class
|
|
836
|
-
const klassLink = this.getClassFileLink(lowerFuncName);
|
|
837
|
-
if (klassLink) {
|
|
838
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionCannotHaveSameNameAsClass(funcName)), { range: func.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope, relatedInformation: [{
|
|
839
|
-
location: util_1.util.createLocation(vscode_uri_1.URI.file(klassLink.file.srcPath).toString(), klassLink.item.tokens.name.range),
|
|
840
|
-
message: 'Original class declared here'
|
|
841
|
-
}] }));
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
detectNameCollisions(file) {
|
|
847
|
-
file.ast.walk((0, visitors_1.createVisitor)({
|
|
848
|
-
NamespaceStatement: (nsStmt) => {
|
|
849
|
-
var _a;
|
|
850
|
-
this.validateNameCollision(file, nsStmt, (_a = nsStmt.getNameParts()) === null || _a === void 0 ? void 0 : _a[0]);
|
|
851
|
-
},
|
|
852
|
-
ClassStatement: (classStmt) => {
|
|
853
|
-
this.validateNameCollision(file, classStmt, classStmt.tokens.name);
|
|
854
|
-
},
|
|
855
|
-
InterfaceStatement: (ifaceStmt) => {
|
|
856
|
-
this.validateNameCollision(file, ifaceStmt, ifaceStmt.tokens.name);
|
|
857
|
-
},
|
|
858
|
-
ConstStatement: (constStmt) => {
|
|
859
|
-
this.validateNameCollision(file, constStmt, constStmt.tokens.name);
|
|
860
|
-
},
|
|
861
|
-
EnumStatement: (enumStmt) => {
|
|
862
|
-
this.validateNameCollision(file, enumStmt, enumStmt.tokens.name);
|
|
863
|
-
}
|
|
864
|
-
}), {
|
|
865
|
-
walkMode: visitors_1.WalkMode.visitStatements
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
validateNameCollision(file, node, nameIdentifier) {
|
|
869
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
870
|
-
const name = nameIdentifier === null || nameIdentifier === void 0 ? void 0 : nameIdentifier.text;
|
|
871
|
-
if (!name || !node) {
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
const nameRange = nameIdentifier.range;
|
|
875
|
-
const containingNamespace = (_a = node.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript);
|
|
876
|
-
const links = this.getAllFileLinks(name, containingNamespace);
|
|
877
|
-
for (let link of links) {
|
|
878
|
-
if (!link || link.item === node) {
|
|
879
|
-
// refers to same node
|
|
880
|
-
continue;
|
|
881
|
-
}
|
|
882
|
-
if ((0, reflection_1.isNamespaceStatement)(link.item) && (0, reflection_1.isNamespaceStatement)(node)) {
|
|
883
|
-
// namespace can be declared multiple times
|
|
884
|
-
continue;
|
|
885
|
-
}
|
|
886
|
-
if ((0, reflection_1.isFunctionStatement)(link.item) || ((_b = link.file) === null || _b === void 0 ? void 0 : _b.destPath) === 'global') {
|
|
887
|
-
// the thing found is a function OR from global (which is also a function)
|
|
888
|
-
if ((0, reflection_1.isNamespaceStatement)(node)) {
|
|
889
|
-
// these are not callable functions in transpiled code - ignore them
|
|
890
|
-
continue;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
const thisNodeKindName = util_1.util.getAstNodeFriendlyName(node);
|
|
894
|
-
const thatNodeKindName = link.file.srcPath === 'global' ? 'Global Function' : (_c = util_1.util.getAstNodeFriendlyName(link.item)) !== null && _c !== void 0 ? _c : '';
|
|
895
|
-
let thatNameRange = (_g = (_f = (_e = (_d = link.item) === null || _d === void 0 ? void 0 : _d.tokens) === null || _e === void 0 ? void 0 : _e.name) === null || _f === void 0 ? void 0 : _f.range) !== null && _g !== void 0 ? _g : (_h = link.item) === null || _h === void 0 ? void 0 : _h.range;
|
|
896
|
-
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
897
|
-
switch ((_j = link.item) === null || _j === void 0 ? void 0 : _j.kind) {
|
|
898
|
-
case AstNode_1.AstNodeKind.ClassStatement: {
|
|
899
|
-
thatNameRange = (_k = link.item.tokens.name) === null || _k === void 0 ? void 0 : _k.range;
|
|
900
|
-
break;
|
|
901
|
-
}
|
|
902
|
-
case AstNode_1.AstNodeKind.NamespaceStatement: {
|
|
903
|
-
thatNameRange = (_m = (_l = link.item.getNameParts()) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.range;
|
|
904
|
-
break;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
const relatedInformation = thatNameRange ? [{
|
|
908
|
-
message: `${thatNodeKindName} declared here`,
|
|
909
|
-
location: util_1.util.createLocation(vscode_uri_1.URI.file((_o = link.file) === null || _o === void 0 ? void 0 : _o.srcPath).toString(), thatNameRange)
|
|
910
|
-
}] : undefined;
|
|
911
|
-
this.diagnostics.push(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.nameCollision(thisNodeKindName, thatNodeKindName, name)), { origin: interfaces_1.DiagnosticOrigin.Scope, range: nameRange, relatedInformation: relatedInformation }));
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
validateClasses() {
|
|
915
|
-
let validator = new ClassValidator_1.BsClassValidator(this);
|
|
916
|
-
validator.validate();
|
|
917
|
-
this.diagnostics.push(...validator.diagnostics.map(diag => {
|
|
918
|
-
return Object.assign(Object.assign({}, diag), { origin: interfaces_1.DiagnosticOrigin.Scope });
|
|
919
|
-
}));
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* Detect local variables (function scope) that have the same name as scope calls
|
|
923
|
-
*/
|
|
924
|
-
diagnosticDetectShadowedLocalVars(file, callableContainerMap) {
|
|
925
|
-
var _a;
|
|
926
|
-
const classMap = this.getClassMap();
|
|
927
|
-
//loop through every function scope
|
|
928
|
-
for (let funcScope of file.functionScopes) {
|
|
929
|
-
//every var declaration in this function scope
|
|
930
|
-
for (let varDeclaration of funcScope.variableDeclarations) {
|
|
931
|
-
const varName = varDeclaration.name;
|
|
932
|
-
const lowerVarName = varName.toLowerCase();
|
|
933
|
-
const varIsFunction = () => {
|
|
934
|
-
return (0, reflection_1.isCallableType)(varDeclaration.getType());
|
|
935
|
-
};
|
|
936
|
-
if (
|
|
937
|
-
//has same name as stdlib
|
|
938
|
-
globalCallables_1.globalCallableMap.has(lowerVarName)) {
|
|
939
|
-
//local var function with same name as stdlib function
|
|
940
|
-
if (varIsFunction()) {
|
|
941
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('stdlib')), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
else if (callableContainerMap.has(lowerVarName)) {
|
|
945
|
-
//is same name as a callable
|
|
946
|
-
if (varIsFunction()) {
|
|
947
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('scope')), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
948
|
-
}
|
|
949
|
-
else {
|
|
950
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarShadowedByScopedFunction()), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
951
|
-
}
|
|
952
|
-
//has the same name as an in-scope class
|
|
953
|
-
}
|
|
954
|
-
else if (classMap.has(lowerVarName)) {
|
|
955
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarSameNameAsClass((_a = classMap.get(lowerVarName)) === null || _a === void 0 ? void 0 : _a.item.getName(Parser_1.ParseMode.BrighterScript))), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* Create diagnostics for any duplicate function declarations
|
|
962
|
-
*/
|
|
963
|
-
diagnosticFindDuplicateFunctionDeclarations(callableContainersByLowerName) {
|
|
964
|
-
//for each list of callables with the same name
|
|
965
|
-
for (let [lowerName, callableContainers] of callableContainersByLowerName) {
|
|
966
|
-
let globalCallables = [];
|
|
967
|
-
let nonGlobalCallables = [];
|
|
968
|
-
let ownCallables = [];
|
|
969
|
-
let ancestorNonGlobalCallables = [];
|
|
970
|
-
for (let container of callableContainers) {
|
|
971
|
-
if (container.scope === this.program.globalScope) {
|
|
972
|
-
globalCallables.push(container);
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
nonGlobalCallables.push(container);
|
|
976
|
-
if (container.scope === this) {
|
|
977
|
-
ownCallables.push(container);
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
ancestorNonGlobalCallables.push(container);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
//add info diagnostics about child shadowing parent functions
|
|
985
|
-
if (ownCallables.length > 0 && ancestorNonGlobalCallables.length > 0) {
|
|
986
|
-
for (let container of ownCallables) {
|
|
987
|
-
//skip the init function (because every component will have one of those){
|
|
988
|
-
if (lowerName !== 'init') {
|
|
989
|
-
let shadowedCallable = ancestorNonGlobalCallables[ancestorNonGlobalCallables.length - 1];
|
|
990
|
-
if (!!shadowedCallable && shadowedCallable.callable.file === container.callable.file) {
|
|
991
|
-
//same file: skip redundant imports
|
|
992
|
-
continue;
|
|
993
|
-
}
|
|
994
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.overridesAncestorFunction(container.callable.name, container.scope.name, shadowedCallable.callable.file.destPath,
|
|
995
|
-
//grab the last item in the list, which should be the closest ancestor's version
|
|
996
|
-
shadowedCallable.scope.name)), { range: container.callable.nameRange, file: container.callable.file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
//add error diagnostics about duplicate functions in the same scope
|
|
1001
|
-
if (ownCallables.length > 1) {
|
|
1002
|
-
for (let callableContainer of ownCallables) {
|
|
1003
|
-
let callable = callableContainer.callable;
|
|
1004
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateFunctionImplementation(callable.name, callableContainer.scope.name)), { range: util_1.util.createRange(callable.nameRange.start.line, callable.nameRange.start.character, callable.nameRange.start.line, callable.nameRange.end.character), file: callable.file, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
851
|
/**
|
|
1010
852
|
* Get the list of all script imports for this scope
|
|
1011
853
|
*/
|
|
@@ -1021,35 +863,6 @@ class Scope {
|
|
|
1021
863
|
});
|
|
1022
864
|
return result;
|
|
1023
865
|
}
|
|
1024
|
-
/**
|
|
1025
|
-
* Verify that all of the scripts imported by each file in this scope actually exist
|
|
1026
|
-
*/
|
|
1027
|
-
diagnosticValidateScriptImportPaths() {
|
|
1028
|
-
let scriptImports = this.getOwnScriptImports();
|
|
1029
|
-
//verify every script import
|
|
1030
|
-
for (let scriptImport of scriptImports) {
|
|
1031
|
-
let referencedFile = this.getFileByRelativePath(scriptImport.destPath);
|
|
1032
|
-
//if we can't find the file
|
|
1033
|
-
if (!referencedFile) {
|
|
1034
|
-
//skip the default bslib file, it will exist at transpile time but should not show up in the program during validation cycle
|
|
1035
|
-
if (scriptImport.destPath === this.program.bslibPkgPath) {
|
|
1036
|
-
continue;
|
|
1037
|
-
}
|
|
1038
|
-
let dInfo;
|
|
1039
|
-
if (scriptImport.text.trim().length === 0) {
|
|
1040
|
-
dInfo = DiagnosticMessages_1.DiagnosticMessages.scriptSrcCannotBeEmpty();
|
|
1041
|
-
}
|
|
1042
|
-
else {
|
|
1043
|
-
dInfo = DiagnosticMessages_1.DiagnosticMessages.referencedFileDoesNotExist();
|
|
1044
|
-
}
|
|
1045
|
-
this.diagnostics.push(Object.assign(Object.assign({}, dInfo), { range: scriptImport.filePathRange, file: scriptImport.sourceFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
1046
|
-
//if the character casing of the script import path does not match that of the actual path
|
|
1047
|
-
}
|
|
1048
|
-
else if (scriptImport.destPath !== referencedFile.destPath) {
|
|
1049
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scriptImportCaseMismatch(referencedFile.destPath)), { range: scriptImport.filePathRange, file: scriptImport.sourceFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
866
|
/**
|
|
1054
867
|
* Find the file with the specified relative path
|
|
1055
868
|
*/
|