brighterscript 1.0.0-alpha.26 → 1.0.0-alpha.28

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 (200) hide show
  1. package/CHANGELOG.md +82 -5
  2. package/README.md +1 -1
  3. package/dist/AstValidationSegmenter.d.ts +1 -1
  4. package/dist/AstValidationSegmenter.js +4 -5
  5. package/dist/AstValidationSegmenter.js.map +1 -1
  6. package/dist/DiagnosticFilterer.d.ts +7 -4
  7. package/dist/DiagnosticFilterer.js +67 -37
  8. package/dist/DiagnosticFilterer.js.map +1 -1
  9. package/dist/DiagnosticMessages.d.ts +1 -3
  10. package/dist/DiagnosticMessages.js +5 -8
  11. package/dist/DiagnosticMessages.js.map +1 -1
  12. package/dist/PluginInterface.js +1 -1
  13. package/dist/PluginInterface.js.map +1 -1
  14. package/dist/Program.d.ts +1 -1
  15. package/dist/Program.js +34 -31
  16. package/dist/Program.js.map +1 -1
  17. package/dist/Scope.d.ts +7 -34
  18. package/dist/Scope.js +45 -305
  19. package/dist/Scope.js.map +1 -1
  20. package/dist/SymbolTable.d.ts +1 -8
  21. package/dist/SymbolTable.js +1 -10
  22. package/dist/SymbolTable.js.map +1 -1
  23. package/dist/SymbolTypeFlag.d.ts +8 -0
  24. package/dist/SymbolTypeFlag.js +13 -0
  25. package/dist/SymbolTypeFlag.js.map +1 -0
  26. package/dist/XmlScope.d.ts +0 -8
  27. package/dist/XmlScope.js +6 -84
  28. package/dist/XmlScope.js.map +1 -1
  29. package/dist/astUtils/CachedLookups.d.ts +1 -2
  30. package/dist/astUtils/CachedLookups.js +4 -19
  31. package/dist/astUtils/CachedLookups.js.map +1 -1
  32. package/dist/astUtils/creators.d.ts +1 -0
  33. package/dist/astUtils/creators.js +48 -8
  34. package/dist/astUtils/creators.js.map +1 -1
  35. package/dist/astUtils/creators.spec.js +0 -10
  36. package/dist/astUtils/creators.spec.js.map +1 -1
  37. package/dist/astUtils/reflection.d.ts +3 -2
  38. package/dist/astUtils/reflection.js +11 -7
  39. package/dist/astUtils/reflection.js.map +1 -1
  40. package/dist/astUtils/reflection.spec.js +11 -16
  41. package/dist/astUtils/reflection.spec.js.map +1 -1
  42. package/dist/astUtils/visitors.d.ts +1 -2
  43. package/dist/astUtils/visitors.js.map +1 -1
  44. package/dist/astUtils/visitors.spec.js +1 -5
  45. package/dist/astUtils/visitors.spec.js.map +1 -1
  46. package/dist/bscPlugin/BscPlugin.d.ts +2 -1
  47. package/dist/bscPlugin/BscPlugin.js +4 -0
  48. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  49. package/dist/bscPlugin/SignatureHelpUtil.js +4 -3
  50. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -1
  51. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -0
  52. package/dist/bscPlugin/completions/CompletionsProcessor.js +46 -29
  53. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  54. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +39 -0
  55. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
  56. package/dist/bscPlugin/hover/HoverProcessor.d.ts +1 -0
  57. package/dist/bscPlugin/hover/HoverProcessor.js +30 -10
  58. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  59. package/dist/bscPlugin/hover/HoverProcessor.spec.js +125 -7
  60. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  61. package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
  62. package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
  63. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
  64. package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
  65. package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
  66. package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
  67. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +2 -3
  68. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  69. package/dist/bscPlugin/validation/BrsFileValidator.js +25 -31
  70. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  71. package/dist/bscPlugin/validation/ScopeValidator.d.ts +34 -1
  72. package/dist/bscPlugin/validation/ScopeValidator.js +435 -27
  73. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  74. package/dist/bscPlugin/validation/ScopeValidator.spec.js +178 -10
  75. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  76. package/dist/diagnosticUtils.d.ts +1 -1
  77. package/dist/files/BrsFile.Class.spec.js +15 -7
  78. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  79. package/dist/files/BrsFile.d.ts +14 -5
  80. package/dist/files/BrsFile.js +83 -150
  81. package/dist/files/BrsFile.js.map +1 -1
  82. package/dist/files/BrsFile.spec.js +429 -162
  83. package/dist/files/BrsFile.spec.js.map +1 -1
  84. package/dist/files/XmlFile.d.ts +2 -3
  85. package/dist/files/XmlFile.js +1 -3
  86. package/dist/files/XmlFile.js.map +1 -1
  87. package/dist/index.d.ts +1 -0
  88. package/dist/index.js +1 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/interfaces.d.ts +117 -85
  91. package/dist/interfaces.js +9 -9
  92. package/dist/interfaces.js.map +1 -1
  93. package/dist/lexer/Lexer.d.ts +9 -3
  94. package/dist/lexer/Lexer.js +36 -15
  95. package/dist/lexer/Lexer.js.map +1 -1
  96. package/dist/lexer/Lexer.spec.js +76 -38
  97. package/dist/lexer/Lexer.spec.js.map +1 -1
  98. package/dist/lexer/Token.js +1 -1
  99. package/dist/lexer/Token.js.map +1 -1
  100. package/dist/lexer/TokenKind.d.ts +1 -0
  101. package/dist/lexer/TokenKind.js +4 -1
  102. package/dist/lexer/TokenKind.js.map +1 -1
  103. package/dist/parser/AstNode.d.ts +1 -2
  104. package/dist/parser/AstNode.js +0 -1
  105. package/dist/parser/AstNode.js.map +1 -1
  106. package/dist/parser/BrsTranspileState.d.ts +1 -1
  107. package/dist/parser/Expression.d.ts +153 -135
  108. package/dist/parser/Expression.js +204 -114
  109. package/dist/parser/Expression.js.map +1 -1
  110. package/dist/parser/Parser.Class.spec.js +15 -16
  111. package/dist/parser/Parser.Class.spec.js.map +1 -1
  112. package/dist/parser/Parser.d.ts +8 -4
  113. package/dist/parser/Parser.js +108 -149
  114. package/dist/parser/Parser.js.map +1 -1
  115. package/dist/parser/Parser.spec.js +48 -72
  116. package/dist/parser/Parser.spec.js.map +1 -1
  117. package/dist/parser/SGParser.js +49 -35
  118. package/dist/parser/SGParser.js.map +1 -1
  119. package/dist/parser/SGTypes.d.ts +36 -24
  120. package/dist/parser/SGTypes.js +31 -60
  121. package/dist/parser/SGTypes.js.map +1 -1
  122. package/dist/parser/Statement.d.ts +214 -207
  123. package/dist/parser/Statement.js +248 -169
  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 +64 -6
  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/expression/TypeExpression.spec.js +8 -9
  143. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -1
  144. package/dist/parser/tests/statement/ConstStatement.spec.js +2 -2
  145. package/dist/parser/tests/statement/InterfaceStatement.spec.js +8 -1
  146. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  147. package/dist/parser/tests/statement/Misc.spec.js +25 -5
  148. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  149. package/dist/parser/tests/statement/TryCatch.spec.js +9 -2
  150. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  151. package/dist/preprocessor/Chunk.js +1 -2
  152. package/dist/preprocessor/Chunk.js.map +1 -1
  153. package/dist/preprocessor/PreprocessorParser.js +2 -1
  154. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  155. package/dist/roku-types/data.json +70 -52
  156. package/dist/roku-types/index.d.ts +43 -21
  157. package/dist/types/ArrayType.js +1 -2
  158. package/dist/types/ArrayType.js.map +1 -1
  159. package/dist/types/ArrayType.spec.js +7 -8
  160. package/dist/types/ArrayType.spec.js.map +1 -1
  161. package/dist/types/AssociativeArrayType.d.ts +3 -0
  162. package/dist/types/AssociativeArrayType.js +10 -2
  163. package/dist/types/AssociativeArrayType.js.map +1 -1
  164. package/dist/types/BscType.d.ts +1 -1
  165. package/dist/types/BscType.js +3 -3
  166. package/dist/types/BscType.js.map +1 -1
  167. package/dist/types/BuiltInInterfaceAdder.js +7 -8
  168. package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
  169. package/dist/types/BuiltInInterfaceAdder.spec.js +31 -32
  170. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -1
  171. package/dist/types/ClassType.spec.js +10 -11
  172. package/dist/types/ClassType.spec.js.map +1 -1
  173. package/dist/types/ComponentType.d.ts +2 -1
  174. package/dist/types/ComponentType.js.map +1 -1
  175. package/dist/types/EnumType.js +2 -3
  176. package/dist/types/EnumType.js.map +1 -1
  177. package/dist/types/InheritableType.js +3 -4
  178. package/dist/types/InheritableType.js.map +1 -1
  179. package/dist/types/InterfaceType.js +2 -3
  180. package/dist/types/InterfaceType.js.map +1 -1
  181. package/dist/types/InterfaceType.spec.js +3 -4
  182. package/dist/types/InterfaceType.spec.js.map +1 -1
  183. package/dist/types/ObjectType.js +1 -2
  184. package/dist/types/ObjectType.js.map +1 -1
  185. package/dist/types/ReferenceType.d.ts +1 -1
  186. package/dist/types/ReferenceType.spec.js +21 -22
  187. package/dist/types/ReferenceType.spec.js.map +1 -1
  188. package/dist/types/UnionType.js +3 -3
  189. package/dist/types/UnionType.js.map +1 -1
  190. package/dist/types/UnionType.spec.js +37 -38
  191. package/dist/types/UnionType.spec.js.map +1 -1
  192. package/dist/types/helper.spec.js +4 -5
  193. package/dist/types/helper.spec.js.map +1 -1
  194. package/dist/util.d.ts +21 -11
  195. package/dist/util.js +116 -37
  196. package/dist/util.js.map +1 -1
  197. package/dist/validators/ClassValidator.d.ts +0 -9
  198. package/dist/validators/ClassValidator.js +3 -46
  199. package/dist/validators/ClassValidator.js.map +1 -1
  200. package/package.json +6 -3
@@ -6,14 +6,17 @@ const reflection_1 = require("../../astUtils/reflection");
6
6
  const Cache_1 = require("../../Cache");
7
7
  const DiagnosticMessages_1 = require("../../DiagnosticMessages");
8
8
  const interfaces_1 = require("../../interfaces");
9
- const SymbolTable_1 = require("../../SymbolTable");
10
9
  const util_1 = require("../../util");
11
10
  const roku_types_1 = require("../../roku-types");
11
+ const AstNode_1 = require("../../parser/AstNode");
12
12
  const Expression_1 = require("../../parser/Expression");
13
13
  const visitors_1 = require("../../astUtils/visitors");
14
14
  const AstValidationSegmenter_1 = require("../../AstValidationSegmenter");
15
15
  const TokenKind_1 = require("../../lexer/TokenKind");
16
16
  const Parser_1 = require("../../parser/Parser");
17
+ const ClassValidator_1 = require("../../validators/ClassValidator");
18
+ const globalCallables_1 = require("../../globalCallables");
19
+ const SGTypes_1 = require("../../parser/SGTypes");
17
20
  /**
18
21
  * The lower-case names of all platform-included scenegraph nodes
19
22
  */
@@ -37,6 +40,15 @@ class ScopeValidator {
37
40
  }
38
41
  this.walkFiles();
39
42
  this.detectDuplicateEnums();
43
+ this.flagDuplicateFunctionDeclarations();
44
+ this.validateScriptImportPaths();
45
+ this.validateClasses();
46
+ if ((0, reflection_1.isXmlScope)(event.scope)) {
47
+ //detect when the child imports a script that its ancestor also imports
48
+ this.diagnosticDetectDuplicateAncestorScriptImports(event.scope);
49
+ //validate component interface
50
+ this.validateXmlInterface(event.scope);
51
+ }
40
52
  }
41
53
  reset() {
42
54
  this.event = undefined;
@@ -44,13 +56,19 @@ class ScopeValidator {
44
56
  this.multiScopeCache.clear();
45
57
  }
46
58
  walkFiles() {
59
+ //do many per-file checks for every file in this (and parent) scopes
60
+ this.event.scope.enumerateBrsFiles((file) => {
61
+ this.diagnosticDetectFunctionCollisions(file);
62
+ this.detectVariableNamespaceCollisions(file);
63
+ this.detectNameCollisions(file);
64
+ });
47
65
  this.event.scope.enumerateOwnFiles((file) => {
48
66
  if ((0, reflection_1.isBrsFile)(file)) {
49
67
  const hasChangeInfo = this.event.changedFiles && this.event.changedSymbols;
50
68
  let thisFileRequiresChangedSymbol = false;
51
69
  for (let requiredSymbol of file.requiredSymbols) {
52
70
  // eslint-disable-next-line no-bitwise
53
- for (const flag of [SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.typetime]) {
71
+ for (const flag of [1 /* SymbolTypeFlag.runtime */, 2 /* SymbolTypeFlag.typetime */]) {
54
72
  // eslint-disable-next-line no-bitwise
55
73
  if (flag & requiredSymbol.flags) {
56
74
  const changeSymbolSetForFlag = this.event.changedSymbols.get(flag);
@@ -93,6 +111,9 @@ class ScopeValidator {
93
111
  },
94
112
  AssignmentStatement: (assignStmt) => {
95
113
  this.validateAssignmentStatement(file, assignStmt);
114
+ },
115
+ NewExpression: (newExpr) => {
116
+ this.validateNewExpression(file, newExpr);
96
117
  }
97
118
  });
98
119
  const segmentsToWalkForValidation = (thisFileHasChanges || !hasChangeInfo)
@@ -116,7 +137,7 @@ class ScopeValidator {
116
137
  /**
117
138
  * If this is the lhs of an assignment, we don't need to flag it as unresolved
118
139
  */
119
- ignoreUnresolvedAssignmentLHS(expression, exprType, definingNode) {
140
+ hasValidDeclaration(expression, exprType, definingNode) {
120
141
  var _a, _b;
121
142
  if (!(0, reflection_1.isVariableExpression)(expression)) {
122
143
  return false;
@@ -127,6 +148,10 @@ class ScopeValidator {
127
148
  assignmentAncestor = definingNode;
128
149
  return ((_a = assignmentAncestor === null || assignmentAncestor === void 0 ? void 0 : assignmentAncestor.tokens.name) === null || _a === void 0 ? void 0 : _a.text.toLowerCase()) === ((_b = expression === null || expression === void 0 ? void 0 : expression.tokens.name) === null || _b === void 0 ? void 0 : _b.text.toLowerCase());
129
150
  }
151
+ else if ((0, reflection_1.isFunctionParameterExpression)(definingNode)) {
152
+ // this symbol was defined in a function param
153
+ return true;
154
+ }
130
155
  else {
131
156
  assignmentAncestor = expression === null || expression === void 0 ? void 0 : expression.findAncestor(reflection_1.isAssignmentStatement);
132
157
  }
@@ -241,7 +266,7 @@ class ScopeValidator {
241
266
  */
242
267
  validateFunctionCall(file, expression) {
243
268
  var _a, _b;
244
- const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime, data: {} };
269
+ const getTypeOptions = { flags: 1 /* SymbolTypeFlag.runtime */, data: {} };
245
270
  let funcType = (_a = expression === null || expression === void 0 ? void 0 : expression.callee) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
246
271
  if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isClassType)(funcType)) {
247
272
  // We're calling a class - get the constructor
@@ -274,7 +299,7 @@ class ScopeValidator {
274
299
  let paramIndex = 0;
275
300
  for (let arg of expression.args) {
276
301
  const data = {};
277
- let argType = arg.getType({ flags: SymbolTable_1.SymbolTypeFlag.runtime, data: data });
302
+ let argType = arg.getType({ flags: 1 /* SymbolTypeFlag.runtime */, data: data });
278
303
  const paramType = (_b = funcType.params[paramIndex]) === null || _b === void 0 ? void 0 : _b.type;
279
304
  if (!paramType) {
280
305
  // unable to find a paramType -- maybe there are more args than params
@@ -302,8 +327,8 @@ class ScopeValidator {
302
327
  */
303
328
  validateReturnStatement(file, returnStmt) {
304
329
  var _a;
305
- const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
306
- let funcType = returnStmt.findAncestor(reflection_1.isFunctionExpression).getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
330
+ const getTypeOptions = { flags: 1 /* SymbolTypeFlag.runtime */ };
331
+ let funcType = returnStmt.findAncestor(reflection_1.isFunctionExpression).getType({ flags: 2 /* SymbolTypeFlag.typetime */ });
307
332
  if ((0, reflection_1.isTypedFunctionType)(funcType)) {
308
333
  const actualReturnType = (_a = returnStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
309
334
  const compatibilityData = {};
@@ -318,7 +343,7 @@ class ScopeValidator {
318
343
  validateDottedSetStatement(file, dottedSetStmt) {
319
344
  var _a;
320
345
  const typeChainExpectedLHS = [];
321
- const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
346
+ const getTypeOpts = { flags: 1 /* SymbolTypeFlag.runtime */ };
322
347
  const expectedLHSType = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.getType(Object.assign(Object.assign({}, getTypeOpts), { data: {}, typeChain: typeChainExpectedLHS }));
323
348
  const actualRHSType = (_a = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOpts);
324
349
  const compatibilityData = {};
@@ -348,11 +373,14 @@ class ScopeValidator {
348
373
  return;
349
374
  }
350
375
  const typeChainExpectedLHS = [];
351
- const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
376
+ const getTypeOpts = { flags: 1 /* SymbolTypeFlag.runtime */ };
352
377
  const expectedLHSType = assignStmt.typeExpression.getType(Object.assign(Object.assign({}, getTypeOpts), { data: {}, typeChain: typeChainExpectedLHS }));
353
378
  const actualRHSType = (_a = assignStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOpts);
354
379
  const compatibilityData = {};
355
- if (!(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
380
+ if (!expectedLHSType || !expectedLHSType.isResolvable()) {
381
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(assignStmt.typeExpression.getName(Parser_1.ParseMode.BrighterScript))), { range: assignStmt.typeExpression.range, file: file }));
382
+ }
383
+ else if (!(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
356
384
  this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch(actualRHSType.toString(), expectedLHSType.toString(), compatibilityData)), { range: assignStmt.range, file: file }));
357
385
  }
358
386
  }
@@ -360,7 +388,7 @@ class ScopeValidator {
360
388
  * Detect invalid use of a binary operator
361
389
  */
362
390
  validateBinaryExpression(file, binaryExpr) {
363
- const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
391
+ const getTypeOpts = { flags: 1 /* SymbolTypeFlag.runtime */ };
364
392
  if (util_1.default.isInTypeExpression(binaryExpr)) {
365
393
  return;
366
394
  }
@@ -405,7 +433,7 @@ class ScopeValidator {
405
433
  * Detect invalid use of a Unary operator
406
434
  */
407
435
  validateUnaryExpression(file, unaryExpr) {
408
- const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
436
+ const getTypeOpts = { flags: 1 /* SymbolTypeFlag.runtime */ };
409
437
  let rightType = unaryExpr.right.getType(getTypeOpts);
410
438
  if (!rightType.isResolvable()) {
411
439
  // Can not find the type. error handled elsewhere
@@ -434,7 +462,7 @@ class ScopeValidator {
434
462
  }
435
463
  }
436
464
  validateVariableAndDottedGetExpressions(file, expression) {
437
- var _a, _b;
465
+ var _a, _b, _c, _d;
438
466
  if ((0, reflection_1.isDottedGetExpression)(expression.parent)) {
439
467
  // We validate dottedGetExpressions at the top-most level
440
468
  return;
@@ -448,13 +476,13 @@ class ScopeValidator {
448
476
  return;
449
477
  }
450
478
  }
451
- let symbolType = SymbolTable_1.SymbolTypeFlag.runtime;
452
- let oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.typetime;
479
+ let symbolType = 1 /* SymbolTypeFlag.runtime */;
480
+ let oppositeSymbolType = 2 /* SymbolTypeFlag.typetime */;
453
481
  const isUsedAsType = util_1.default.isInTypeExpression(expression);
454
482
  if (isUsedAsType) {
455
483
  // This is used in a TypeExpression - only look up types from SymbolTable
456
- symbolType = SymbolTable_1.SymbolTypeFlag.typetime;
457
- oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.runtime;
484
+ symbolType = 2 /* SymbolTypeFlag.typetime */;
485
+ oppositeSymbolType = 1 /* SymbolTypeFlag.runtime */;
458
486
  }
459
487
  // Do a complete type check on all DottedGet and Variable expressions
460
488
  // this will create a diagnostic if an invalid member is accessed
@@ -465,18 +493,22 @@ class ScopeValidator {
465
493
  typeChain: typeChain,
466
494
  data: typeData
467
495
  });
468
- const shouldIgnoreLHS = this.ignoreUnresolvedAssignmentLHS(expression, exprType, typeData === null || typeData === void 0 ? void 0 : typeData.definingNode);
469
- if (!this.isTypeKnown(exprType) && !shouldIgnoreLHS) {
470
- if ((_a = expression.getType({ flags: oppositeSymbolType })) === null || _a === void 0 ? void 0 : _a.isResolvable()) {
496
+ const hasValidDeclaration = this.hasValidDeclaration(expression, exprType, typeData === null || typeData === void 0 ? void 0 : typeData.definingNode);
497
+ if (!this.isTypeKnown(exprType) && !hasValidDeclaration) {
498
+ if ((_a = expression.getType({ flags: oppositeSymbolType, isExistenceTest: true })) === null || _a === void 0 ? void 0 : _a.isResolvable()) {
471
499
  const oppoSiteTypeChain = [];
472
- const invalidlyUsedResolvedType = expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain });
500
+ const invalidlyUsedResolvedType = expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain, isExistenceTest: true });
473
501
  const typeChainScan = util_1.default.processTypeChain(oppoSiteTypeChain);
474
502
  if (isUsedAsType) {
475
503
  this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsType(typeChainScan.fullChainName)), { range: expression.range, file: file }));
476
504
  }
477
- else {
505
+ else if (invalidlyUsedResolvedType && !(0, reflection_1.isReferenceType)(invalidlyUsedResolvedType)) {
478
506
  this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: expression.range, file: file }));
479
507
  }
508
+ else {
509
+ const typeChainScan = util_1.default.processTypeChain(typeChain);
510
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
511
+ }
480
512
  }
481
513
  else {
482
514
  const typeChainScan = util_1.default.processTypeChain(typeChain);
@@ -486,6 +518,14 @@ class ScopeValidator {
486
518
  if (isUsedAsType) {
487
519
  return;
488
520
  }
521
+ const containingNamespaceName = (_b = expression.findAncestor(reflection_1.isNamespaceStatement)) === null || _b === void 0 ? void 0 : _b.getName(Parser_1.ParseMode.BrighterScript);
522
+ if (!((0, reflection_1.isCallExpression)(expression.parent) && (0, reflection_1.isNewExpression)((_c = expression.parent) === null || _c === void 0 ? void 0 : _c.parent))) {
523
+ const classUsedAsVarEntry = this.checkTypeChainForClassUsedAsVar(typeChain, containingNamespaceName);
524
+ if (classUsedAsVarEntry) {
525
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(classUsedAsVarEntry.toString())), { range: expression.range, file: file }));
526
+ return;
527
+ }
528
+ }
489
529
  const lastTypeInfo = typeChain[typeChain.length - 1];
490
530
  const parentTypeInfo = typeChain[typeChain.length - 2];
491
531
  this.checkMemberAccessibility(file, expression, typeChain);
@@ -505,11 +545,35 @@ class ScopeValidator {
505
545
  if (enumFileLink) {
506
546
  this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownEnumValue(lastTypeInfo === null || lastTypeInfo === void 0 ? void 0 : lastTypeInfo.name, typeChainScanForParent.fullChainName)), { range: lastTypeInfo === null || lastTypeInfo === void 0 ? void 0 : lastTypeInfo.range, relatedInformation: [{
507
547
  message: 'Enum declared here',
508
- location: util_1.default.createLocation(vscode_uri_1.URI.file(enumFileLink === null || enumFileLink === void 0 ? void 0 : enumFileLink.file.srcPath).toString(), (_b = enumFileLink === null || enumFileLink === void 0 ? void 0 : enumFileLink.item) === null || _b === void 0 ? void 0 : _b.tokens.name.range)
548
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(enumFileLink === null || enumFileLink === void 0 ? void 0 : enumFileLink.file.srcPath).toString(), (_d = enumFileLink === null || enumFileLink === void 0 ? void 0 : enumFileLink.item) === null || _d === void 0 ? void 0 : _d.tokens.name.range)
509
549
  }] }));
510
550
  }
511
551
  }
512
552
  }
553
+ checkTypeChainForClassUsedAsVar(typeChain, containingNamespaceName) {
554
+ const ignoreKinds = [AstNode_1.AstNodeKind.TypeCastExpression, AstNode_1.AstNodeKind.NewExpression];
555
+ let lowerNameSoFar = '';
556
+ let classUsedAsVar;
557
+ let isFirst = true;
558
+ for (let i = 0; i < typeChain.length - 1; i++) { // do not look at final entry - we CAN use the constructor as a variable
559
+ const tce = typeChain[i];
560
+ lowerNameSoFar += `${lowerNameSoFar ? '.' : ''}${tce.name.toLowerCase()}`;
561
+ if (!(0, reflection_1.isNamespaceType)(tce.type)) {
562
+ if (isFirst && containingNamespaceName) {
563
+ lowerNameSoFar = `${containingNamespaceName.toLowerCase()}.${lowerNameSoFar}`;
564
+ }
565
+ if (!tce.kind || ignoreKinds.includes(tce.kind)) {
566
+ break;
567
+ }
568
+ else if ((0, reflection_1.isClassType)(tce.type) && lowerNameSoFar.toLowerCase() === tce.type.name.toLowerCase()) {
569
+ classUsedAsVar = tce.type;
570
+ }
571
+ break;
572
+ }
573
+ isFirst = false;
574
+ }
575
+ return classUsedAsVar;
576
+ }
513
577
  /**
514
578
  * Adds diagnostics for accibility mismatches
515
579
  *
@@ -530,7 +594,7 @@ class ScopeValidator {
530
594
  const definingClassName = classStmtThatDefinesChildMember.getName(Parser_1.ParseMode.BrighterScript);
531
595
  const inMatchingClassStmt = (containingClassStmt === null || containingClassStmt === void 0 ? void 0 : containingClassStmt.getName(Parser_1.ParseMode.BrighterScript).toLowerCase()) === parentChainItem.type.name.toLowerCase();
532
596
  // eslint-disable-next-line no-bitwise
533
- if (childChainItem.data.flags & SymbolTable_1.SymbolTypeFlag.private) {
597
+ if (childChainItem.data.flags & 8 /* SymbolTypeFlag.private */) {
534
598
  if (!inMatchingClassStmt || childChainItem.data.memberOfAncestor) {
535
599
  this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch(childChainItem.name, childChainItem.data.flags, definingClassName)), { range: expression.range, file: file }));
536
600
  // there's an error... don't worry about the rest of the chain
@@ -538,7 +602,7 @@ class ScopeValidator {
538
602
  }
539
603
  }
540
604
  // eslint-disable-next-line no-bitwise
541
- if (childChainItem.data.flags & SymbolTable_1.SymbolTypeFlag.protected) {
605
+ if (childChainItem.data.flags & 16 /* SymbolTypeFlag.protected */) {
542
606
  const containingClassName = containingClassStmt === null || containingClassStmt === void 0 ? void 0 : containingClassStmt.getName(Parser_1.ParseMode.BrighterScript);
543
607
  const containingNamespaceName = (_c = expression.findAncestor(reflection_1.isNamespaceStatement)) === null || _c === void 0 ? void 0 : _c.getName(Parser_1.ParseMode.BrighterScript);
544
608
  const ancestorClasses = this.event.scope.getClassHierarchy(containingClassName, containingNamespaceName).map(link => link.item);
@@ -554,12 +618,356 @@ class ScopeValidator {
554
618
  }
555
619
  return true;
556
620
  }
621
+ /**
622
+ * Find all "new" statements in the program,
623
+ * and make sure we can find a class with that name
624
+ */
625
+ validateNewExpression(file, newExpression) {
626
+ var _a;
627
+ let potentialClassName = newExpression.className.getName(Parser_1.ParseMode.BrighterScript);
628
+ const namespaceName = (_a = newExpression.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript);
629
+ let newableClass = this.event.scope.getClass(potentialClassName, namespaceName);
630
+ if (!newableClass) {
631
+ //try and find functions with this name.
632
+ let fullName = util_1.default.getFullyQualifiedClassName(potentialClassName, namespaceName);
633
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expressionIsNotConstructable(fullName)), { file: file, range: newExpression.className.range }));
634
+ }
635
+ }
636
+ /**
637
+ * Create diagnostics for any duplicate function declarations
638
+ */
639
+ flagDuplicateFunctionDeclarations() {
640
+ //for each list of callables with the same name
641
+ for (let [lowerName, callableContainers] of this.event.scope.getCallableContainerMap()) {
642
+ let globalCallables = [];
643
+ let nonGlobalCallables = [];
644
+ let ownCallables = [];
645
+ let ancestorNonGlobalCallables = [];
646
+ for (let container of callableContainers) {
647
+ if (container.scope === this.event.program.globalScope) {
648
+ globalCallables.push(container);
649
+ }
650
+ else {
651
+ nonGlobalCallables.push(container);
652
+ if (container.scope === this.event.scope) {
653
+ ownCallables.push(container);
654
+ }
655
+ else {
656
+ ancestorNonGlobalCallables.push(container);
657
+ }
658
+ }
659
+ }
660
+ //add info diagnostics about child shadowing parent functions
661
+ if (ownCallables.length > 0 && ancestorNonGlobalCallables.length > 0) {
662
+ for (let container of ownCallables) {
663
+ //skip the init function (because every component will have one of those){
664
+ if (lowerName !== 'init') {
665
+ let shadowedCallable = ancestorNonGlobalCallables[ancestorNonGlobalCallables.length - 1];
666
+ if (!!shadowedCallable && shadowedCallable.callable.file === container.callable.file) {
667
+ //same file: skip redundant imports
668
+ continue;
669
+ }
670
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.overridesAncestorFunction(container.callable.name, container.scope.name, shadowedCallable.callable.file.destPath,
671
+ //grab the last item in the list, which should be the closest ancestor's version
672
+ shadowedCallable.scope.name)), { range: container.callable.nameRange, file: container.callable.file, origin: interfaces_1.DiagnosticOrigin.Scope }));
673
+ }
674
+ }
675
+ }
676
+ //add error diagnostics about duplicate functions in the same scope
677
+ if (ownCallables.length > 1) {
678
+ for (let callableContainer of ownCallables) {
679
+ let callable = callableContainer.callable;
680
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateFunctionImplementation(callable.name, callableContainer.scope.name)), { range: callable.nameRange, file: callable.file, origin: interfaces_1.DiagnosticOrigin.Scope }));
681
+ }
682
+ }
683
+ }
684
+ }
685
+ /**
686
+ * Verify that all of the scripts imported by each file in this scope actually exist, and have the correct case
687
+ */
688
+ validateScriptImportPaths() {
689
+ let scriptImports = this.event.scope.getOwnScriptImports();
690
+ //verify every script import
691
+ for (let scriptImport of scriptImports) {
692
+ let referencedFile = this.event.scope.getFileByRelativePath(scriptImport.destPath);
693
+ //if we can't find the file
694
+ if (!referencedFile) {
695
+ //skip the default bslib file, it will exist at transpile time but should not show up in the program during validation cycle
696
+ if (scriptImport.destPath === this.event.program.bslibPkgPath) {
697
+ continue;
698
+ }
699
+ let dInfo;
700
+ if (scriptImport.text.trim().length === 0) {
701
+ dInfo = DiagnosticMessages_1.DiagnosticMessages.scriptSrcCannotBeEmpty();
702
+ }
703
+ else {
704
+ dInfo = DiagnosticMessages_1.DiagnosticMessages.referencedFileDoesNotExist();
705
+ }
706
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, dInfo), { range: scriptImport.filePathRange, file: scriptImport.sourceFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
707
+ //if the character casing of the script import path does not match that of the actual path
708
+ }
709
+ else if (scriptImport.destPath !== referencedFile.destPath) {
710
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scriptImportCaseMismatch(referencedFile.destPath)), { range: scriptImport.filePathRange, file: scriptImport.sourceFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
711
+ }
712
+ }
713
+ }
714
+ /**
715
+ * Validate all classes defined in this scope
716
+ */
717
+ validateClasses() {
718
+ let validator = new ClassValidator_1.BsClassValidator(this.event.scope);
719
+ validator.validate();
720
+ for (const diagnostic of validator.diagnostics) {
721
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, diagnostic), { origin: interfaces_1.DiagnosticOrigin.Scope }));
722
+ }
723
+ }
724
+ /**
725
+ * Find various function collisions
726
+ */
727
+ diagnosticDetectFunctionCollisions(file) {
728
+ for (let func of file.callables) {
729
+ const funcName = func.getName(Parser_1.ParseMode.BrighterScript);
730
+ const lowerFuncName = funcName === null || funcName === void 0 ? void 0 : funcName.toLowerCase();
731
+ if (lowerFuncName) {
732
+ //find function declarations with the same name as a stdlib function
733
+ if (globalCallables_1.globalCallableMap.has(lowerFuncName)) {
734
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scopeFunctionShadowedByBuiltInFunction()), { range: func.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
735
+ }
736
+ //find any functions that have the same name as a class
737
+ const klassLink = this.event.scope.getClassFileLink(lowerFuncName);
738
+ if (klassLink) {
739
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionCannotHaveSameNameAsClass(funcName)), { range: func.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope, relatedInformation: [{
740
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(klassLink.file.srcPath).toString(), klassLink.item.tokens.name.range),
741
+ message: 'Original class declared here'
742
+ }] }));
743
+ }
744
+ }
745
+ }
746
+ }
747
+ detectNameCollisions(file) {
748
+ file.ast.walk((0, visitors_1.createVisitor)({
749
+ NamespaceStatement: (nsStmt) => {
750
+ var _a;
751
+ this.validateNameCollision(file, nsStmt, (_a = nsStmt.getNameParts()) === null || _a === void 0 ? void 0 : _a[0]);
752
+ },
753
+ ClassStatement: (classStmt) => {
754
+ this.validateNameCollision(file, classStmt, classStmt.tokens.name);
755
+ },
756
+ InterfaceStatement: (ifaceStmt) => {
757
+ this.validateNameCollision(file, ifaceStmt, ifaceStmt.tokens.name);
758
+ },
759
+ ConstStatement: (constStmt) => {
760
+ this.validateNameCollision(file, constStmt, constStmt.tokens.name);
761
+ },
762
+ EnumStatement: (enumStmt) => {
763
+ this.validateNameCollision(file, enumStmt, enumStmt.tokens.name);
764
+ },
765
+ AssignmentStatement: (assignStmt) => {
766
+ // Note: this also includes For statements
767
+ this.detectShadowedLocalVar(file, {
768
+ name: assignStmt.tokens.name.text,
769
+ type: assignStmt.getType({ flags: 1 /* SymbolTypeFlag.runtime */ }),
770
+ nameRange: assignStmt.tokens.name.range
771
+ });
772
+ },
773
+ ForEachStatement: (forEachStmt) => {
774
+ this.detectShadowedLocalVar(file, {
775
+ name: forEachStmt.tokens.item.text,
776
+ type: forEachStmt.getType({ flags: 1 /* SymbolTypeFlag.runtime */ }),
777
+ nameRange: forEachStmt.tokens.item.range
778
+ });
779
+ }
780
+ }), {
781
+ walkMode: visitors_1.WalkMode.visitAllRecursive
782
+ });
783
+ }
784
+ validateNameCollision(file, node, nameIdentifier) {
785
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
786
+ const name = nameIdentifier === null || nameIdentifier === void 0 ? void 0 : nameIdentifier.text;
787
+ if (!name || !node) {
788
+ return;
789
+ }
790
+ const nameRange = nameIdentifier.range;
791
+ const containingNamespace = (_a = node.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript);
792
+ const containingNamespaceLower = containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase();
793
+ const links = this.event.scope.getAllFileLinks(name, containingNamespace);
794
+ for (let link of links) {
795
+ if (!link || link.item === node) {
796
+ // refers to same node
797
+ continue;
798
+ }
799
+ if ((0, reflection_1.isNamespaceStatement)(link.item) && (0, reflection_1.isNamespaceStatement)(node)) {
800
+ // namespace can be declared multiple times
801
+ continue;
802
+ }
803
+ if ((0, reflection_1.isFunctionStatement)(link.item) || ((_b = link.file) === null || _b === void 0 ? void 0 : _b.destPath) === 'global') {
804
+ const linkItemNamespaceLower = (_e = (_d = (_c = link.item) === null || _c === void 0 ? void 0 : _c.findAncestor(reflection_1.isNamespaceStatement)) === null || _d === void 0 ? void 0 : _d.getName(Parser_1.ParseMode.BrighterScript)) === null || _e === void 0 ? void 0 : _e.toLowerCase();
805
+ if (!(containingNamespaceLower && linkItemNamespaceLower) || linkItemNamespaceLower !== containingNamespaceLower) {
806
+ // the thing found is a function OR from global (which is also a function)
807
+ if ((0, reflection_1.isNamespaceStatement)(node) ||
808
+ (0, reflection_1.isEnumStatement)(node) ||
809
+ (0, reflection_1.isConstStatement)(node) ||
810
+ (0, reflection_1.isInterfaceStatement)(node)) {
811
+ // these are not callable functions in transpiled code - ignore them
812
+ continue;
813
+ }
814
+ }
815
+ }
816
+ const thisNodeKindName = util_1.default.getAstNodeFriendlyName(node);
817
+ const thatNodeKindName = link.file.srcPath === 'global' ? 'Global Function' : (_f = util_1.default.getAstNodeFriendlyName(link.item)) !== null && _f !== void 0 ? _f : '';
818
+ let thatNameRange = (_k = (_j = (_h = (_g = link.item) === null || _g === void 0 ? void 0 : _g.tokens) === null || _h === void 0 ? void 0 : _h.name) === null || _j === void 0 ? void 0 : _j.range) !== null && _k !== void 0 ? _k : (_l = link.item) === null || _l === void 0 ? void 0 : _l.range;
819
+ if ((0, reflection_1.isNamespaceStatement)(link.item)) {
820
+ thatNameRange = (_o = (_m = link.item.getNameParts()) === null || _m === void 0 ? void 0 : _m[0]) === null || _o === void 0 ? void 0 : _o.range;
821
+ }
822
+ const relatedInformation = thatNameRange ? [{
823
+ message: `${thatNodeKindName} declared here`,
824
+ location: util_1.default.createLocation(vscode_uri_1.URI.file((_p = link.file) === null || _p === void 0 ? void 0 : _p.srcPath).toString(), thatNameRange)
825
+ }] : undefined;
826
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.nameCollision(thisNodeKindName, thatNodeKindName, name)), { origin: interfaces_1.DiagnosticOrigin.Scope, range: nameRange, relatedInformation: relatedInformation }));
827
+ }
828
+ }
829
+ detectShadowedLocalVar(file, varDeclaration) {
830
+ var _a;
831
+ const varName = varDeclaration.name;
832
+ const lowerVarName = varName.toLowerCase();
833
+ const classMap = this.event.scope.getClassMap();
834
+ const callableContainerMap = this.event.scope.getCallableContainerMap();
835
+ const varIsFunction = () => {
836
+ return (0, reflection_1.isCallableType)(varDeclaration.type);
837
+ };
838
+ if (
839
+ //has same name as stdlib
840
+ globalCallables_1.globalCallableMap.has(lowerVarName)) {
841
+ //local var function with same name as stdlib function
842
+ if (varIsFunction()) {
843
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('stdlib')), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
844
+ }
845
+ }
846
+ else if (callableContainerMap.has(lowerVarName)) {
847
+ const callable = callableContainerMap.get(lowerVarName);
848
+ //is same name as a callable
849
+ if (varIsFunction()) {
850
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('scope')), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope, relatedInformation: [{
851
+ message: 'Function declared here',
852
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(callable[0].callable.file.srcPath).toString(), callable[0].callable.nameRange)
853
+ }] }));
854
+ }
855
+ else {
856
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarShadowedByScopedFunction()), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope, relatedInformation: [{
857
+ message: 'Function declared here',
858
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(callable[0].callable.file.srcPath).toString(), callable[0].callable.nameRange)
859
+ }] }));
860
+ }
861
+ //has the same name as an in-scope class
862
+ }
863
+ else if (classMap.has(lowerVarName)) {
864
+ const classStmtLink = classMap.get(lowerVarName);
865
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarSameNameAsClass((_a = classStmtLink === null || classStmtLink === void 0 ? void 0 : classStmtLink.item) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript))), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope, relatedInformation: [{
866
+ message: 'Class declared here',
867
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(classStmtLink.file.srcPath).toString(), classStmtLink === null || classStmtLink === void 0 ? void 0 : classStmtLink.item.tokens.name.range)
868
+ }] }));
869
+ }
870
+ }
871
+ detectVariableNamespaceCollisions(file) {
872
+ var _a, _b;
873
+ //find all function parameters
874
+ // eslint-disable-next-line @typescript-eslint/dot-notation
875
+ for (let func of file['_cachedLookups'].functionExpressions) {
876
+ for (let param of func.parameters) {
877
+ let lowerParamName = param.tokens.name.text.toLowerCase();
878
+ let namespace = this.event.scope.getNamespace(lowerParamName, (_a = param.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
879
+ //see if the param matches any starting namespace part
880
+ if (namespace) {
881
+ this.addMultiScopeDiagnostic(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: [{
882
+ message: 'Namespace declared here',
883
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
884
+ }] }));
885
+ }
886
+ }
887
+ }
888
+ // eslint-disable-next-line @typescript-eslint/dot-notation
889
+ for (let assignment of file['_cachedLookups'].assignmentStatements) {
890
+ let lowerAssignmentName = assignment.tokens.name.text.toLowerCase();
891
+ let namespace = this.event.scope.getNamespace(lowerAssignmentName, (_b = assignment.findAncestor(reflection_1.isNamespaceStatement)) === null || _b === void 0 ? void 0 : _b.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
892
+ //see if the param matches any starting namespace part
893
+ if (namespace) {
894
+ this.addMultiScopeDiagnostic(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: [{
895
+ message: 'Namespace declared here',
896
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
897
+ }] }));
898
+ }
899
+ }
900
+ }
901
+ validateXmlInterface(scope) {
902
+ var _a, _b, _c, _d, _e;
903
+ if (!((_b = (_a = scope.xmlFile.parser.ast) === null || _a === void 0 ? void 0 : _a.componentElement) === null || _b === void 0 ? void 0 : _b.interfaceElement)) {
904
+ return;
905
+ }
906
+ const iface = scope.xmlFile.parser.ast.componentElement.interfaceElement;
907
+ const callableContainerMap = scope.getCallableContainerMap();
908
+ //validate functions
909
+ for (const func of iface.functions) {
910
+ const name = func.name;
911
+ if (!name) {
912
+ this.addDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.xmlTagMissingAttribute(func.tokens.startTagName.text, 'name')), { range: func.tokens.startTagName.range, file: scope.xmlFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
913
+ }
914
+ else if (!callableContainerMap.has(name.toLowerCase())) {
915
+ this.addDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.xmlFunctionNotFound(name)), { range: (_c = func.getAttribute('name')) === null || _c === void 0 ? void 0 : _c.tokens.value.range, file: scope.xmlFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
916
+ }
917
+ }
918
+ //validate fields
919
+ for (const field of iface.fields) {
920
+ const { id, type, onChange } = field;
921
+ if (!id) {
922
+ this.addDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.xmlTagMissingAttribute(field.tokens.startTagName.text, 'id')), { range: field.tokens.startTagName.range, file: scope.xmlFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
923
+ }
924
+ if (!type) {
925
+ if (!field.alias) {
926
+ this.addDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.xmlTagMissingAttribute(field.tokens.startTagName.text, 'type')), { range: field.tokens.startTagName.range, file: scope.xmlFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
927
+ }
928
+ }
929
+ else if (!SGTypes_1.SGFieldTypes.includes(type.toLowerCase())) {
930
+ this.addDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.xmlInvalidFieldType(type)), { range: (_d = field.getAttribute('type')) === null || _d === void 0 ? void 0 : _d.tokens.value.range, file: scope.xmlFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
931
+ }
932
+ if (onChange) {
933
+ if (!callableContainerMap.has(onChange.toLowerCase())) {
934
+ this.addDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.xmlFunctionNotFound(onChange)), { range: (_e = field.getAttribute('onchange')) === null || _e === void 0 ? void 0 : _e.tokens.value.range, file: scope.xmlFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
935
+ }
936
+ }
937
+ }
938
+ }
939
+ /**
940
+ * Detect when a child has imported a script that an ancestor also imported
941
+ */
942
+ diagnosticDetectDuplicateAncestorScriptImports(scope) {
943
+ var _a, _b;
944
+ if (scope.xmlFile.parentComponent) {
945
+ //build a lookup of pkg paths -> FileReference so we can more easily look up collisions
946
+ let parentScriptImports = scope.xmlFile.getAncestorScriptTagImports();
947
+ let lookup = {};
948
+ for (let parentScriptImport of parentScriptImports) {
949
+ //keep the first occurance of a pkgPath. Parent imports are first in the array
950
+ if (!lookup[parentScriptImport.destPath]) {
951
+ lookup[parentScriptImport.destPath] = parentScriptImport;
952
+ }
953
+ }
954
+ //add warning for every script tag that this file shares with an ancestor
955
+ for (let scriptImport of scope.xmlFile.scriptTagImports) {
956
+ let ancestorScriptImport = lookup[scriptImport.destPath];
957
+ if (ancestorScriptImport) {
958
+ let ancestorComponent = ancestorScriptImport.sourceFile;
959
+ let ancestorComponentName = (_b = (_a = ancestorComponent.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : ancestorComponent.destPath;
960
+ this.addDiagnostic(Object.assign(Object.assign({ file: scope.xmlFile, range: scriptImport.filePathRange }, DiagnosticMessages_1.DiagnosticMessages.unnecessaryScriptImportInChildFromParent(ancestorComponentName)), { origin: interfaces_1.DiagnosticOrigin.Scope }));
961
+ }
962
+ }
963
+ }
964
+ }
557
965
  /**
558
966
  * Adds a diagnostic to the first scope for this key. Prevents duplicate diagnostics
559
967
  * for diagnostics where scope isn't important. (i.e. CreateObject validations)
560
968
  */
561
969
  addDiagnosticOnce(diagnostic) {
562
- this.onceCache.getOrAdd(`${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
970
+ this.onceCache.getOrAdd(`${diagnostic.code} -${diagnostic.message} -${util_1.default.rangeToString(diagnostic.range)} `, () => {
563
971
  const diagnosticWithOrigin = Object.assign({}, diagnostic);
564
972
  if (!diagnosticWithOrigin.origin) {
565
973
  // diagnostic does not have origin.
@@ -586,7 +994,7 @@ class ScopeValidator {
586
994
  */
587
995
  addMultiScopeDiagnostic(diagnostic) {
588
996
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
589
- diagnostic = this.multiScopeCache.getOrAdd(`${(_a = diagnostic.file) === null || _a === void 0 ? void 0 : _a.srcPath}-${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
997
+ diagnostic = this.multiScopeCache.getOrAdd(`${(_a = diagnostic.file) === null || _a === void 0 ? void 0 : _a.srcPath} -${diagnostic.code} -${diagnostic.message} -${util_1.default.rangeToString(diagnostic.range)} `, () => {
590
998
  if (!diagnostic.relatedInformation) {
591
999
  diagnostic.relatedInformation = [];
592
1000
  }