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.
Files changed (168) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +1 -1
  3. package/dist/AstValidationSegmenter.d.ts +12 -2
  4. package/dist/AstValidationSegmenter.js +74 -16
  5. package/dist/AstValidationSegmenter.js.map +1 -1
  6. package/dist/DependencyGraph.d.ts +4 -0
  7. package/dist/DependencyGraph.js +19 -0
  8. package/dist/DependencyGraph.js.map +1 -1
  9. package/dist/DiagnosticFilterer.d.ts +7 -4
  10. package/dist/DiagnosticFilterer.js +67 -37
  11. package/dist/DiagnosticFilterer.js.map +1 -1
  12. package/dist/DiagnosticMessages.d.ts +1 -1
  13. package/dist/PluginInterface.js +1 -1
  14. package/dist/PluginInterface.js.map +1 -1
  15. package/dist/Program.d.ts +19 -15
  16. package/dist/Program.js +153 -88
  17. package/dist/Program.js.map +1 -1
  18. package/dist/Scope.d.ts +27 -28
  19. package/dist/Scope.js +174 -361
  20. package/dist/Scope.js.map +1 -1
  21. package/dist/Stopwatch.d.ts +4 -0
  22. package/dist/Stopwatch.js +7 -0
  23. package/dist/Stopwatch.js.map +1 -1
  24. package/dist/SymbolTable.d.ts +2 -1
  25. package/dist/SymbolTable.js +26 -0
  26. package/dist/SymbolTable.js.map +1 -1
  27. package/dist/{SymbolTableFlag.js → SymbolTypeFlag.js} +1 -1
  28. package/dist/SymbolTypeFlag.js.map +1 -0
  29. package/dist/XmlScope.d.ts +0 -8
  30. package/dist/XmlScope.js +0 -77
  31. package/dist/XmlScope.js.map +1 -1
  32. package/dist/astUtils/CachedLookups.js +4 -8
  33. package/dist/astUtils/CachedLookups.js.map +1 -1
  34. package/dist/astUtils/creators.d.ts +1 -0
  35. package/dist/astUtils/creators.js +3 -2
  36. package/dist/astUtils/creators.js.map +1 -1
  37. package/dist/astUtils/creators.spec.js +0 -10
  38. package/dist/astUtils/creators.spec.js.map +1 -1
  39. package/dist/astUtils/reflection.d.ts +4 -4
  40. package/dist/astUtils/reflection.js +8 -7
  41. package/dist/astUtils/reflection.js.map +1 -1
  42. package/dist/astUtils/reflection.spec.js +10 -15
  43. package/dist/astUtils/reflection.spec.js.map +1 -1
  44. package/dist/astUtils/visitors.d.ts +1 -2
  45. package/dist/astUtils/visitors.js.map +1 -1
  46. package/dist/astUtils/visitors.spec.js +1 -5
  47. package/dist/astUtils/visitors.spec.js.map +1 -1
  48. package/dist/bscPlugin/BscPlugin.d.ts +3 -1
  49. package/dist/bscPlugin/BscPlugin.js +10 -0
  50. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  51. package/dist/bscPlugin/SignatureHelpUtil.js +4 -3
  52. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -1
  53. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -0
  54. package/dist/bscPlugin/completions/CompletionsProcessor.js +31 -11
  55. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  56. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +39 -0
  57. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
  58. package/dist/bscPlugin/hover/HoverProcessor.js +5 -5
  59. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  60. package/dist/bscPlugin/hover/HoverProcessor.spec.js +51 -5
  61. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  62. package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
  63. package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
  64. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
  65. package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
  66. package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
  67. package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
  68. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +1 -1
  69. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -1
  70. package/dist/bscPlugin/validation/BrsFileAfterValidatior.d.ts +7 -0
  71. package/dist/bscPlugin/validation/BrsFileAfterValidatior.js +18 -0
  72. package/dist/bscPlugin/validation/BrsFileAfterValidatior.js.map +1 -0
  73. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +1 -0
  74. package/dist/bscPlugin/validation/BrsFileValidator.js +17 -10
  75. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  76. package/dist/bscPlugin/validation/ScopeValidator.d.ts +37 -1
  77. package/dist/bscPlugin/validation/ScopeValidator.js +434 -25
  78. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  79. package/dist/bscPlugin/validation/ScopeValidator.spec.js +91 -4
  80. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  81. package/dist/files/BrsFile.Class.spec.js +11 -4
  82. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  83. package/dist/files/BrsFile.d.ts +23 -5
  84. package/dist/files/BrsFile.js +189 -51
  85. package/dist/files/BrsFile.js.map +1 -1
  86. package/dist/files/BrsFile.spec.js +589 -97
  87. package/dist/files/BrsFile.spec.js.map +1 -1
  88. package/dist/files/BscFile.d.ts +2 -1
  89. package/dist/files/BscFile.js.map +1 -1
  90. package/dist/files/XmlFile.d.ts +2 -2
  91. package/dist/files/XmlFile.js +2 -2
  92. package/dist/files/XmlFile.js.map +1 -1
  93. package/dist/index.d.ts +1 -0
  94. package/dist/index.js +1 -0
  95. package/dist/index.js.map +1 -1
  96. package/dist/interfaces.d.ts +43 -4
  97. package/dist/interfaces.js.map +1 -1
  98. package/dist/lexer/Lexer.d.ts +9 -3
  99. package/dist/lexer/Lexer.js +36 -15
  100. package/dist/lexer/Lexer.js.map +1 -1
  101. package/dist/lexer/Lexer.spec.js +76 -38
  102. package/dist/lexer/Lexer.spec.js.map +1 -1
  103. package/dist/lexer/Token.js +1 -1
  104. package/dist/lexer/Token.js.map +1 -1
  105. package/dist/lexer/TokenKind.d.ts +1 -0
  106. package/dist/lexer/TokenKind.js +4 -1
  107. package/dist/lexer/TokenKind.js.map +1 -1
  108. package/dist/parser/AstNode.d.ts +1 -2
  109. package/dist/parser/AstNode.js +0 -1
  110. package/dist/parser/AstNode.js.map +1 -1
  111. package/dist/parser/BrsTranspileState.d.ts +1 -1
  112. package/dist/parser/Expression.d.ts +77 -47
  113. package/dist/parser/Expression.js +162 -88
  114. package/dist/parser/Expression.js.map +1 -1
  115. package/dist/parser/Parser.d.ts +7 -2
  116. package/dist/parser/Parser.js +40 -90
  117. package/dist/parser/Parser.js.map +1 -1
  118. package/dist/parser/Parser.spec.js +21 -44
  119. package/dist/parser/Parser.spec.js.map +1 -1
  120. package/dist/parser/SGTypes.js +5 -5
  121. package/dist/parser/SGTypes.js.map +1 -1
  122. package/dist/parser/Statement.d.ts +92 -84
  123. package/dist/parser/Statement.js +199 -133
  124. package/dist/parser/Statement.js.map +1 -1
  125. package/dist/parser/Statement.spec.js +0 -13
  126. package/dist/parser/Statement.spec.js.map +1 -1
  127. package/dist/parser/TranspileState.d.ts +17 -8
  128. package/dist/parser/TranspileState.js +67 -8
  129. package/dist/parser/TranspileState.js.map +1 -1
  130. package/dist/parser/tests/Parser.spec.d.ts +1 -1
  131. package/dist/parser/tests/Parser.spec.js +1 -2
  132. package/dist/parser/tests/Parser.spec.js.map +1 -1
  133. package/dist/parser/tests/controlFlow/If.spec.js +1 -1
  134. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  135. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +1 -3
  136. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  137. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +44 -0
  138. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  139. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +6 -6
  140. package/dist/parser/tests/expression/TernaryExpression.spec.js +47 -0
  141. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  142. package/dist/parser/tests/statement/ConstStatement.spec.js +2 -2
  143. package/dist/parser/tests/statement/InterfaceStatement.spec.js +8 -1
  144. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  145. package/dist/parser/tests/statement/Misc.spec.js +25 -5
  146. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  147. package/dist/preprocessor/Chunk.js +1 -2
  148. package/dist/preprocessor/Chunk.js.map +1 -1
  149. package/dist/preprocessor/PreprocessorParser.js +2 -1
  150. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  151. package/dist/types/AssociativeArrayType.d.ts +3 -0
  152. package/dist/types/AssociativeArrayType.js +9 -0
  153. package/dist/types/AssociativeArrayType.js.map +1 -1
  154. package/dist/types/BscType.d.ts +1 -1
  155. package/dist/types/BscType.js +1 -0
  156. package/dist/types/BscType.js.map +1 -1
  157. package/dist/types/ComponentType.d.ts +1 -1
  158. package/dist/types/ReferenceType.d.ts +9 -1
  159. package/dist/types/ReferenceType.js +45 -1
  160. package/dist/types/ReferenceType.js.map +1 -1
  161. package/dist/types/ReferenceType.spec.js +15 -0
  162. package/dist/types/ReferenceType.spec.js.map +1 -1
  163. package/dist/util.d.ts +23 -9
  164. package/dist/util.js +115 -21
  165. package/dist/util.js.map +1 -1
  166. package/package.json +6 -3
  167. package/dist/SymbolTableFlag.js.map +0 -1
  168. /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 AstNode_1 = require("./parser/AstNode");
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
- const lowerClassName = className === null || className === void 0 ? void 0 : className.toLowerCase();
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(util_1.util.getFullyQualifiedClassName(lowerClassName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
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(lowerClassName);
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(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
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(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
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(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
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, _b, _c, _d, _e, _f;
270
+ getAllFileLinks(name, containingNamespace, includeNamespaces = false, includeNameShadowsOutsideNamespace = false) {
271
+ var _a;
217
272
  let links = [];
218
- links.push((_a = this.getClassFileLink(name)) !== null && _a !== void 0 ? _a : this.getClassFileLink(name, containingNamespace), (_b = this.getInterfaceFileLink(name)) !== null && _b !== void 0 ? _b : this.getInterfaceFileLink(name, containingNamespace), (_c = this.getConstFileLink(name)) !== null && _c !== void 0 ? _c : this.getConstFileLink(name, containingNamespace), (_d = this.getEnumFileLink(name)) !== null && _d !== void 0 ? _d : this.getEnumFileLink(name, containingNamespace));
219
- const nameSpaces = this.getNamespacesWithRoot(name, containingNamespace);
220
- if ((nameSpaces === null || nameSpaces === void 0 ? void 0 : nameSpaces.length) > 0) {
221
- const nsContainersWithStatement = (_e = nameSpaces.filter(nsContainer => { var _a; return ((_a = nsContainer === null || nsContainer === void 0 ? void 0 : nsContainer.namespaceStatements) === null || _a === void 0 ? void 0 : _a.length) > 0; })) === null || _e === void 0 ? void 0 : _e[0];
222
- if (nsContainersWithStatement) {
223
- links.push({ item: (_f = nsContainersWithStatement === null || nsContainersWithStatement === void 0 ? void 0 : nsContainersWithStatement.namespaceStatements) === null || _f === void 0 ? void 0 : _f[0], file: nsContainersWithStatement === null || nsContainersWithStatement === void 0 ? void 0 : nsContainersWithStatement.file });
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(/$component:/, ''));
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._validate(callableContainerMap);
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
- //Add namespace aggregates to namespace member tables
734
- const namespaceTypesKnown = new Map();
735
- // eslint-disable-next-line no-bitwise
736
- let getTypeOptions = { flags: 1 /* SymbolTypeFlag.runtime */ | 2 /* SymbolTypeFlag.typetime */ };
737
- for (const [nsName, nsContainer] of this.namespaceLookup) {
738
- let currentNSType = null;
739
- let parentNSType = null;
740
- const existingNsStmt = (_a = nsContainer.namespaceStatements) === null || _a === void 0 ? void 0 : _a[0];
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
  */