brighterscript 1.0.0-alpha.24 → 1.0.0-alpha.26

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 (536) hide show
  1. package/CHANGELOG.md +521 -233
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +46 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +25 -0
  8. package/dist/AstValidationSegmenter.js +152 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +40 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +61 -13
  33. package/dist/DiagnosticMessages.js +116 -19
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +150 -69
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +158 -79
  54. package/dist/Program.js +841 -706
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +130 -103
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +86 -137
  60. package/dist/Scope.js +453 -519
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +89 -34
  65. package/dist/SymbolTable.js +239 -114
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -11
  74. package/dist/XmlScope.js +75 -88
  75. package/dist/XmlScope.js.map +1 -1
  76. package/dist/astUtils/CachedLookups.d.ts +48 -0
  77. package/dist/astUtils/CachedLookups.js +323 -0
  78. package/dist/astUtils/CachedLookups.js.map +1 -0
  79. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
  80. package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
  81. package/dist/astUtils/Editor.js.map +1 -0
  82. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +69 -65
  83. package/dist/astUtils/Editor.spec.js.map +1 -0
  84. package/dist/astUtils/creators.d.ts +10 -10
  85. package/dist/astUtils/creators.js +54 -24
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -104
  90. package/dist/astUtils/reflection.js +220 -174
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +256 -157
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +53 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +208 -52
  100. package/dist/astUtils/visitors.spec.js.map +1 -1
  101. package/dist/astUtils/xml.d.ts +9 -9
  102. package/dist/astUtils/xml.js +9 -9
  103. package/dist/astUtils/xml.js.map +1 -1
  104. package/dist/bscPlugin/BscPlugin.d.ts +11 -2
  105. package/dist/bscPlugin/BscPlugin.js +37 -3
  106. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  107. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  108. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  109. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  110. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  111. package/dist/bscPlugin/FileWriter.js +24 -0
  112. package/dist/bscPlugin/FileWriter.js.map +1 -0
  113. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  114. package/dist/bscPlugin/SignatureHelpUtil.js +136 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +16 -13
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  120. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  123. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  125. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  126. package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
  127. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  128. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
  129. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
  130. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  131. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  132. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
  134. package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
  135. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  136. package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
  137. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
  139. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +83 -23
  140. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  141. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
  142. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  143. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  144. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  145. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  146. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  147. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  148. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  149. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  150. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  151. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  152. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  153. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +38 -12
  154. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  155. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  156. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  157. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  158. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  159. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  160. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
  162. package/dist/bscPlugin/validation/BrsFileValidator.js +262 -52
  163. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  164. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
  165. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  166. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  167. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  168. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  169. package/dist/bscPlugin/validation/ScopeValidator.d.ts +58 -27
  170. package/dist/bscPlugin/validation/ScopeValidator.js +514 -286
  171. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  172. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  173. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2527 -0
  174. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  175. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  176. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  177. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  178. package/dist/cli.js +104 -13
  179. package/dist/cli.js.map +1 -1
  180. package/dist/deferred.d.ts +3 -3
  181. package/dist/deferred.js.map +1 -1
  182. package/dist/diagnosticUtils.d.ts +8 -2
  183. package/dist/diagnosticUtils.js +47 -17
  184. package/dist/diagnosticUtils.js.map +1 -1
  185. package/dist/examples/plugins/removePrint.js +8 -10
  186. package/dist/examples/plugins/removePrint.js.map +1 -1
  187. package/dist/files/AssetFile.d.ts +26 -0
  188. package/dist/files/AssetFile.js +26 -0
  189. package/dist/files/AssetFile.js.map +1 -0
  190. package/dist/files/BrsFile.Class.spec.js +523 -493
  191. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  192. package/dist/files/BrsFile.d.ts +111 -117
  193. package/dist/files/BrsFile.js +684 -1142
  194. package/dist/files/BrsFile.js.map +1 -1
  195. package/dist/files/BrsFile.spec.js +1783 -1233
  196. package/dist/files/BrsFile.spec.js.map +1 -1
  197. package/dist/files/BscFile.d.ts +104 -0
  198. package/dist/files/BscFile.js +16 -0
  199. package/dist/files/BscFile.js.map +1 -0
  200. package/dist/files/Factory.d.ts +25 -0
  201. package/dist/files/Factory.js +22 -0
  202. package/dist/files/Factory.js.map +1 -0
  203. package/dist/files/LazyFileData.d.ts +20 -0
  204. package/dist/files/LazyFileData.js +54 -0
  205. package/dist/files/LazyFileData.js.map +1 -0
  206. package/dist/files/LazyFileData.spec.d.ts +1 -0
  207. package/dist/files/LazyFileData.spec.js +27 -0
  208. package/dist/files/LazyFileData.spec.js.map +1 -0
  209. package/dist/files/XmlFile.d.ts +70 -32
  210. package/dist/files/XmlFile.js +106 -118
  211. package/dist/files/XmlFile.js.map +1 -1
  212. package/dist/files/XmlFile.spec.js +325 -262
  213. package/dist/files/XmlFile.spec.js.map +1 -1
  214. package/dist/files/tests/imports.spec.js +48 -40
  215. package/dist/files/tests/imports.spec.js.map +1 -1
  216. package/dist/files/tests/optionalChaning.spec.js +84 -24
  217. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  218. package/dist/globalCallables.js +16 -21
  219. package/dist/globalCallables.js.map +1 -1
  220. package/dist/index.d.ts +12 -1
  221. package/dist/index.js +12 -1
  222. package/dist/index.js.map +1 -1
  223. package/dist/interfaces.d.ts +421 -162
  224. package/dist/interfaces.js +27 -0
  225. package/dist/interfaces.js.map +1 -1
  226. package/dist/lexer/Character.spec.js +5 -5
  227. package/dist/lexer/Character.spec.js.map +1 -1
  228. package/dist/lexer/Lexer.d.ts +12 -5
  229. package/dist/lexer/Lexer.js +28 -13
  230. package/dist/lexer/Lexer.js.map +1 -1
  231. package/dist/lexer/Lexer.spec.js +181 -135
  232. package/dist/lexer/Lexer.spec.js.map +1 -1
  233. package/dist/lexer/Token.d.ts +9 -1
  234. package/dist/lexer/Token.js +9 -1
  235. package/dist/lexer/Token.js.map +1 -1
  236. package/dist/lexer/TokenKind.d.ts +8 -0
  237. package/dist/lexer/TokenKind.js +24 -4
  238. package/dist/lexer/TokenKind.js.map +1 -1
  239. package/dist/parser/AstNode.d.ts +162 -0
  240. package/dist/parser/AstNode.js +225 -0
  241. package/dist/parser/AstNode.js.map +1 -0
  242. package/dist/parser/AstNode.spec.d.ts +1 -0
  243. package/dist/parser/AstNode.spec.js +165 -0
  244. package/dist/parser/AstNode.spec.js.map +1 -0
  245. package/dist/parser/BrsTranspileState.d.ts +4 -7
  246. package/dist/parser/BrsTranspileState.js +4 -12
  247. package/dist/parser/BrsTranspileState.js.map +1 -1
  248. package/dist/parser/Expression.d.ts +376 -283
  249. package/dist/parser/Expression.js +742 -585
  250. package/dist/parser/Expression.js.map +1 -1
  251. package/dist/parser/Parser.Class.spec.js +151 -145
  252. package/dist/parser/Parser.Class.spec.js.map +1 -1
  253. package/dist/parser/Parser.d.ts +48 -201
  254. package/dist/parser/Parser.js +705 -1026
  255. package/dist/parser/Parser.js.map +1 -1
  256. package/dist/parser/Parser.spec.d.ts +3 -1
  257. package/dist/parser/Parser.spec.js +861 -848
  258. package/dist/parser/Parser.spec.js.map +1 -1
  259. package/dist/parser/SGParser.d.ts +9 -8
  260. package/dist/parser/SGParser.js +10 -8
  261. package/dist/parser/SGParser.js.map +1 -1
  262. package/dist/parser/SGParser.spec.js +27 -38
  263. package/dist/parser/SGParser.spec.js.map +1 -1
  264. package/dist/parser/SGTypes.d.ts +98 -35
  265. package/dist/parser/SGTypes.js +169 -99
  266. package/dist/parser/SGTypes.js.map +1 -1
  267. package/dist/parser/Statement.d.ts +468 -272
  268. package/dist/parser/Statement.js +904 -631
  269. package/dist/parser/Statement.js.map +1 -1
  270. package/dist/parser/Statement.spec.js +47 -23
  271. package/dist/parser/Statement.spec.js.map +1 -1
  272. package/dist/parser/TranspileState.d.ts +1 -1
  273. package/dist/parser/TranspileState.js +7 -12
  274. package/dist/parser/TranspileState.js.map +1 -1
  275. package/dist/parser/tests/Parser.spec.js +3 -2
  276. package/dist/parser/tests/Parser.spec.js.map +1 -1
  277. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  278. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  279. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  280. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  281. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  282. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  283. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  284. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  285. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  286. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  287. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  288. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  289. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +62 -21
  290. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  291. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  292. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  293. package/dist/parser/tests/expression/Call.spec.js +129 -21
  294. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  295. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  296. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  297. package/dist/parser/tests/expression/Function.spec.js +36 -36
  298. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  299. package/dist/parser/tests/expression/Indexing.spec.js +92 -22
  300. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  301. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  302. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  303. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
  304. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  305. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  306. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  307. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  308. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  309. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  310. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  311. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  312. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  313. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  314. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  315. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
  316. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  317. package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
  318. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  319. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  321. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  323. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  324. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  325. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  326. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  327. package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
  328. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  329. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  330. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  331. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  332. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  333. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  335. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/Enum.spec.js +98 -302
  337. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/For.spec.js +9 -10
  339. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  341. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Function.spec.js +44 -35
  343. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  345. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  347. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  349. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  351. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  353. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/PrintStatement.spec.js +36 -34
  355. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  357. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Set.spec.js +48 -35
  359. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  361. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  363. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  364. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  365. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  366. package/dist/preprocessor/Manifest.d.ts +1 -1
  367. package/dist/preprocessor/Manifest.js +2 -2
  368. package/dist/preprocessor/Manifest.js.map +1 -1
  369. package/dist/preprocessor/Manifest.spec.js +8 -8
  370. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  371. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  372. package/dist/preprocessor/Preprocessor.js +5 -5
  373. package/dist/preprocessor/Preprocessor.js.map +1 -1
  374. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  375. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  376. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  377. package/dist/preprocessor/PreprocessorParser.js +7 -1
  378. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  379. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  380. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  381. package/dist/roku-types/data.json +5892 -10081
  382. package/dist/roku-types/index.d.ts +622 -1719
  383. package/dist/types/ArrayType.d.ts +10 -9
  384. package/dist/types/ArrayType.js +65 -60
  385. package/dist/types/ArrayType.js.map +1 -1
  386. package/dist/types/ArrayType.spec.js +36 -68
  387. package/dist/types/ArrayType.spec.js.map +1 -1
  388. package/dist/types/AssociativeArrayType.d.ts +11 -0
  389. package/dist/types/AssociativeArrayType.js +52 -0
  390. package/dist/types/AssociativeArrayType.js.map +1 -0
  391. package/dist/types/BaseFunctionType.d.ts +9 -0
  392. package/dist/types/BaseFunctionType.js +25 -0
  393. package/dist/types/BaseFunctionType.js.map +1 -0
  394. package/dist/types/BooleanType.d.ts +8 -5
  395. package/dist/types/BooleanType.js +14 -7
  396. package/dist/types/BooleanType.js.map +1 -1
  397. package/dist/types/BooleanType.spec.js +10 -6
  398. package/dist/types/BooleanType.spec.js.map +1 -1
  399. package/dist/types/BscType.d.ts +32 -21
  400. package/dist/types/BscType.js +118 -21
  401. package/dist/types/BscType.js.map +1 -1
  402. package/dist/types/BscTypeKind.d.ts +25 -0
  403. package/dist/types/BscTypeKind.js +30 -0
  404. package/dist/types/BscTypeKind.js.map +1 -0
  405. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  406. package/dist/types/BuiltInInterfaceAdder.js +171 -0
  407. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  409. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  410. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  411. package/dist/types/ClassType.d.ts +17 -0
  412. package/dist/types/ClassType.js +58 -0
  413. package/dist/types/ClassType.js.map +1 -0
  414. package/dist/types/ClassType.spec.d.ts +1 -0
  415. package/dist/types/ClassType.spec.js +77 -0
  416. package/dist/types/ClassType.spec.js.map +1 -0
  417. package/dist/types/ComponentType.d.ts +26 -0
  418. package/dist/types/ComponentType.js +83 -0
  419. package/dist/types/ComponentType.js.map +1 -0
  420. package/dist/types/DoubleType.d.ts +8 -5
  421. package/dist/types/DoubleType.js +18 -16
  422. package/dist/types/DoubleType.js.map +1 -1
  423. package/dist/types/DoubleType.spec.js +12 -6
  424. package/dist/types/DoubleType.spec.js.map +1 -1
  425. package/dist/types/DynamicType.d.ts +9 -5
  426. package/dist/types/DynamicType.js +15 -4
  427. package/dist/types/DynamicType.js.map +1 -1
  428. package/dist/types/DynamicType.spec.js +16 -5
  429. package/dist/types/DynamicType.spec.js.map +1 -1
  430. package/dist/types/EnumType.d.ts +30 -12
  431. package/dist/types/EnumType.js +43 -17
  432. package/dist/types/EnumType.js.map +1 -1
  433. package/dist/types/EnumType.spec.d.ts +1 -0
  434. package/dist/types/EnumType.spec.js +33 -0
  435. package/dist/types/EnumType.spec.js.map +1 -0
  436. package/dist/types/FloatType.d.ts +8 -5
  437. package/dist/types/FloatType.js +18 -16
  438. package/dist/types/FloatType.js.map +1 -1
  439. package/dist/types/FloatType.spec.js +4 -6
  440. package/dist/types/FloatType.spec.js.map +1 -1
  441. package/dist/types/FunctionType.d.ts +13 -8
  442. package/dist/types/FunctionType.js +30 -14
  443. package/dist/types/FunctionType.js.map +1 -1
  444. package/dist/types/InheritableType.d.ts +28 -0
  445. package/dist/types/InheritableType.js +152 -0
  446. package/dist/types/InheritableType.js.map +1 -0
  447. package/dist/types/IntegerType.d.ts +8 -5
  448. package/dist/types/IntegerType.js +18 -16
  449. package/dist/types/IntegerType.js.map +1 -1
  450. package/dist/types/IntegerType.spec.js +8 -6
  451. package/dist/types/IntegerType.spec.js.map +1 -1
  452. package/dist/types/InterfaceType.d.ts +12 -13
  453. package/dist/types/InterfaceType.js +20 -48
  454. package/dist/types/InterfaceType.js.map +1 -1
  455. package/dist/types/InterfaceType.spec.js +90 -56
  456. package/dist/types/InterfaceType.spec.js.map +1 -1
  457. package/dist/types/InvalidType.d.ts +7 -5
  458. package/dist/types/InvalidType.js +13 -7
  459. package/dist/types/InvalidType.js.map +1 -1
  460. package/dist/types/InvalidType.spec.js +8 -6
  461. package/dist/types/InvalidType.spec.js.map +1 -1
  462. package/dist/types/LongIntegerType.d.ts +8 -5
  463. package/dist/types/LongIntegerType.js +17 -15
  464. package/dist/types/LongIntegerType.js.map +1 -1
  465. package/dist/types/LongIntegerType.spec.js +10 -6
  466. package/dist/types/LongIntegerType.spec.js.map +1 -1
  467. package/dist/types/NamespaceType.d.ts +12 -0
  468. package/dist/types/NamespaceType.js +28 -0
  469. package/dist/types/NamespaceType.js.map +1 -0
  470. package/dist/types/ObjectType.d.ts +9 -8
  471. package/dist/types/ObjectType.js +21 -11
  472. package/dist/types/ObjectType.js.map +1 -1
  473. package/dist/types/ObjectType.spec.js +3 -3
  474. package/dist/types/ObjectType.spec.js.map +1 -1
  475. package/dist/types/ReferenceType.d.ts +63 -0
  476. package/dist/types/ReferenceType.js +423 -0
  477. package/dist/types/ReferenceType.js.map +1 -0
  478. package/dist/types/ReferenceType.spec.d.ts +1 -0
  479. package/dist/types/ReferenceType.spec.js +137 -0
  480. package/dist/types/ReferenceType.spec.js.map +1 -0
  481. package/dist/types/StringType.d.ts +11 -5
  482. package/dist/types/StringType.js +18 -7
  483. package/dist/types/StringType.js.map +1 -1
  484. package/dist/types/StringType.spec.js +3 -5
  485. package/dist/types/StringType.spec.js.map +1 -1
  486. package/dist/types/TypedFunctionType.d.ts +22 -17
  487. package/dist/types/TypedFunctionType.js +78 -60
  488. package/dist/types/TypedFunctionType.js.map +1 -1
  489. package/dist/types/TypedFunctionType.spec.js +105 -20
  490. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  491. package/dist/types/UninitializedType.d.ts +8 -6
  492. package/dist/types/UninitializedType.js +13 -7
  493. package/dist/types/UninitializedType.js.map +1 -1
  494. package/dist/types/UnionType.d.ts +20 -0
  495. package/dist/types/UnionType.js +123 -0
  496. package/dist/types/UnionType.js.map +1 -0
  497. package/dist/types/UnionType.spec.d.ts +1 -0
  498. package/dist/types/UnionType.spec.js +130 -0
  499. package/dist/types/UnionType.spec.js.map +1 -0
  500. package/dist/types/VoidType.d.ts +8 -5
  501. package/dist/types/VoidType.js +14 -7
  502. package/dist/types/VoidType.js.map +1 -1
  503. package/dist/types/VoidType.spec.js +3 -3
  504. package/dist/types/VoidType.spec.js.map +1 -1
  505. package/dist/types/helper.spec.d.ts +1 -0
  506. package/dist/types/helper.spec.js +145 -0
  507. package/dist/types/helper.spec.js.map +1 -0
  508. package/dist/types/helpers.d.ts +19 -37
  509. package/dist/types/helpers.js +159 -99
  510. package/dist/types/helpers.js.map +1 -1
  511. package/dist/types/index.d.ts +22 -0
  512. package/dist/types/index.js +39 -0
  513. package/dist/types/index.js.map +1 -0
  514. package/dist/util.d.ts +143 -139
  515. package/dist/util.js +864 -385
  516. package/dist/util.js.map +1 -1
  517. package/dist/validators/ClassValidator.d.ts +8 -25
  518. package/dist/validators/ClassValidator.js +99 -179
  519. package/dist/validators/ClassValidator.js.map +1 -1
  520. package/package.json +165 -152
  521. package/dist/astUtils/AstEditor.js.map +0 -1
  522. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/definition/DefinitionProvider.spec.d.ts} +0 -0
@@ -5,15 +5,21 @@ const vscode_uri_1 = require("vscode-uri");
5
5
  const reflection_1 = require("../../astUtils/reflection");
6
6
  const Cache_1 = require("../../Cache");
7
7
  const DiagnosticMessages_1 = require("../../DiagnosticMessages");
8
+ const interfaces_1 = require("../../interfaces");
9
+ const SymbolTable_1 = require("../../SymbolTable");
8
10
  const util_1 = require("../../util");
9
11
  const roku_types_1 = require("../../roku-types");
10
- const UninitializedType_1 = require("../../types/UninitializedType");
11
- const BscType_1 = require("../../types/BscType");
12
+ const Expression_1 = require("../../parser/Expression");
13
+ const visitors_1 = require("../../astUtils/visitors");
14
+ const AstValidationSegmenter_1 = require("../../AstValidationSegmenter");
15
+ const TokenKind_1 = require("../../lexer/TokenKind");
16
+ const Parser_1 = require("../../parser/Parser");
12
17
  /**
13
18
  * The lower-case names of all platform-included scenegraph nodes
14
19
  */
15
- const platformNodeNames = new Set(Object.values(roku_types_1.nodes).map(x => x.name.toLowerCase()));
16
- const platformComponentNames = new Set(Object.values(roku_types_1.components).map(x => x.name.toLowerCase()));
20
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
21
+ const platformNodeNames = roku_types_1.nodes ? new Set(Object.values(roku_types_1.nodes).map(x => x === null || x === void 0 ? void 0 : x.name.toLowerCase())) : new Set();
22
+ const platformComponentNames = roku_types_1.components ? new Set(Object.values(roku_types_1.components).map(x => x === null || x === void 0 ? void 0 : x.name.toLowerCase())) : new Set();
17
23
  /**
18
24
  * A validator that handles all scope validations for a program validation cycle.
19
25
  * You should create ONE of these to handle all scope events between beforeProgramValidate and afterProgramValidate,
@@ -21,183 +27,120 @@ const platformComponentNames = new Set(Object.values(roku_types_1.components).ma
21
27
  */
22
28
  class ScopeValidator {
23
29
  constructor() {
24
- this.events = [];
25
30
  this.onceCache = new Cache_1.Cache();
26
31
  this.multiScopeCache = new Cache_1.Cache();
27
32
  }
28
33
  processEvent(event) {
29
- this.events.push(event);
30
- event.scope.linkSymbolTable();
31
- this.detectDuplicateEnums(event);
32
- this.validateCreateObjectCalls(event);
33
- this.iterateExpressions(event);
34
- this.detectInvalidFunctionCalls(event);
35
- event.scope.unlinkSymbolTable();
34
+ this.event = event;
35
+ if (this.event.program.globalScope === this.event.scope) {
36
+ return;
37
+ }
38
+ this.walkFiles();
39
+ this.detectDuplicateEnums();
36
40
  }
37
41
  reset() {
42
+ this.event = undefined;
38
43
  this.onceCache.clear();
39
44
  this.multiScopeCache.clear();
40
- this.events = [];
41
- }
42
- /**
43
- * Adds a diagnostic to the first scope for this key. Prevents duplicate diagnostics
44
- * for diagnostics where scope isn't important. (i.e. CreateObject validations)
45
- */
46
- addDiagnosticOnce(event, diagnostic) {
47
- this.onceCache.getOrAdd(`${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
48
- event.scope.addDiagnostics([diagnostic]);
49
- return true;
50
- });
51
- }
52
- addDiagnostic(event, diagnostic) {
53
- event.scope.addDiagnostics([diagnostic]);
54
- }
55
- /**
56
- * Add a diagnostic (to the first scope) that will have `relatedInformation` for each affected scope
57
- */
58
- addMultiScopeDiagnostic(event, diagnostic, message = 'Not defined in scope') {
59
- var _a, _b;
60
- 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)}`, () => {
61
- if (!diagnostic.relatedInformation) {
62
- diagnostic.relatedInformation = [];
63
- }
64
- this.addDiagnostic(event, diagnostic);
65
- return diagnostic;
66
- });
67
- const info = {
68
- message: `${message} '${event.scope.name}'`
69
- };
70
- if ((0, reflection_1.isXmlScope)(event.scope) && ((_b = event.scope.xmlFile) === null || _b === void 0 ? void 0 : _b.srcPath)) {
71
- info.location = util_1.default.createLocation(vscode_uri_1.URI.file(event.scope.xmlFile.srcPath).toString(), util_1.default.createRange(0, 0, 0, 10));
72
- }
73
- else {
74
- info.location = util_1.default.createLocation(vscode_uri_1.URI.file(diagnostic.file.srcPath).toString(), diagnostic.range);
75
- }
76
- diagnostic.relatedInformation.push(info);
77
45
  }
78
- /**
79
- * Find the closest symbol table for the given position
80
- */
81
- getSymbolTable(scope, file, position) {
82
- var _a, _b;
83
- let symbolTable;
84
- symbolTable = (_a = file.getFunctionExpressionAtPosition(position)) === null || _a === void 0 ? void 0 : _a.symbolTable;
85
- if (!symbolTable) {
86
- symbolTable = (_b = file.getNamespaceStatementForPosition(position)) === null || _b === void 0 ? void 0 : _b.symbolTable;
87
- }
88
- if (!symbolTable) {
89
- symbolTable = scope.symbolTable;
90
- }
91
- return symbolTable;
92
- }
93
- iterateExpressions(event) {
94
- const { scope } = event;
95
- event.scope.enumerateOwnFiles((file) => {
96
- var _a, _b, _c;
46
+ walkFiles() {
47
+ this.event.scope.enumerateOwnFiles((file) => {
97
48
  if ((0, reflection_1.isBrsFile)(file)) {
98
- const expressions = [
99
- ...file.parser.references.expressions,
100
- //all class "extends <whatever>" expressions
101
- ...file.parser.references.classStatements.map(x => { var _a; return (_a = x.parentClassName) === null || _a === void 0 ? void 0 : _a.expression; }),
102
- //all interface "extends <whatever>" expressions
103
- ...file.parser.references.interfaceStatements.map(x => { var _a; return (_a = x.parentInterfaceName) === null || _a === void 0 ? void 0 : _a.expression; })
104
- ];
105
- outer: for (let referenceExpression of expressions) {
106
- if (!referenceExpression) {
107
- continue;
108
- }
109
- let expression;
110
- //lift the callee from call expressions to handle namespaced function calls
111
- if ((0, reflection_1.isCallExpression)(referenceExpression)) {
112
- expression = referenceExpression.callee;
113
- }
114
- else if ((0, reflection_1.isNewExpression)(referenceExpression)) {
115
- expression = referenceExpression.call.callee;
116
- }
117
- else {
118
- expression = referenceExpression;
119
- }
120
- if ((0, reflection_1.isCallExpression)(expression.parent) && !(0, reflection_1.isNewExpression)(referenceExpression)) {
121
- // function calls are validated in detectInvalidFunctionCalls
122
- continue;
123
- }
124
- const tokens = util_1.default.getAllDottedGetParts(expression);
125
- if ((tokens === null || tokens === void 0 ? void 0 : tokens.length) > 0) {
126
- const symbolTable = this.getSymbolTable(scope, file, tokens[0].range.start); //flag all unknown left-most variables
127
- if (!symbolTable.hasSymbol((_a = tokens[0]) === null || _a === void 0 ? void 0 : _a.text)) {
128
- this.addMultiScopeDiagnostic(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(tokens[0].text)), { range: tokens[0].range }));
129
- //skip to the next expression
130
- continue;
131
- }
132
- //at this point, we know the first item is a known symbol. find unknown namespace parts after the first part
133
- if (tokens.length > 1) {
134
- const firstNamespacePart = tokens.shift().text;
135
- const firstNamespacePartLower = firstNamespacePart === null || firstNamespacePart === void 0 ? void 0 : firstNamespacePart.toLowerCase();
136
- const namespaceContainer = scope.namespaceLookup.get(firstNamespacePartLower);
137
- const enumStatement = scope.getEnum(firstNamespacePartLower);
138
- //if this isn't a namespace, skip it
139
- if (!namespaceContainer && !enumStatement) {
140
- continue;
141
- }
142
- //catch unknown namespace items
143
- const processedNames = [firstNamespacePart];
144
- for (const token of tokens !== null && tokens !== void 0 ? tokens : []) {
145
- processedNames.push(token.text);
146
- const entityName = processedNames.join('.');
147
- const entityNameLower = entityName.toLowerCase();
148
- //if this is an enum member, stop validating here to prevent errors further down the chain
149
- if (scope.getEnumMemberMap().has(entityNameLower)) {
150
- break;
151
- }
152
- if (!scope.getEnumMap().has(entityNameLower) &&
153
- !scope.getClassMap().has(entityNameLower) &&
154
- !scope.getConstMap().has(entityNameLower) &&
155
- !scope.getCallableByName(entityNameLower) &&
156
- !scope.namespaceLookup.has(entityNameLower)) {
157
- //if this looks like an enum, provide a nicer error message
158
- const theEnum = (_b = this.getEnum(scope, entityNameLower)) === null || _b === void 0 ? void 0 : _b.item;
159
- if (theEnum) {
160
- this.addMultiScopeDiagnostic(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownEnumValue((_c = token.text) === null || _c === void 0 ? void 0 : _c.split('.').pop(), theEnum.fullName)), { range: tokens[tokens.length - 1].range, relatedInformation: [{
161
- message: 'Enum declared here',
162
- location: util_1.default.createLocation(vscode_uri_1.URI.file(file.srcPath).toString(), theEnum.tokens.name.range)
163
- }] }));
164
- }
165
- else {
166
- this.addMultiScopeDiagnostic(event, Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(token.text, entityName)), { range: token.range, file: file }));
167
- }
168
- //no need to add another diagnostic for future unknown items
169
- continue outer;
170
- }
49
+ const hasChangeInfo = this.event.changedFiles && this.event.changedSymbols;
50
+ let thisFileRequiresChangedSymbol = false;
51
+ for (let requiredSymbol of file.requiredSymbols) {
52
+ // eslint-disable-next-line no-bitwise
53
+ for (const flag of [SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.typetime]) {
54
+ // eslint-disable-next-line no-bitwise
55
+ if (flag & requiredSymbol.flags) {
56
+ const changeSymbolSetForFlag = this.event.changedSymbols.get(flag);
57
+ if (util_1.default.setContainsUnresolvedSymbol(changeSymbolSetForFlag, requiredSymbol)) {
58
+ thisFileRequiresChangedSymbol = true;
171
59
  }
172
60
  }
173
61
  }
174
62
  }
63
+ const thisFileHasChanges = this.event.changedFiles.includes(file);
64
+ if (hasChangeInfo && !thisFileRequiresChangedSymbol && !thisFileHasChanges) {
65
+ // this file does not require a symbol that has changed, and this file has not changed
66
+ return;
67
+ }
68
+ if (thisFileHasChanges) {
69
+ this.event.scope.clearAstSegmentDiagnosticsByFile(file);
70
+ }
71
+ const validationVisitor = (0, visitors_1.createVisitor)({
72
+ VariableExpression: (varExpr) => {
73
+ this.validateVariableAndDottedGetExpressions(file, varExpr);
74
+ },
75
+ DottedGetExpression: (dottedGet) => {
76
+ this.validateVariableAndDottedGetExpressions(file, dottedGet);
77
+ },
78
+ CallExpression: (functionCall) => {
79
+ this.validateFunctionCall(file, functionCall);
80
+ this.validateCreateObjectCall(file, functionCall);
81
+ },
82
+ ReturnStatement: (returnStatement) => {
83
+ this.validateReturnStatement(file, returnStatement);
84
+ },
85
+ DottedSetStatement: (dottedSetStmt) => {
86
+ this.validateDottedSetStatement(file, dottedSetStmt);
87
+ },
88
+ BinaryExpression: (binaryExpr) => {
89
+ this.validateBinaryExpression(file, binaryExpr);
90
+ },
91
+ UnaryExpression: (unaryExpr) => {
92
+ this.validateUnaryExpression(file, unaryExpr);
93
+ },
94
+ AssignmentStatement: (assignStmt) => {
95
+ this.validateAssignmentStatement(file, assignStmt);
96
+ }
97
+ });
98
+ const segmentsToWalkForValidation = (thisFileHasChanges || !hasChangeInfo)
99
+ ? file.validationSegmenter.segmentsForValidation // validate everything in the file
100
+ : file.getValidationSegments(this.event.changedSymbols); // validate only what's needed in the file
101
+ for (const segment of segmentsToWalkForValidation) {
102
+ this.currentSegmentBeingValidated = segment;
103
+ this.event.scope.clearAstSegmentDiagnostics(segment);
104
+ segment.walk(validationVisitor, {
105
+ walkMode: AstValidationSegmenter_1.InsideSegmentWalkMode
106
+ });
107
+ file.markSegmentAsValidated(segment);
108
+ }
175
109
  }
176
110
  });
177
111
  }
112
+ isTypeKnown(exprType) {
113
+ let isKnownType = exprType === null || exprType === void 0 ? void 0 : exprType.isResolvable();
114
+ return isKnownType;
115
+ }
178
116
  /**
179
- * Given a string optionally separated by dots, find an enum related to it.
180
- * For example, all of these would return the enum: `SomeNamespace.SomeEnum.SomeMember`, SomeEnum.SomeMember, `SomeEnum`
117
+ * If this is the lhs of an assignment, we don't need to flag it as unresolved
181
118
  */
182
- getEnum(scope, name) {
183
- //look for the enum directly
184
- let result = scope.getEnumMap().get(name);
185
- //assume we've been given the enum.member syntax, so pop the member and try again
186
- if (!result) {
187
- const parts = name.split('.');
188
- parts.pop();
189
- result = scope.getEnumMap().get(parts.join('.'));
190
- }
191
- return result;
119
+ ignoreUnresolvedAssignmentLHS(expression, exprType, definingNode) {
120
+ var _a, _b;
121
+ if (!(0, reflection_1.isVariableExpression)(expression)) {
122
+ return false;
123
+ }
124
+ let assignmentAncestor;
125
+ if ((0, reflection_1.isAssignmentStatement)(definingNode) && definingNode.tokens.equals.kind === TokenKind_1.TokenKind.Equal) {
126
+ // this symbol was defined in a "normal" assignment (eg. not a compound assignment)
127
+ assignmentAncestor = definingNode;
128
+ 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
+ }
130
+ else {
131
+ assignmentAncestor = expression === null || expression === void 0 ? void 0 : expression.findAncestor(reflection_1.isAssignmentStatement);
132
+ }
133
+ return (assignmentAncestor === null || assignmentAncestor === void 0 ? void 0 : assignmentAncestor.tokens.name) === (expression === null || expression === void 0 ? void 0 : expression.tokens.name) && (0, reflection_1.isUnionType)(exprType);
192
134
  }
193
135
  /**
194
136
  * Flag duplicate enums
195
137
  */
196
- detectDuplicateEnums(event) {
138
+ detectDuplicateEnums() {
197
139
  const diagnostics = [];
198
140
  const enumLocationsByName = new Cache_1.Cache();
199
- event.scope.enumerateBrsFiles((file) => {
200
- for (const enumStatement of file.parser.references.enumStatements) {
141
+ this.event.scope.enumerateBrsFiles((file) => {
142
+ // eslint-disable-next-line @typescript-eslint/dot-notation
143
+ for (const enumStatement of file['_cachedLookups'].enumStatements) {
201
144
  const fullName = enumStatement.fullName;
202
145
  const nameLower = fullName === null || fullName === void 0 ? void 0 : fullName.toLowerCase();
203
146
  if ((nameLower === null || nameLower === void 0 ? void 0 : nameLower.length) > 0) {
@@ -226,13 +169,13 @@ class ScopeValidator {
226
169
  const primaryEnum = enumLocations.shift();
227
170
  const fullName = primaryEnum.statement.fullName;
228
171
  for (const duplicateEnumInfo of enumLocations) {
229
- diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateEnumDeclaration(event.scope.name, fullName)), { file: duplicateEnumInfo.file, range: duplicateEnumInfo.statement.tokens.name.range, relatedInformation: [{
172
+ diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateEnumDeclaration(this.event.scope.name, fullName)), { file: duplicateEnumInfo.file, range: duplicateEnumInfo.statement.tokens.name.range, relatedInformation: [{
230
173
  message: 'Enum declared here',
231
174
  location: util_1.default.createLocation(vscode_uri_1.URI.file(primaryEnum.file.srcPath).toString(), primaryEnum.statement.tokens.name.range)
232
- }] }));
175
+ }], origin: interfaces_1.DiagnosticOrigin.Scope }));
233
176
  }
234
177
  }
235
- event.scope.addDiagnostics(diagnostics);
178
+ this.event.scope.addDiagnostics(diagnostics);
236
179
  }
237
180
  /**
238
181
  * Validate every function call to `CreateObject`.
@@ -240,150 +183,435 @@ class ScopeValidator {
240
183
  * what these calls are supposed to look like, and this is a very common thing for brs devs to do, so just
241
184
  * do this manually for now.
242
185
  */
243
- validateCreateObjectCalls(event) {
244
- const diagnostics = [];
245
- event.scope.enumerateBrsFiles((file) => {
246
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
247
- for (const call of file.functionCalls) {
248
- //skip non CreateObject function calls
249
- if (((_a = call.name) === null || _a === void 0 ? void 0 : _a.text.toLowerCase()) !== 'createobject' || !(0, reflection_1.isLiteralExpression)((_b = call === null || call === void 0 ? void 0 : call.args[0]) === null || _b === void 0 ? void 0 : _b.expression)) {
250
- continue;
251
- }
252
- const firstParamToken = (_d = (_c = call === null || call === void 0 ? void 0 : call.args[0]) === null || _c === void 0 ? void 0 : _c.expression) === null || _d === void 0 ? void 0 : _d.token;
253
- const firstParamStringValue = (_e = firstParamToken === null || firstParamToken === void 0 ? void 0 : firstParamToken.text) === null || _e === void 0 ? void 0 : _e.replace(/"/g, '');
254
- //if this is a `createObject('roSGNode'` call, only support known sg node types
255
- if ((firstParamStringValue === null || firstParamStringValue === void 0 ? void 0 : firstParamStringValue.toLowerCase()) === 'rosgnode' && (0, reflection_1.isLiteralExpression)((_f = call === null || call === void 0 ? void 0 : call.args[1]) === null || _f === void 0 ? void 0 : _f.expression)) {
256
- const componentName = (_h = (_g = call === null || call === void 0 ? void 0 : call.args[1]) === null || _g === void 0 ? void 0 : _g.expression) === null || _h === void 0 ? void 0 : _h.token;
257
- //don't validate any components with a colon in their name (probably component libraries, but regular components can have them too).
258
- if ((_j = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _j === void 0 ? void 0 : _j.includes(':')) {
259
- continue;
260
- }
261
- //add diagnostic for unknown components
262
- const unquotedComponentName = (_k = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _k === void 0 ? void 0 : _k.replace(/"/g, '');
263
- if (unquotedComponentName && !platformNodeNames.has(unquotedComponentName.toLowerCase()) && !event.program.getComponent(unquotedComponentName)) {
264
- this.addDiagnosticOnce(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownRoSGNode(unquotedComponentName)), { range: componentName.range }));
265
- }
266
- else if ((call === null || call === void 0 ? void 0 : call.args.length) !== 2) {
267
- // roSgNode should only ever have 2 args in `createObject`
268
- this.addDiagnosticOnce(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.mismatchCreateObjectArgumentCount(firstParamStringValue, [2], call === null || call === void 0 ? void 0 : call.args.length)), { range: call.range }));
269
- }
186
+ validateCreateObjectCall(file, call) {
187
+ var _a, _b, _c, _d, _e, _f, _g;
188
+ //skip non CreateObject function calls
189
+ const callName = (_a = util_1.default.getAllDottedGetPartsAsString(call.callee)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
190
+ if (callName !== 'createobject' || !(0, reflection_1.isLiteralExpression)(call === null || call === void 0 ? void 0 : call.args[0])) {
191
+ return;
192
+ }
193
+ const firstParamToken = (_c = (_b = call === null || call === void 0 ? void 0 : call.args[0]) === null || _b === void 0 ? void 0 : _b.tokens) === null || _c === void 0 ? void 0 : _c.value;
194
+ const firstParamStringValue = (_d = firstParamToken === null || firstParamToken === void 0 ? void 0 : firstParamToken.text) === null || _d === void 0 ? void 0 : _d.replace(/"/g, '');
195
+ if (!firstParamStringValue) {
196
+ return;
197
+ }
198
+ const firstParamStringValueLower = firstParamStringValue.toLowerCase();
199
+ //if this is a `createObject('roSGNode'` call, only support known sg node types
200
+ if (firstParamStringValueLower === 'rosgnode' && (0, reflection_1.isLiteralExpression)(call === null || call === void 0 ? void 0 : call.args[1])) {
201
+ const componentName = (_e = call === null || call === void 0 ? void 0 : call.args[1]) === null || _e === void 0 ? void 0 : _e.tokens.value;
202
+ //don't validate any components with a colon in their name (probably component libraries, but regular components can have them too).
203
+ if (!componentName || ((_f = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _f === void 0 ? void 0 : _f.includes(':'))) {
204
+ return;
205
+ }
206
+ //add diagnostic for unknown components
207
+ const unquotedComponentName = (_g = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _g === void 0 ? void 0 : _g.replace(/"/g, '');
208
+ if (unquotedComponentName && !platformNodeNames.has(unquotedComponentName.toLowerCase()) && !this.event.program.getComponent(unquotedComponentName)) {
209
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownRoSGNode(unquotedComponentName)), { range: componentName.range }));
210
+ }
211
+ else if ((call === null || call === void 0 ? void 0 : call.args.length) !== 2) {
212
+ // roSgNode should only ever have 2 args in `createObject`
213
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.mismatchCreateObjectArgumentCount(firstParamStringValue, [2], call === null || call === void 0 ? void 0 : call.args.length)), { range: call.range }));
214
+ }
215
+ }
216
+ else if (!platformComponentNames.has(firstParamStringValueLower)) {
217
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownBrightScriptComponent(firstParamStringValue)), { range: firstParamToken.range }));
218
+ }
219
+ else {
220
+ // This is valid brightscript component
221
+ // Test for invalid arg counts
222
+ const brightScriptComponent = roku_types_1.components[firstParamStringValueLower];
223
+ // Valid arg counts for createObject are 1+ number of args for constructor
224
+ let validArgCounts = brightScriptComponent === null || brightScriptComponent === void 0 ? void 0 : brightScriptComponent.constructors.map(cnstr => cnstr.params.length + 1);
225
+ if (validArgCounts.length === 0) {
226
+ // no constructors for this component, so createObject only takes 1 arg
227
+ validArgCounts = [1];
228
+ }
229
+ if (!validArgCounts.includes(call === null || call === void 0 ? void 0 : call.args.length)) {
230
+ // Incorrect number of arguments included in `createObject()`
231
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.mismatchCreateObjectArgumentCount(firstParamStringValue, validArgCounts, call === null || call === void 0 ? void 0 : call.args.length)), { range: call.range }));
232
+ }
233
+ // Test for deprecation
234
+ if (brightScriptComponent === null || brightScriptComponent === void 0 ? void 0 : brightScriptComponent.isDeprecated) {
235
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.deprecatedBrightScriptComponent(firstParamStringValue, brightScriptComponent.deprecatedDescription)), { range: call.range }));
236
+ }
237
+ }
238
+ }
239
+ /**
240
+ * Detect calls to functions with the incorrect number of parameters, or wrong types of arguments
241
+ */
242
+ validateFunctionCall(file, expression) {
243
+ var _a, _b;
244
+ const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime, data: {} };
245
+ let funcType = (_a = expression === null || expression === void 0 ? void 0 : expression.callee) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
246
+ if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isClassType)(funcType)) {
247
+ // We're calling a class - get the constructor
248
+ funcType = funcType.getMemberType('new', getTypeOptions);
249
+ }
250
+ if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isTypedFunctionType)(funcType)) {
251
+ //funcType.setName(expression.callee. .name);
252
+ //get min/max parameter count for callable
253
+ let minParams = 0;
254
+ let maxParams = 0;
255
+ for (let param of funcType.params) {
256
+ maxParams++;
257
+ //optional parameters must come last, so we can assume that minParams won't increase once we hit
258
+ //the first isOptional
259
+ if (param.isOptional !== true) {
260
+ minParams++;
270
261
  }
271
- else if (!platformComponentNames.has(firstParamStringValue.toLowerCase())) {
272
- this.addDiagnosticOnce(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownBrightScriptComponent(firstParamStringValue)), { range: firstParamToken.range }));
262
+ }
263
+ if (funcType.isVariadic) {
264
+ // function accepts variable number of arguments
265
+ maxParams = Expression_1.CallExpression.MaximumArguments;
266
+ }
267
+ let expCallArgCount = expression.args.length;
268
+ if (expCallArgCount > maxParams || expCallArgCount < minParams) {
269
+ let minMaxParamsText = minParams === maxParams ? maxParams : `${minParams}-${maxParams}`;
270
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expression.callee.range,
271
+ //TODO detect end of expression call
272
+ file: file }));
273
+ }
274
+ let paramIndex = 0;
275
+ for (let arg of expression.args) {
276
+ const data = {};
277
+ let argType = arg.getType({ flags: SymbolTable_1.SymbolTypeFlag.runtime, data: data });
278
+ const paramType = (_b = funcType.params[paramIndex]) === null || _b === void 0 ? void 0 : _b.type;
279
+ if (!paramType) {
280
+ // unable to find a paramType -- maybe there are more args than params
281
+ break;
273
282
  }
274
- else {
275
- // This is valid brightscript component
276
- // Test for invalid arg counts
277
- const brightScriptComponent = roku_types_1.components[firstParamStringValue.toLowerCase()];
278
- // Valid arg counts for createObject are 1+ number of args for constructor
279
- let validArgCounts = brightScriptComponent.constructors.map(cnstr => cnstr.params.length + 1);
280
- if (validArgCounts.length === 0) {
281
- // no constructors for this component, so createObject only takes 1 arg
282
- validArgCounts = [1];
283
- }
284
- if (!validArgCounts.includes(call === null || call === void 0 ? void 0 : call.args.length)) {
285
- // Incorrect number of arguments included in `createObject()`
286
- this.addDiagnosticOnce(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.mismatchCreateObjectArgumentCount(firstParamStringValue, validArgCounts, call === null || call === void 0 ? void 0 : call.args.length)), { range: call.range }));
287
- }
288
- // Test for deprecation
289
- if (brightScriptComponent.isDeprecated) {
290
- this.addDiagnosticOnce(event, Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.deprecatedBrightScriptComponent(firstParamStringValue, brightScriptComponent.deprecatedDescription)), { range: call.range }));
283
+ if ((0, reflection_1.isCallableType)(paramType) && (0, reflection_1.isClassType)(argType) && (0, reflection_1.isClassStatement)(data.definingNode)) {
284
+ // the param is expecting a function, but we're passing a Class... are we actually passing the constructor? then we're ok!
285
+ const namespace = expression.findAncestor(reflection_1.isNamespaceStatement);
286
+ if (file.calleeIsKnownFunction(arg, namespace === null || namespace === void 0 ? void 0 : namespace.getName(Parser_1.ParseMode.BrighterScript))) {
287
+ argType = data.definingNode.getConstructorType();
291
288
  }
292
289
  }
290
+ const compatibilityData = {};
291
+ if (!(paramType === null || paramType === void 0 ? void 0 : paramType.isTypeCompatible(argType, compatibilityData))) {
292
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch(argType.toString(), paramType.toString(), compatibilityData)), { range: arg.range,
293
+ //TODO detect end of expression call
294
+ file: file }));
295
+ }
296
+ paramIndex++;
293
297
  }
294
- });
295
- event.scope.addDiagnostics(diagnostics);
298
+ }
296
299
  }
297
- detectInvalidFunctionCalls(event) {
298
- const diagnostics = [];
299
- //get a list of all callables, indexed by their lower case names
300
- let callableContainerMap = event.scope.getCallableContainerMap();
301
- event.scope.enumerateBrsFiles((file) => {
302
- diagnostics.push(...this.detectInvalidFunctionCallsForFile(event.scope, file, callableContainerMap));
303
- });
304
- event.scope.addDiagnostics(diagnostics);
300
+ /**
301
+ * Detect return statements with incompatible types vs. declared return type
302
+ */
303
+ validateReturnStatement(file, returnStmt) {
304
+ var _a;
305
+ const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
306
+ let funcType = returnStmt.findAncestor(reflection_1.isFunctionExpression).getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
307
+ if ((0, reflection_1.isTypedFunctionType)(funcType)) {
308
+ const actualReturnType = (_a = returnStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
309
+ const compatibilityData = {};
310
+ if (actualReturnType && !funcType.returnType.isTypeCompatible(actualReturnType, compatibilityData)) {
311
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch(actualReturnType.toString(), funcType.returnType.toString(), compatibilityData)), { range: returnStmt.value.range, file: file }));
312
+ }
313
+ }
305
314
  }
306
315
  /**
307
- * Find functions with either the wrong type of parameters, or the wrong number of parameters
308
- */
309
- detectInvalidFunctionCallsForFile(scope, file, callableContainersByLowerName) {
310
- var _a, _b, _c, _d;
311
- const diagnostics = [];
312
- const specialCaseGlobalFunctions = ['val']; // Global callables with multiple definitions
313
- if ((0, reflection_1.isBrsFile)(file)) {
314
- for (let expCall of file.functionCalls) {
315
- const symbolTypeInfo = file.getSymbolTypeFromToken(expCall.name, expCall.functionExpression, scope);
316
- let funcType = symbolTypeInfo.type;
317
- if ((!(0, reflection_1.isTypedFunctionType)(funcType) && !(0, reflection_1.isDynamicType)(funcType)) || specialCaseGlobalFunctions.includes(expCall.name.text)) {
318
- // We don't know if this is a function. Try seeing if it is a global
319
- const callableContainer = util_1.default.getCallableContainerByFunctionCall(callableContainersByLowerName, expCall);
320
- if (callableContainer) {
321
- // We found a global callable with correct number of params - use that
322
- funcType = (_a = callableContainer.callable) === null || _a === void 0 ? void 0 : _a.type;
323
- }
324
- else {
325
- const allowedParamCount = util_1.default.getMinMaxParamCountByFunctionCall(callableContainersByLowerName, expCall);
326
- if (allowedParamCount) {
327
- // We found a global callable, but it needs a different number of args
328
- diagnostics.push(this.getMismatchParamCountDiagnostic(allowedParamCount, expCall, file));
329
- continue;
330
- }
331
- }
316
+ * Detect return statements with incompatible types vs. declared return type
317
+ */
318
+ validateDottedSetStatement(file, dottedSetStmt) {
319
+ var _a;
320
+ const typeChainExpectedLHS = [];
321
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
322
+ const expectedLHSType = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.getType(Object.assign(Object.assign({}, getTypeOpts), { data: {}, typeChain: typeChainExpectedLHS }));
323
+ const actualRHSType = (_a = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOpts);
324
+ const compatibilityData = {};
325
+ const typeChainScan = util_1.default.processTypeChain(typeChainExpectedLHS);
326
+ // check if anything in typeChain is an AA - if so, just allow it
327
+ if (typeChainExpectedLHS.find(typeChainItem => (0, reflection_1.isAssociativeArrayType)(typeChainItem.type))) {
328
+ // something in the chain is an AA
329
+ // treat members as dynamic - they could have been set without the type system's knowledge
330
+ return;
331
+ }
332
+ if (!(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isResolvable())) {
333
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
334
+ return;
335
+ }
336
+ const accessibilityIsOk = this.checkMemberAccessibility(file, dottedSetStmt, typeChainExpectedLHS);
337
+ if (accessibilityIsOk && !(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
338
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch(actualRHSType.toString(), expectedLHSType.toString(), compatibilityData)), { range: dottedSetStmt.range, file: file }));
339
+ }
340
+ }
341
+ /**
342
+ * Detect when declared type does not match rhs type
343
+ */
344
+ validateAssignmentStatement(file, assignStmt) {
345
+ var _a;
346
+ if (!(assignStmt === null || assignStmt === void 0 ? void 0 : assignStmt.typeExpression)) {
347
+ // nothing to check
348
+ return;
349
+ }
350
+ const typeChainExpectedLHS = [];
351
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
352
+ const expectedLHSType = assignStmt.typeExpression.getType(Object.assign(Object.assign({}, getTypeOpts), { data: {}, typeChain: typeChainExpectedLHS }));
353
+ const actualRHSType = (_a = assignStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOpts);
354
+ const compatibilityData = {};
355
+ if (!(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
356
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch(actualRHSType.toString(), expectedLHSType.toString(), compatibilityData)), { range: assignStmt.range, file: file }));
357
+ }
358
+ }
359
+ /**
360
+ * Detect invalid use of a binary operator
361
+ */
362
+ validateBinaryExpression(file, binaryExpr) {
363
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
364
+ if (util_1.default.isInTypeExpression(binaryExpr)) {
365
+ return;
366
+ }
367
+ let leftType = binaryExpr.left.getType(getTypeOpts);
368
+ let rightType = binaryExpr.right.getType(getTypeOpts);
369
+ if (!leftType.isResolvable() || !rightType.isResolvable()) {
370
+ // Can not find the type. error handled elsewhere
371
+ return;
372
+ }
373
+ let leftTypeToTest = leftType;
374
+ let rightTypeToTest = rightType;
375
+ if ((0, reflection_1.isEnumMemberType)(leftType) || (0, reflection_1.isEnumType)(leftType)) {
376
+ leftTypeToTest = leftType.underlyingType;
377
+ }
378
+ if ((0, reflection_1.isEnumMemberType)(rightType) || (0, reflection_1.isEnumType)(rightType)) {
379
+ rightTypeToTest = rightType.underlyingType;
380
+ }
381
+ if ((0, reflection_1.isUnionType)(leftType) || (0, reflection_1.isUnionType)(rightType)) {
382
+ // TODO: it is possible to validate based on innerTypes, but more complicated
383
+ // Because you need to verify each combination of types
384
+ return;
385
+ }
386
+ const leftIsPrimitive = (0, reflection_1.isPrimitiveType)(leftTypeToTest);
387
+ const rightIsPrimitive = (0, reflection_1.isPrimitiveType)(rightTypeToTest);
388
+ const leftIsAny = (0, reflection_1.isDynamicType)(leftTypeToTest) || (0, reflection_1.isObjectType)(leftTypeToTest);
389
+ const rightIsAny = (0, reflection_1.isDynamicType)(rightTypeToTest) || (0, reflection_1.isObjectType)(rightTypeToTest);
390
+ if (leftIsAny && rightIsAny) {
391
+ // both operands are basically "any" type... ignore;
392
+ return;
393
+ }
394
+ else if ((leftIsAny && rightIsPrimitive) || (leftIsPrimitive && rightIsAny)) {
395
+ // one operand is basically "any" type... ignore;
396
+ return;
397
+ }
398
+ const opResult = util_1.default.binaryOperatorResultType(leftTypeToTest, binaryExpr.tokens.operator, rightTypeToTest);
399
+ if ((0, reflection_1.isDynamicType)(opResult)) {
400
+ // if the result was dynamic, that means there wasn't a valid operation
401
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(binaryExpr.tokens.operator.text, leftType.toString(), rightType.toString())), { range: binaryExpr.range, file: file }));
402
+ }
403
+ }
404
+ /**
405
+ * Detect invalid use of a Unary operator
406
+ */
407
+ validateUnaryExpression(file, unaryExpr) {
408
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
409
+ let rightType = unaryExpr.right.getType(getTypeOpts);
410
+ if (!rightType.isResolvable()) {
411
+ // Can not find the type. error handled elsewhere
412
+ return;
413
+ }
414
+ let rightTypeToTest = rightType;
415
+ if ((0, reflection_1.isEnumMemberType)(rightType)) {
416
+ rightTypeToTest = rightType.underlyingType;
417
+ }
418
+ if ((0, reflection_1.isUnionType)(rightTypeToTest)) {
419
+ // TODO: it is possible to validate based on innerTypes, but more complicated
420
+ // Because you need to verify each combination of types
421
+ }
422
+ else if ((0, reflection_1.isDynamicType)(rightTypeToTest) || (0, reflection_1.isObjectType)(rightTypeToTest)) {
423
+ // operand is basically "any" type... ignore;
424
+ }
425
+ else if ((0, reflection_1.isPrimitiveType)(rightType)) {
426
+ const opResult = util_1.default.unaryOperatorResultType(unaryExpr.tokens.operator, rightTypeToTest);
427
+ if ((0, reflection_1.isDynamicType)(opResult)) {
428
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(unaryExpr.tokens.operator.text, rightType.toString())), { range: unaryExpr.range, file: file }));
429
+ }
430
+ }
431
+ else {
432
+ // rhs is not a primitive, so no binary operator is allowed
433
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(unaryExpr.tokens.operator.text, rightType.toString())), { range: unaryExpr.range, file: file }));
434
+ }
435
+ }
436
+ validateVariableAndDottedGetExpressions(file, expression) {
437
+ var _a, _b;
438
+ if ((0, reflection_1.isDottedGetExpression)(expression.parent)) {
439
+ // We validate dottedGetExpressions at the top-most level
440
+ return;
441
+ }
442
+ if ((0, reflection_1.isVariableExpression)(expression)) {
443
+ if ((0, reflection_1.isAssignmentStatement)(expression.parent) && expression.parent.tokens.name === expression.tokens.name) {
444
+ // Don't validate LHS of assignments
445
+ return;
446
+ }
447
+ else if ((0, reflection_1.isNamespaceStatement)(expression.parent)) {
448
+ return;
449
+ }
450
+ }
451
+ let symbolType = SymbolTable_1.SymbolTypeFlag.runtime;
452
+ let oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.typetime;
453
+ const isUsedAsType = util_1.default.isInTypeExpression(expression);
454
+ if (isUsedAsType) {
455
+ // This is used in a TypeExpression - only look up types from SymbolTable
456
+ symbolType = SymbolTable_1.SymbolTypeFlag.typetime;
457
+ oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.runtime;
458
+ }
459
+ // Do a complete type check on all DottedGet and Variable expressions
460
+ // this will create a diagnostic if an invalid member is accessed
461
+ const typeChain = [];
462
+ const typeData = {};
463
+ let exprType = expression.getType({
464
+ flags: symbolType,
465
+ typeChain: typeChain,
466
+ data: typeData
467
+ });
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()) {
471
+ const oppoSiteTypeChain = [];
472
+ const invalidlyUsedResolvedType = expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain });
473
+ const typeChainScan = util_1.default.processTypeChain(oppoSiteTypeChain);
474
+ if (isUsedAsType) {
475
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsType(typeChainScan.fullChainName)), { range: expression.range, file: file }));
332
476
  }
333
- if ((0, reflection_1.isFunctionType)(funcType)) {
334
- // This is a generic function, and it is callable
477
+ else {
478
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: expression.range, file: file }));
335
479
  }
336
- else if ((0, reflection_1.isTypedFunctionType)(funcType)) {
337
- // Check for Argument count mismatch.
338
- //get min/max parameter count for callable
339
- let paramCount = util_1.default.getMinMaxParamCount(funcType.params);
340
- if (expCall.args.length > paramCount.max || expCall.args.length < paramCount.min) {
341
- diagnostics.push(this.getMismatchParamCountDiagnostic(paramCount, expCall, file));
342
- }
343
- // Check for Argument type mismatch.
344
- const paramTypeContext = { file: file, scope: scope, position: (_b = expCall.functionExpression.range) === null || _b === void 0 ? void 0 : _b.start };
345
- const argTypeContext = { file: file, scope: scope, position: (_c = expCall.range) === null || _c === void 0 ? void 0 : _c.start };
346
- for (let index = 0; index < funcType.params.length; index++) {
347
- const param = funcType.params[index];
348
- const arg = expCall.args[index];
349
- if (!arg) {
350
- // not enough args
351
- break;
352
- }
353
- let argType = (_d = arg.type) !== null && _d !== void 0 ? _d : new UninitializedType_1.UninitializedType();
354
- const paramType = (0, BscType_1.getTypeFromContext)(param.type, paramTypeContext);
355
- if (!paramType) {
356
- // other error - can not determine what type this parameter should be
357
- continue;
358
- }
359
- argType = (0, BscType_1.getTypeFromContext)(argType, argTypeContext);
360
- let assignable = argType === null || argType === void 0 ? void 0 : argType.isAssignableTo(paramType, argTypeContext);
361
- if (!assignable) {
362
- // TODO TYPES: perhaps this should be a strict mode setting?
363
- assignable = argType === null || argType === void 0 ? void 0 : argType.isConvertibleTo(paramType, argTypeContext);
480
+ }
481
+ else {
482
+ const typeChainScan = util_1.default.processTypeChain(typeChain);
483
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
484
+ }
485
+ }
486
+ if (isUsedAsType) {
487
+ return;
488
+ }
489
+ const lastTypeInfo = typeChain[typeChain.length - 1];
490
+ const parentTypeInfo = typeChain[typeChain.length - 2];
491
+ this.checkMemberAccessibility(file, expression, typeChain);
492
+ if ((0, reflection_1.isNamespaceType)(exprType)) {
493
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: expression.range, file: file }));
494
+ }
495
+ else if ((0, reflection_1.isEnumType)(exprType)) {
496
+ const enumStatement = this.event.scope.getEnum(util_1.default.getAllDottedGetPartsAsString(expression));
497
+ if (enumStatement) {
498
+ // there's an enum with this name
499
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('enum')), { range: expression.range, file: file }));
500
+ }
501
+ }
502
+ else if ((0, reflection_1.isDynamicType)(exprType) && (0, reflection_1.isEnumType)(parentTypeInfo === null || parentTypeInfo === void 0 ? void 0 : parentTypeInfo.type) && (0, reflection_1.isDottedGetExpression)(expression)) {
503
+ const enumFileLink = this.event.scope.getEnumFileLink(util_1.default.getAllDottedGetPartsAsString(expression.obj));
504
+ const typeChainScanForParent = util_1.default.processTypeChain(typeChain.slice(0, -1));
505
+ if (enumFileLink) {
506
+ 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
+ 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)
509
+ }] }));
510
+ }
511
+ }
512
+ }
513
+ /**
514
+ * Adds diagnostics for accibility mismatches
515
+ *
516
+ * @param file file
517
+ * @param expression containing expression
518
+ * @param typeChain type chain to check
519
+ * @returns true if member accesiibility is okay
520
+ */
521
+ checkMemberAccessibility(file, expression, typeChain) {
522
+ var _a, _b, _c;
523
+ for (let i = 0; i < typeChain.length - 1; i++) {
524
+ const parentChainItem = typeChain[i];
525
+ const childChainItem = typeChain[i + 1];
526
+ if ((0, reflection_1.isClassType)(parentChainItem.type)) {
527
+ const containingClassStmt = expression.findAncestor(reflection_1.isClassStatement);
528
+ const classStmtThatDefinesChildMember = (_b = (_a = childChainItem.data) === null || _a === void 0 ? void 0 : _a.definingNode) === null || _b === void 0 ? void 0 : _b.findAncestor(reflection_1.isClassStatement);
529
+ if (classStmtThatDefinesChildMember) {
530
+ const definingClassName = classStmtThatDefinesChildMember.getName(Parser_1.ParseMode.BrighterScript);
531
+ const inMatchingClassStmt = (containingClassStmt === null || containingClassStmt === void 0 ? void 0 : containingClassStmt.getName(Parser_1.ParseMode.BrighterScript).toLowerCase()) === parentChainItem.type.name.toLowerCase();
532
+ // eslint-disable-next-line no-bitwise
533
+ if (childChainItem.data.flags & SymbolTable_1.SymbolTypeFlag.private) {
534
+ if (!inMatchingClassStmt || childChainItem.data.memberOfAncestor) {
535
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch(childChainItem.name, childChainItem.data.flags, definingClassName)), { range: expression.range, file: file }));
536
+ // there's an error... don't worry about the rest of the chain
537
+ return false;
364
538
  }
365
- if (!assignable) {
366
- diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch(argType === null || argType === void 0 ? void 0 : argType.toString(argTypeContext), paramType.toString(paramTypeContext))), { range: arg === null || arg === void 0 ? void 0 : arg.range, file: file }));
539
+ }
540
+ // eslint-disable-next-line no-bitwise
541
+ if (childChainItem.data.flags & SymbolTable_1.SymbolTypeFlag.protected) {
542
+ const containingClassName = containingClassStmt === null || containingClassStmt === void 0 ? void 0 : containingClassStmt.getName(Parser_1.ParseMode.BrighterScript);
543
+ const containingNamespaceName = (_c = expression.findAncestor(reflection_1.isNamespaceStatement)) === null || _c === void 0 ? void 0 : _c.getName(Parser_1.ParseMode.BrighterScript);
544
+ const ancestorClasses = this.event.scope.getClassHierarchy(containingClassName, containingNamespaceName).map(link => link.item);
545
+ const isSubClassOfDefiningClass = ancestorClasses.includes(classStmtThatDefinesChildMember);
546
+ if (!isSubClassOfDefiningClass) {
547
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch(childChainItem.name, childChainItem.data.flags, definingClassName)), { range: expression.range, file: file }));
548
+ // there's an error... don't worry about the rest of the chain
549
+ return false;
367
550
  }
368
551
  }
369
552
  }
370
- else if ((0, reflection_1.isInvalidType)(symbolTypeInfo.type)) {
371
- // TODO TYPES: standard member functions like integer.ToStr() are not detectable yet.
372
- }
373
- else if ((0, reflection_1.isDynamicType)(symbolTypeInfo.type)) {
374
- // maybe this is a function? who knows
375
- }
376
- else {
377
- diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(symbolTypeInfo.expandedTokenText, symbolTypeInfo.fullName)), { range: expCall.range, file: file }));
378
- }
379
553
  }
380
554
  }
381
- return diagnostics;
555
+ return true;
556
+ }
557
+ /**
558
+ * Adds a diagnostic to the first scope for this key. Prevents duplicate diagnostics
559
+ * for diagnostics where scope isn't important. (i.e. CreateObject validations)
560
+ */
561
+ addDiagnosticOnce(diagnostic) {
562
+ this.onceCache.getOrAdd(`${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
563
+ const diagnosticWithOrigin = Object.assign({}, diagnostic);
564
+ if (!diagnosticWithOrigin.origin) {
565
+ // diagnostic does not have origin.
566
+ // set the origin to the current astSegment
567
+ diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
568
+ diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
569
+ }
570
+ this.event.scope.addDiagnostics([diagnosticWithOrigin]);
571
+ return true;
572
+ });
573
+ }
574
+ addDiagnostic(diagnostic) {
575
+ const diagnosticWithOrigin = Object.assign({}, diagnostic);
576
+ if (!diagnosticWithOrigin.origin) {
577
+ // diagnostic does not have origin.
578
+ // set the origin to the current astSegment
579
+ diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
580
+ diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
581
+ }
582
+ this.event.scope.addDiagnostics([diagnosticWithOrigin]);
382
583
  }
383
- getMismatchParamCountDiagnostic(paramCount, expCall, file) {
384
- const minMaxParamsText = paramCount.min === paramCount.max ? paramCount.max : `${paramCount.min}-${paramCount.max}`;
385
- const expCallArgCount = expCall.args.length;
386
- return (Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expCall.nameRange, file: file }));
584
+ /**
585
+ * Add a diagnostic (to the first scope) that will have `relatedInformation` for each affected scope
586
+ */
587
+ addMultiScopeDiagnostic(diagnostic) {
588
+ 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)}`, () => {
590
+ if (!diagnostic.relatedInformation) {
591
+ diagnostic.relatedInformation = [];
592
+ }
593
+ const diagnosticWithOrigin = Object.assign({}, diagnostic);
594
+ if (!diagnosticWithOrigin.origin) {
595
+ // diagnostic does not have origin.
596
+ // set the origin to the current astSegment
597
+ diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
598
+ diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
599
+ }
600
+ this.addDiagnostic(diagnosticWithOrigin);
601
+ return diagnosticWithOrigin;
602
+ });
603
+ if ((0, reflection_1.isXmlScope)(this.event.scope) && ((_b = this.event.scope.xmlFile) === null || _b === void 0 ? void 0 : _b.srcPath)) {
604
+ diagnostic.relatedInformation.push({
605
+ message: `In component scope '${(_e = (_d = (_c = this.event.scope) === null || _c === void 0 ? void 0 : _c.xmlFile) === null || _d === void 0 ? void 0 : _d.componentName) === null || _e === void 0 ? void 0 : _e.text}'`,
606
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(this.event.scope.xmlFile.srcPath).toString(), (_o = (_m = (_l = (_k = (_j = (_h = (_g = (_f = this.event.scope) === null || _f === void 0 ? void 0 : _f.xmlFile) === null || _g === void 0 ? void 0 : _g.ast) === null || _h === void 0 ? void 0 : _h.componentElement) === null || _j === void 0 ? void 0 : _j.getAttribute('name')) === null || _k === void 0 ? void 0 : _k.tokens) === null || _l === void 0 ? void 0 : _l.value) === null || _m === void 0 ? void 0 : _m.range) !== null && _o !== void 0 ? _o : util_1.default.createRange(0, 0, 0, 10))
607
+ });
608
+ }
609
+ else {
610
+ diagnostic.relatedInformation.push({
611
+ message: `In scope '${this.event.scope.name}'`,
612
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(diagnostic.file.srcPath).toString(), diagnostic.range)
613
+ });
614
+ }
387
615
  }
388
616
  }
389
617
  exports.ScopeValidator = ScopeValidator;