brighterscript 1.0.0-alpha.24 → 1.0.0-alpha.25

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 (530) hide show
  1. package/CHANGELOG.md +493 -233
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +41 -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 +39 -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 +831 -695
  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 +87 -133
  60. package/dist/Scope.js +450 -510
  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 -6
  74. package/dist/XmlScope.js +74 -69
  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} +68 -64
  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 +26 -16
  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 +208 -126
  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 +178 -33
  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 +10 -2
  105. package/dist/bscPlugin/BscPlugin.js +33 -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 +135 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +14 -11
  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/fileProviders/FileProvider.d.ts +9 -0
  126. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  127. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  128. package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
  129. package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
  130. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  131. package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
  132. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  133. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
  134. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +85 -23
  135. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  136. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
  137. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  138. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  139. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  140. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  141. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  142. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  143. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  144. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  145. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  146. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  147. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +33 -9
  148. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  149. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  150. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  151. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  152. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  153. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  154. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  155. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
  156. package/dist/bscPlugin/validation/BrsFileValidator.js +259 -49
  157. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  158. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
  159. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  160. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  161. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  162. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  163. package/dist/bscPlugin/validation/ScopeValidator.d.ts +54 -27
  164. package/dist/bscPlugin/validation/ScopeValidator.js +483 -286
  165. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  166. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  167. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
  168. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  169. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  170. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  171. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  172. package/dist/cli.js +104 -13
  173. package/dist/cli.js.map +1 -1
  174. package/dist/deferred.d.ts +3 -3
  175. package/dist/deferred.js.map +1 -1
  176. package/dist/diagnosticUtils.d.ts +8 -2
  177. package/dist/diagnosticUtils.js +47 -17
  178. package/dist/diagnosticUtils.js.map +1 -1
  179. package/dist/examples/plugins/removePrint.js +8 -10
  180. package/dist/examples/plugins/removePrint.js.map +1 -1
  181. package/dist/files/AssetFile.d.ts +26 -0
  182. package/dist/files/AssetFile.js +26 -0
  183. package/dist/files/AssetFile.js.map +1 -0
  184. package/dist/files/BrsFile.Class.spec.js +523 -493
  185. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  186. package/dist/files/BrsFile.d.ts +112 -111
  187. package/dist/files/BrsFile.js +741 -1032
  188. package/dist/files/BrsFile.js.map +1 -1
  189. package/dist/files/BrsFile.spec.js +1728 -1232
  190. package/dist/files/BrsFile.spec.js.map +1 -1
  191. package/dist/files/BscFile.d.ts +104 -0
  192. package/dist/files/BscFile.js +16 -0
  193. package/dist/files/BscFile.js.map +1 -0
  194. package/dist/files/Factory.d.ts +25 -0
  195. package/dist/files/Factory.js +22 -0
  196. package/dist/files/Factory.js.map +1 -0
  197. package/dist/files/LazyFileData.d.ts +20 -0
  198. package/dist/files/LazyFileData.js +54 -0
  199. package/dist/files/LazyFileData.js.map +1 -0
  200. package/dist/files/LazyFileData.spec.d.ts +1 -0
  201. package/dist/files/LazyFileData.spec.js +27 -0
  202. package/dist/files/LazyFileData.spec.js.map +1 -0
  203. package/dist/files/XmlFile.d.ts +70 -32
  204. package/dist/files/XmlFile.js +106 -118
  205. package/dist/files/XmlFile.js.map +1 -1
  206. package/dist/files/XmlFile.spec.js +325 -262
  207. package/dist/files/XmlFile.spec.js.map +1 -1
  208. package/dist/files/tests/imports.spec.js +48 -40
  209. package/dist/files/tests/imports.spec.js.map +1 -1
  210. package/dist/files/tests/optionalChaning.spec.js +84 -24
  211. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  212. package/dist/globalCallables.js +16 -21
  213. package/dist/globalCallables.js.map +1 -1
  214. package/dist/index.d.ts +12 -1
  215. package/dist/index.js +12 -1
  216. package/dist/index.js.map +1 -1
  217. package/dist/interfaces.d.ts +389 -161
  218. package/dist/interfaces.js +27 -0
  219. package/dist/interfaces.js.map +1 -1
  220. package/dist/lexer/Character.spec.js +5 -5
  221. package/dist/lexer/Character.spec.js.map +1 -1
  222. package/dist/lexer/Lexer.d.ts +12 -5
  223. package/dist/lexer/Lexer.js +28 -13
  224. package/dist/lexer/Lexer.js.map +1 -1
  225. package/dist/lexer/Lexer.spec.js +181 -135
  226. package/dist/lexer/Lexer.spec.js.map +1 -1
  227. package/dist/lexer/Token.d.ts +9 -1
  228. package/dist/lexer/Token.js +9 -1
  229. package/dist/lexer/Token.js.map +1 -1
  230. package/dist/lexer/TokenKind.d.ts +8 -0
  231. package/dist/lexer/TokenKind.js +24 -4
  232. package/dist/lexer/TokenKind.js.map +1 -1
  233. package/dist/parser/AstNode.d.ts +162 -0
  234. package/dist/parser/AstNode.js +225 -0
  235. package/dist/parser/AstNode.js.map +1 -0
  236. package/dist/parser/AstNode.spec.d.ts +1 -0
  237. package/dist/parser/AstNode.spec.js +165 -0
  238. package/dist/parser/AstNode.spec.js.map +1 -0
  239. package/dist/parser/BrsTranspileState.d.ts +4 -7
  240. package/dist/parser/BrsTranspileState.js +4 -12
  241. package/dist/parser/BrsTranspileState.js.map +1 -1
  242. package/dist/parser/Expression.d.ts +126 -176
  243. package/dist/parser/Expression.js +523 -405
  244. package/dist/parser/Expression.js.map +1 -1
  245. package/dist/parser/Parser.Class.spec.js +151 -145
  246. package/dist/parser/Parser.Class.spec.js.map +1 -1
  247. package/dist/parser/Parser.d.ts +43 -201
  248. package/dist/parser/Parser.js +446 -962
  249. package/dist/parser/Parser.js.map +1 -1
  250. package/dist/parser/Parser.spec.d.ts +3 -1
  251. package/dist/parser/Parser.spec.js +1002 -846
  252. package/dist/parser/Parser.spec.js.map +1 -1
  253. package/dist/parser/SGParser.d.ts +9 -8
  254. package/dist/parser/SGParser.js +10 -8
  255. package/dist/parser/SGParser.js.map +1 -1
  256. package/dist/parser/SGParser.spec.js +27 -38
  257. package/dist/parser/SGParser.spec.js.map +1 -1
  258. package/dist/parser/SGTypes.d.ts +98 -35
  259. package/dist/parser/SGTypes.js +169 -99
  260. package/dist/parser/SGTypes.js.map +1 -1
  261. package/dist/parser/Statement.d.ts +183 -131
  262. package/dist/parser/Statement.js +549 -387
  263. package/dist/parser/Statement.js.map +1 -1
  264. package/dist/parser/Statement.spec.js +45 -21
  265. package/dist/parser/Statement.spec.js.map +1 -1
  266. package/dist/parser/TranspileState.d.ts +1 -1
  267. package/dist/parser/TranspileState.js +7 -12
  268. package/dist/parser/TranspileState.js.map +1 -1
  269. package/dist/parser/tests/Parser.spec.js +3 -2
  270. package/dist/parser/tests/Parser.spec.js.map +1 -1
  271. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  272. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  273. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  274. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  275. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  276. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  277. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  278. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  279. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  280. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  281. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  282. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  283. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
  284. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  285. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  286. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  287. package/dist/parser/tests/expression/Call.spec.js +129 -21
  288. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  289. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  290. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  291. package/dist/parser/tests/expression/Function.spec.js +36 -36
  292. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  293. package/dist/parser/tests/expression/Indexing.spec.js +67 -22
  294. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  295. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  296. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  297. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
  298. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  299. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  300. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  301. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  302. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  303. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  304. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  305. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  306. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  307. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  308. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  309. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
  310. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  311. package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
  312. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  313. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  314. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  315. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  316. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  317. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  318. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  319. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  320. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  321. package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
  322. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  323. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  324. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  325. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  326. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  327. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  328. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  329. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  330. package/dist/parser/tests/statement/Enum.spec.js +98 -302
  331. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  332. package/dist/parser/tests/statement/For.spec.js +9 -10
  333. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  335. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/Function.spec.js +44 -35
  337. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  339. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  341. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  343. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  345. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  347. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/PrintStatement.spec.js +35 -33
  349. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  351. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/Set.spec.js +48 -35
  353. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  355. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  357. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  359. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  360. package/dist/preprocessor/Manifest.d.ts +1 -1
  361. package/dist/preprocessor/Manifest.js +2 -2
  362. package/dist/preprocessor/Manifest.js.map +1 -1
  363. package/dist/preprocessor/Manifest.spec.js +8 -8
  364. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  365. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  366. package/dist/preprocessor/Preprocessor.js +5 -5
  367. package/dist/preprocessor/Preprocessor.js.map +1 -1
  368. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  369. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  370. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  371. package/dist/preprocessor/PreprocessorParser.js +7 -1
  372. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  373. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  374. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  375. package/dist/roku-types/data.json +5892 -10081
  376. package/dist/roku-types/index.d.ts +622 -1719
  377. package/dist/types/ArrayType.d.ts +10 -9
  378. package/dist/types/ArrayType.js +65 -60
  379. package/dist/types/ArrayType.js.map +1 -1
  380. package/dist/types/ArrayType.spec.js +36 -68
  381. package/dist/types/ArrayType.spec.js.map +1 -1
  382. package/dist/types/AssociativeArrayType.d.ts +11 -0
  383. package/dist/types/AssociativeArrayType.js +52 -0
  384. package/dist/types/AssociativeArrayType.js.map +1 -0
  385. package/dist/types/BaseFunctionType.d.ts +9 -0
  386. package/dist/types/BaseFunctionType.js +25 -0
  387. package/dist/types/BaseFunctionType.js.map +1 -0
  388. package/dist/types/BooleanType.d.ts +8 -5
  389. package/dist/types/BooleanType.js +14 -7
  390. package/dist/types/BooleanType.js.map +1 -1
  391. package/dist/types/BooleanType.spec.js +10 -6
  392. package/dist/types/BooleanType.spec.js.map +1 -1
  393. package/dist/types/BscType.d.ts +32 -21
  394. package/dist/types/BscType.js +118 -21
  395. package/dist/types/BscType.js.map +1 -1
  396. package/dist/types/BscTypeKind.d.ts +25 -0
  397. package/dist/types/BscTypeKind.js +30 -0
  398. package/dist/types/BscTypeKind.js.map +1 -0
  399. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  400. package/dist/types/BuiltInInterfaceAdder.js +164 -0
  401. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  402. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  403. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  404. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  405. package/dist/types/ClassType.d.ts +17 -0
  406. package/dist/types/ClassType.js +58 -0
  407. package/dist/types/ClassType.js.map +1 -0
  408. package/dist/types/ClassType.spec.d.ts +1 -0
  409. package/dist/types/ClassType.spec.js +77 -0
  410. package/dist/types/ClassType.spec.js.map +1 -0
  411. package/dist/types/ComponentType.d.ts +26 -0
  412. package/dist/types/ComponentType.js +83 -0
  413. package/dist/types/ComponentType.js.map +1 -0
  414. package/dist/types/DoubleType.d.ts +8 -5
  415. package/dist/types/DoubleType.js +18 -16
  416. package/dist/types/DoubleType.js.map +1 -1
  417. package/dist/types/DoubleType.spec.js +12 -6
  418. package/dist/types/DoubleType.spec.js.map +1 -1
  419. package/dist/types/DynamicType.d.ts +9 -5
  420. package/dist/types/DynamicType.js +15 -4
  421. package/dist/types/DynamicType.js.map +1 -1
  422. package/dist/types/DynamicType.spec.js +16 -5
  423. package/dist/types/DynamicType.spec.js.map +1 -1
  424. package/dist/types/EnumType.d.ts +30 -12
  425. package/dist/types/EnumType.js +43 -17
  426. package/dist/types/EnumType.js.map +1 -1
  427. package/dist/types/EnumType.spec.d.ts +1 -0
  428. package/dist/types/EnumType.spec.js +33 -0
  429. package/dist/types/EnumType.spec.js.map +1 -0
  430. package/dist/types/FloatType.d.ts +8 -5
  431. package/dist/types/FloatType.js +18 -16
  432. package/dist/types/FloatType.js.map +1 -1
  433. package/dist/types/FloatType.spec.js +4 -6
  434. package/dist/types/FloatType.spec.js.map +1 -1
  435. package/dist/types/FunctionType.d.ts +13 -8
  436. package/dist/types/FunctionType.js +30 -14
  437. package/dist/types/FunctionType.js.map +1 -1
  438. package/dist/types/InheritableType.d.ts +28 -0
  439. package/dist/types/InheritableType.js +152 -0
  440. package/dist/types/InheritableType.js.map +1 -0
  441. package/dist/types/IntegerType.d.ts +8 -5
  442. package/dist/types/IntegerType.js +18 -16
  443. package/dist/types/IntegerType.js.map +1 -1
  444. package/dist/types/IntegerType.spec.js +8 -6
  445. package/dist/types/IntegerType.spec.js.map +1 -1
  446. package/dist/types/InterfaceType.d.ts +12 -13
  447. package/dist/types/InterfaceType.js +20 -48
  448. package/dist/types/InterfaceType.js.map +1 -1
  449. package/dist/types/InterfaceType.spec.js +90 -56
  450. package/dist/types/InterfaceType.spec.js.map +1 -1
  451. package/dist/types/InvalidType.d.ts +7 -5
  452. package/dist/types/InvalidType.js +13 -7
  453. package/dist/types/InvalidType.js.map +1 -1
  454. package/dist/types/InvalidType.spec.js +8 -6
  455. package/dist/types/InvalidType.spec.js.map +1 -1
  456. package/dist/types/LongIntegerType.d.ts +8 -5
  457. package/dist/types/LongIntegerType.js +17 -15
  458. package/dist/types/LongIntegerType.js.map +1 -1
  459. package/dist/types/LongIntegerType.spec.js +10 -6
  460. package/dist/types/LongIntegerType.spec.js.map +1 -1
  461. package/dist/types/NamespaceType.d.ts +12 -0
  462. package/dist/types/NamespaceType.js +28 -0
  463. package/dist/types/NamespaceType.js.map +1 -0
  464. package/dist/types/ObjectType.d.ts +9 -8
  465. package/dist/types/ObjectType.js +21 -11
  466. package/dist/types/ObjectType.js.map +1 -1
  467. package/dist/types/ObjectType.spec.js +3 -3
  468. package/dist/types/ObjectType.spec.js.map +1 -1
  469. package/dist/types/ReferenceType.d.ts +63 -0
  470. package/dist/types/ReferenceType.js +423 -0
  471. package/dist/types/ReferenceType.js.map +1 -0
  472. package/dist/types/ReferenceType.spec.d.ts +1 -0
  473. package/dist/types/ReferenceType.spec.js +137 -0
  474. package/dist/types/ReferenceType.spec.js.map +1 -0
  475. package/dist/types/StringType.d.ts +11 -5
  476. package/dist/types/StringType.js +18 -7
  477. package/dist/types/StringType.js.map +1 -1
  478. package/dist/types/StringType.spec.js +3 -5
  479. package/dist/types/StringType.spec.js.map +1 -1
  480. package/dist/types/TypedFunctionType.d.ts +22 -17
  481. package/dist/types/TypedFunctionType.js +78 -60
  482. package/dist/types/TypedFunctionType.js.map +1 -1
  483. package/dist/types/TypedFunctionType.spec.js +105 -20
  484. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  485. package/dist/types/UninitializedType.d.ts +8 -6
  486. package/dist/types/UninitializedType.js +13 -7
  487. package/dist/types/UninitializedType.js.map +1 -1
  488. package/dist/types/UnionType.d.ts +20 -0
  489. package/dist/types/UnionType.js +123 -0
  490. package/dist/types/UnionType.js.map +1 -0
  491. package/dist/types/UnionType.spec.d.ts +1 -0
  492. package/dist/types/UnionType.spec.js +130 -0
  493. package/dist/types/UnionType.spec.js.map +1 -0
  494. package/dist/types/VoidType.d.ts +8 -5
  495. package/dist/types/VoidType.js +14 -7
  496. package/dist/types/VoidType.js.map +1 -1
  497. package/dist/types/VoidType.spec.js +3 -3
  498. package/dist/types/VoidType.spec.js.map +1 -1
  499. package/dist/types/helper.spec.d.ts +1 -0
  500. package/dist/types/helper.spec.js +145 -0
  501. package/dist/types/helper.spec.js.map +1 -0
  502. package/dist/types/helpers.d.ts +19 -37
  503. package/dist/types/helpers.js +159 -99
  504. package/dist/types/helpers.js.map +1 -1
  505. package/dist/types/index.d.ts +22 -0
  506. package/dist/types/index.js +39 -0
  507. package/dist/types/index.js.map +1 -0
  508. package/dist/util.d.ts +132 -137
  509. package/dist/util.js +796 -362
  510. package/dist/util.js.map +1 -1
  511. package/dist/validators/ClassValidator.d.ts +8 -25
  512. package/dist/validators/ClassValidator.js +96 -176
  513. package/dist/validators/ClassValidator.js.map +1 -1
  514. package/package.json +165 -152
  515. package/dist/astUtils/AstEditor.js.map +0 -1
  516. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  517. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  518. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  519. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  520. package/dist/parser/SGTypes.spec.js +0 -351
  521. package/dist/parser/SGTypes.spec.js.map +0 -1
  522. package/dist/types/CustomType.d.ts +0 -12
  523. package/dist/types/CustomType.js +0 -44
  524. package/dist/types/CustomType.js.map +0 -1
  525. package/dist/types/LazyType.d.ts +0 -16
  526. package/dist/types/LazyType.js +0 -44
  527. package/dist/types/LazyType.js.map +0 -1
  528. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  529. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  530. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/serialize/BslibInjector.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,117 @@ 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
45
  }
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
- }
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
+ });
95
+ const segmentsToWalkForValidation = (thisFileHasChanges || !hasChangeInfo)
96
+ ? file.validationSegmenter.segmentsForValidation // validate everything in the file
97
+ : file.getValidationSegments(this.event.changedSymbols); // validate only what's needed in the file
98
+ for (const segment of segmentsToWalkForValidation) {
99
+ this.currentSegmentBeingValidated = segment;
100
+ this.event.scope.clearAstSegmentDiagnostics(segment);
101
+ segment.walk(validationVisitor, {
102
+ walkMode: AstValidationSegmenter_1.InsideSegmentWalkMode
103
+ });
104
+ file.markSegmentAsValidated(segment);
105
+ }
175
106
  }
176
107
  });
177
108
  }
109
+ isTypeKnown(exprType) {
110
+ let isKnownType = exprType === null || exprType === void 0 ? void 0 : exprType.isResolvable();
111
+ return isKnownType;
112
+ }
178
113
  /**
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`
114
+ * If this is the lhs of an assignment, we don't need to flag it as unresolved
181
115
  */
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;
116
+ ignoreUnresolvedAssignmentLHS(expression, exprType, definingNode) {
117
+ var _a, _b;
118
+ if (!(0, reflection_1.isVariableExpression)(expression)) {
119
+ return false;
120
+ }
121
+ let assignmentAncestor;
122
+ if ((0, reflection_1.isAssignmentStatement)(definingNode) && definingNode.equals.kind === TokenKind_1.TokenKind.Equal) {
123
+ // this symbol was defined in a "normal" assignment (eg. not a compound assignment)
124
+ assignmentAncestor = definingNode;
125
+ return ((_a = assignmentAncestor === null || assignmentAncestor === void 0 ? void 0 : assignmentAncestor.name) === null || _a === void 0 ? void 0 : _a.text.toLowerCase()) === ((_b = expression === null || expression === void 0 ? void 0 : expression.name) === null || _b === void 0 ? void 0 : _b.text.toLowerCase());
126
+ }
127
+ else {
128
+ assignmentAncestor = expression === null || expression === void 0 ? void 0 : expression.findAncestor(reflection_1.isAssignmentStatement);
129
+ }
130
+ return (assignmentAncestor === null || assignmentAncestor === void 0 ? void 0 : assignmentAncestor.name) === (expression === null || expression === void 0 ? void 0 : expression.name) && (0, reflection_1.isUnionType)(exprType);
192
131
  }
193
132
  /**
194
133
  * Flag duplicate enums
195
134
  */
196
- detectDuplicateEnums(event) {
135
+ detectDuplicateEnums() {
197
136
  const diagnostics = [];
198
137
  const enumLocationsByName = new Cache_1.Cache();
199
- event.scope.enumerateBrsFiles((file) => {
200
- for (const enumStatement of file.parser.references.enumStatements) {
138
+ this.event.scope.enumerateBrsFiles((file) => {
139
+ // eslint-disable-next-line @typescript-eslint/dot-notation
140
+ for (const enumStatement of file['_cachedLookups'].enumStatements) {
201
141
  const fullName = enumStatement.fullName;
202
142
  const nameLower = fullName === null || fullName === void 0 ? void 0 : fullName.toLowerCase();
203
143
  if ((nameLower === null || nameLower === void 0 ? void 0 : nameLower.length) > 0) {
@@ -226,13 +166,13 @@ class ScopeValidator {
226
166
  const primaryEnum = enumLocations.shift();
227
167
  const fullName = primaryEnum.statement.fullName;
228
168
  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: [{
169
+ 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
170
  message: 'Enum declared here',
231
171
  location: util_1.default.createLocation(vscode_uri_1.URI.file(primaryEnum.file.srcPath).toString(), primaryEnum.statement.tokens.name.range)
232
- }] }));
172
+ }], origin: interfaces_1.DiagnosticOrigin.Scope }));
233
173
  }
234
174
  }
235
- event.scope.addDiagnostics(diagnostics);
175
+ this.event.scope.addDiagnostics(diagnostics);
236
176
  }
237
177
  /**
238
178
  * Validate every function call to `CreateObject`.
@@ -240,150 +180,407 @@ class ScopeValidator {
240
180
  * what these calls are supposed to look like, and this is a very common thing for brs devs to do, so just
241
181
  * do this manually for now.
242
182
  */
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
- }
183
+ validateCreateObjectCall(file, call) {
184
+ var _a, _b, _c, _d, _e, _f;
185
+ //skip non CreateObject function calls
186
+ const callName = (_a = util_1.default.getAllDottedGetPartsAsString(call.callee)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
187
+ if (callName !== 'createobject' || !(0, reflection_1.isLiteralExpression)(call === null || call === void 0 ? void 0 : call.args[0])) {
188
+ return;
189
+ }
190
+ const firstParamToken = (_b = call === null || call === void 0 ? void 0 : call.args[0]) === null || _b === void 0 ? void 0 : _b.token;
191
+ const firstParamStringValue = (_c = firstParamToken === null || firstParamToken === void 0 ? void 0 : firstParamToken.text) === null || _c === void 0 ? void 0 : _c.replace(/"/g, '');
192
+ //if this is a `createObject('roSGNode'` call, only support known sg node types
193
+ if ((firstParamStringValue === null || firstParamStringValue === void 0 ? void 0 : firstParamStringValue.toLowerCase()) === 'rosgnode' && (0, reflection_1.isLiteralExpression)(call === null || call === void 0 ? void 0 : call.args[1])) {
194
+ const componentName = (_d = call === null || call === void 0 ? void 0 : call.args[1]) === null || _d === void 0 ? void 0 : _d.token;
195
+ //don't validate any components with a colon in their name (probably component libraries, but regular components can have them too).
196
+ if ((_e = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _e === void 0 ? void 0 : _e.includes(':')) {
197
+ return;
198
+ }
199
+ //add diagnostic for unknown components
200
+ const unquotedComponentName = (_f = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _f === void 0 ? void 0 : _f.replace(/"/g, '');
201
+ if (unquotedComponentName && !platformNodeNames.has(unquotedComponentName.toLowerCase()) && !this.event.program.getComponent(unquotedComponentName)) {
202
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownRoSGNode(unquotedComponentName)), { range: componentName.range }));
203
+ }
204
+ else if ((call === null || call === void 0 ? void 0 : call.args.length) !== 2) {
205
+ // roSgNode should only ever have 2 args in `createObject`
206
+ 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 }));
207
+ }
208
+ }
209
+ else if (!platformComponentNames.has(firstParamStringValue.toLowerCase())) {
210
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownBrightScriptComponent(firstParamStringValue)), { range: firstParamToken.range }));
211
+ }
212
+ else {
213
+ // This is valid brightscript component
214
+ // Test for invalid arg counts
215
+ const brightScriptComponent = roku_types_1.components[firstParamStringValue.toLowerCase()];
216
+ // Valid arg counts for createObject are 1+ number of args for constructor
217
+ let validArgCounts = brightScriptComponent.constructors.map(cnstr => cnstr.params.length + 1);
218
+ if (validArgCounts.length === 0) {
219
+ // no constructors for this component, so createObject only takes 1 arg
220
+ validArgCounts = [1];
221
+ }
222
+ if (!validArgCounts.includes(call === null || call === void 0 ? void 0 : call.args.length)) {
223
+ // Incorrect number of arguments included in `createObject()`
224
+ 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 }));
225
+ }
226
+ // Test for deprecation
227
+ if (brightScriptComponent.isDeprecated) {
228
+ this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.deprecatedBrightScriptComponent(firstParamStringValue, brightScriptComponent.deprecatedDescription)), { range: call.range }));
229
+ }
230
+ }
231
+ }
232
+ /**
233
+ * Detect calls to functions with the incorrect number of parameters, or wrong types of arguments
234
+ */
235
+ validateFunctionCall(file, expression) {
236
+ var _a, _b;
237
+ const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime, data: {} };
238
+ let funcType = (_a = expression === null || expression === void 0 ? void 0 : expression.callee) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
239
+ if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isClassType)(funcType)) {
240
+ // We're calling a class - get the constructor
241
+ funcType = funcType.getMemberType('new', getTypeOptions);
242
+ }
243
+ if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isTypedFunctionType)(funcType)) {
244
+ //funcType.setName(expression.callee. .name);
245
+ //get min/max parameter count for callable
246
+ let minParams = 0;
247
+ let maxParams = 0;
248
+ for (let param of funcType.params) {
249
+ maxParams++;
250
+ //optional parameters must come last, so we can assume that minParams won't increase once we hit
251
+ //the first isOptional
252
+ if (param.isOptional !== true) {
253
+ minParams++;
270
254
  }
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 }));
255
+ }
256
+ if (funcType.isVariadic) {
257
+ // function accepts variable number of arguments
258
+ maxParams = Expression_1.CallExpression.MaximumArguments;
259
+ }
260
+ let expCallArgCount = expression.args.length;
261
+ if (expCallArgCount > maxParams || expCallArgCount < minParams) {
262
+ let minMaxParamsText = minParams === maxParams ? maxParams : `${minParams}-${maxParams}`;
263
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expression.callee.range,
264
+ //TODO detect end of expression call
265
+ file: file }));
266
+ }
267
+ let paramIndex = 0;
268
+ for (let arg of expression.args) {
269
+ const data = {};
270
+ let argType = arg.getType({ flags: SymbolTable_1.SymbolTypeFlag.runtime, data: data });
271
+ const paramType = (_b = funcType.params[paramIndex]) === null || _b === void 0 ? void 0 : _b.type;
272
+ if (!paramType) {
273
+ // unable to find a paramType -- maybe there are more args than params
274
+ break;
273
275
  }
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 }));
276
+ if ((0, reflection_1.isCallableType)(paramType) && (0, reflection_1.isClassType)(argType) && (0, reflection_1.isClassStatement)(data.definingNode)) {
277
+ // the param is expecting a function, but we're passing a Class... are we actually passing the constructor? then we're ok!
278
+ const namespace = expression.findAncestor(reflection_1.isNamespaceStatement);
279
+ if (file.calleeIsKnownFunction(arg, namespace === null || namespace === void 0 ? void 0 : namespace.getName(Parser_1.ParseMode.BrighterScript))) {
280
+ argType = data.definingNode.getConstructorType();
291
281
  }
292
282
  }
283
+ const compatibilityData = {};
284
+ if (!(paramType === null || paramType === void 0 ? void 0 : paramType.isTypeCompatible(argType, compatibilityData))) {
285
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch(argType.toString(), paramType.toString(), compatibilityData)), { range: arg.range,
286
+ //TODO detect end of expression call
287
+ file: file }));
288
+ }
289
+ paramIndex++;
293
290
  }
294
- });
295
- event.scope.addDiagnostics(diagnostics);
291
+ }
296
292
  }
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);
293
+ /**
294
+ * Detect return statements with incompatible types vs. declared return type
295
+ */
296
+ validateReturnStatement(file, returnStmt) {
297
+ var _a;
298
+ const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
299
+ let funcType = returnStmt.findAncestor(reflection_1.isFunctionExpression).getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
300
+ if ((0, reflection_1.isTypedFunctionType)(funcType)) {
301
+ const actualReturnType = (_a = returnStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
302
+ const compatibilityData = {};
303
+ if (actualReturnType && !funcType.returnType.isTypeCompatible(actualReturnType, compatibilityData)) {
304
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch(actualReturnType.toString(), funcType.returnType.toString(), compatibilityData)), { range: returnStmt.value.range, file: file }));
305
+ }
306
+ }
305
307
  }
306
308
  /**
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
- }
309
+ * Detect return statements with incompatible types vs. declared return type
310
+ */
311
+ validateDottedSetStatement(file, dottedSetStmt) {
312
+ var _a;
313
+ const typeChainExpectedLHS = [];
314
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
315
+ const expectedLHSType = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.getType(Object.assign(Object.assign({}, getTypeOpts), { data: {}, typeChain: typeChainExpectedLHS }));
316
+ const actualRHSType = (_a = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.value) === null || _a === void 0 ? void 0 : _a.getType(getTypeOpts);
317
+ const compatibilityData = {};
318
+ const typeChainScan = util_1.default.processTypeChain(typeChainExpectedLHS);
319
+ if (!(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isResolvable())) {
320
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
321
+ return;
322
+ }
323
+ const accessibilityIsOk = this.checkMemberAccessibility(file, dottedSetStmt, typeChainExpectedLHS);
324
+ if (accessibilityIsOk && !(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
325
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch(actualRHSType.toString(), expectedLHSType.toString(), compatibilityData)), { range: dottedSetStmt.range, file: file }));
326
+ }
327
+ }
328
+ /**
329
+ * Detect invalid use of a binary operator
330
+ */
331
+ validateBinaryExpression(file, binaryExpr) {
332
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
333
+ if (util_1.default.isInTypeExpression(binaryExpr)) {
334
+ return;
335
+ }
336
+ let leftType = binaryExpr.left.getType(getTypeOpts);
337
+ let rightType = binaryExpr.right.getType(getTypeOpts);
338
+ if (!leftType.isResolvable() || !rightType.isResolvable()) {
339
+ // Can not find the type. error handled elsewhere
340
+ return;
341
+ }
342
+ let leftTypeToTest = leftType;
343
+ let rightTypeToTest = rightType;
344
+ if ((0, reflection_1.isEnumMemberType)(leftType) || (0, reflection_1.isEnumType)(leftType)) {
345
+ leftTypeToTest = leftType.underlyingType;
346
+ }
347
+ if ((0, reflection_1.isEnumMemberType)(rightType) || (0, reflection_1.isEnumType)(rightType)) {
348
+ rightTypeToTest = rightType.underlyingType;
349
+ }
350
+ if ((0, reflection_1.isUnionType)(leftType) || (0, reflection_1.isUnionType)(rightType)) {
351
+ // TODO: it is possible to validate based on innerTypes, but more complicated
352
+ // Because you need to verify each combination of types
353
+ return;
354
+ }
355
+ const leftIsPrimitive = (0, reflection_1.isPrimitiveType)(leftTypeToTest);
356
+ const rightIsPrimitive = (0, reflection_1.isPrimitiveType)(rightTypeToTest);
357
+ const leftIsAny = (0, reflection_1.isDynamicType)(leftTypeToTest) || (0, reflection_1.isObjectType)(leftTypeToTest);
358
+ const rightIsAny = (0, reflection_1.isDynamicType)(rightTypeToTest) || (0, reflection_1.isObjectType)(rightTypeToTest);
359
+ if (leftIsAny && rightIsAny) {
360
+ // both operands are basically "any" type... ignore;
361
+ return;
362
+ }
363
+ else if ((leftIsAny && rightIsPrimitive) || (leftIsPrimitive && rightIsAny)) {
364
+ // one operand is basically "any" type... ignore;
365
+ return;
366
+ }
367
+ const opResult = util_1.default.binaryOperatorResultType(leftTypeToTest, binaryExpr.operator, rightTypeToTest);
368
+ if ((0, reflection_1.isDynamicType)(opResult)) {
369
+ // if the result was dynamic, that means there wasn't a valid operation
370
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(binaryExpr.operator.text, leftType.toString(), rightType.toString())), { range: binaryExpr.range, file: file }));
371
+ }
372
+ }
373
+ /**
374
+ * Detect invalid use of a Unary operator
375
+ */
376
+ validateUnaryExpression(file, unaryExpr) {
377
+ const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
378
+ let rightType = unaryExpr.right.getType(getTypeOpts);
379
+ if (!rightType.isResolvable()) {
380
+ // Can not find the type. error handled elsewhere
381
+ return;
382
+ }
383
+ let rightTypeToTest = rightType;
384
+ if ((0, reflection_1.isEnumMemberType)(rightType)) {
385
+ rightTypeToTest = rightType.underlyingType;
386
+ }
387
+ if ((0, reflection_1.isUnionType)(rightTypeToTest)) {
388
+ // TODO: it is possible to validate based on innerTypes, but more complicated
389
+ // Because you need to verify each combination of types
390
+ }
391
+ else if ((0, reflection_1.isDynamicType)(rightTypeToTest) || (0, reflection_1.isObjectType)(rightTypeToTest)) {
392
+ // operand is basically "any" type... ignore;
393
+ }
394
+ else if ((0, reflection_1.isPrimitiveType)(rightType)) {
395
+ const opResult = util_1.default.unaryOperatorResultType(unaryExpr.operator, rightTypeToTest);
396
+ if ((0, reflection_1.isDynamicType)(opResult)) {
397
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(unaryExpr.operator.text, rightType.toString())), { range: unaryExpr.range, file: file }));
398
+ }
399
+ }
400
+ else {
401
+ // rhs is not a primitive, so no binary operator is allowed
402
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(unaryExpr.operator.text, rightType.toString())), { range: unaryExpr.range, file: file }));
403
+ }
404
+ }
405
+ validateVariableAndDottedGetExpressions(file, expression) {
406
+ var _a, _b;
407
+ if ((0, reflection_1.isDottedGetExpression)(expression.parent)) {
408
+ // We validate dottedGetExpressions at the top-most level
409
+ return;
410
+ }
411
+ if ((0, reflection_1.isVariableExpression)(expression)) {
412
+ if ((0, reflection_1.isAssignmentStatement)(expression.parent) && expression.parent.name === expression.name) {
413
+ // Don't validate LHS of assignments
414
+ return;
415
+ }
416
+ else if ((0, reflection_1.isNamespaceStatement)(expression.parent)) {
417
+ return;
418
+ }
419
+ }
420
+ let symbolType = SymbolTable_1.SymbolTypeFlag.runtime;
421
+ let oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.typetime;
422
+ const isUsedAsType = util_1.default.isInTypeExpression(expression);
423
+ if (isUsedAsType) {
424
+ // This is used in a TypeExpression - only look up types from SymbolTable
425
+ symbolType = SymbolTable_1.SymbolTypeFlag.typetime;
426
+ oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.runtime;
427
+ }
428
+ // Do a complete type check on all DottedGet and Variable expressions
429
+ // this will create a diagnostic if an invalid member is accessed
430
+ const typeChain = [];
431
+ const typeData = {};
432
+ let exprType = expression.getType({
433
+ flags: symbolType,
434
+ typeChain: typeChain,
435
+ data: typeData
436
+ });
437
+ const shouldIgnoreLHS = this.ignoreUnresolvedAssignmentLHS(expression, exprType, typeData === null || typeData === void 0 ? void 0 : typeData.definingNode);
438
+ if (!this.isTypeKnown(exprType) && !shouldIgnoreLHS) {
439
+ if ((_a = expression.getType({ flags: oppositeSymbolType })) === null || _a === void 0 ? void 0 : _a.isResolvable()) {
440
+ const oppoSiteTypeChain = [];
441
+ const invalidlyUsedResolvedType = expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain });
442
+ const typeChainScan = util_1.default.processTypeChain(oppoSiteTypeChain);
443
+ if (isUsedAsType) {
444
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsType(typeChainScan.fullChainName)), { range: expression.range, file: file }));
332
445
  }
333
- if ((0, reflection_1.isFunctionType)(funcType)) {
334
- // This is a generic function, and it is callable
446
+ else {
447
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: expression.range, file: file }));
335
448
  }
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);
449
+ }
450
+ else {
451
+ const typeChainScan = util_1.default.processTypeChain(typeChain);
452
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
453
+ }
454
+ }
455
+ if (isUsedAsType) {
456
+ return;
457
+ }
458
+ const lastTypeInfo = typeChain[typeChain.length - 1];
459
+ const parentTypeInfo = typeChain[typeChain.length - 2];
460
+ this.checkMemberAccessibility(file, expression, typeChain);
461
+ if ((0, reflection_1.isNamespaceType)(exprType)) {
462
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: expression.range, file: file }));
463
+ }
464
+ else if ((0, reflection_1.isEnumType)(exprType)) {
465
+ const enumStatement = this.event.scope.getEnum(util_1.default.getAllDottedGetPartsAsString(expression));
466
+ if (enumStatement) {
467
+ // there's an enum with this name
468
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('enum')), { range: expression.range, file: file }));
469
+ }
470
+ }
471
+ 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)) {
472
+ const enumFileLink = this.event.scope.getEnumFileLink(util_1.default.getAllDottedGetPartsAsString(expression.obj));
473
+ const typeChainScanForParent = util_1.default.processTypeChain(typeChain.slice(0, -1));
474
+ if (enumFileLink) {
475
+ 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: [{
476
+ message: 'Enum declared here',
477
+ 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)
478
+ }] }));
479
+ }
480
+ }
481
+ }
482
+ /**
483
+ * Adds diagnostics for accibility mismatches
484
+ *
485
+ * @param file file
486
+ * @param expression containing expression
487
+ * @param typeChain type chain to check
488
+ * @returns true if member accesiibility is okay
489
+ */
490
+ checkMemberAccessibility(file, expression, typeChain) {
491
+ var _a, _b, _c;
492
+ for (let i = 0; i < typeChain.length - 1; i++) {
493
+ const parentChainItem = typeChain[i];
494
+ const childChainItem = typeChain[i + 1];
495
+ if ((0, reflection_1.isClassType)(parentChainItem.type)) {
496
+ const containingClassStmt = expression.findAncestor(reflection_1.isClassStatement);
497
+ 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);
498
+ if (classStmtThatDefinesChildMember) {
499
+ const definingClassName = classStmtThatDefinesChildMember.getName(Parser_1.ParseMode.BrighterScript);
500
+ const inMatchingClassStmt = (containingClassStmt === null || containingClassStmt === void 0 ? void 0 : containingClassStmt.getName(Parser_1.ParseMode.BrighterScript).toLowerCase()) === parentChainItem.type.name.toLowerCase();
501
+ // eslint-disable-next-line no-bitwise
502
+ if (childChainItem.data.flags & SymbolTable_1.SymbolTypeFlag.private) {
503
+ if (!inMatchingClassStmt || childChainItem.data.memberOfAncestor) {
504
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch(childChainItem.name, childChainItem.data.flags, definingClassName)), { range: expression.range, file: file }));
505
+ // there's an error... don't worry about the rest of the chain
506
+ return false;
364
507
  }
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 }));
508
+ }
509
+ // eslint-disable-next-line no-bitwise
510
+ if (childChainItem.data.flags & SymbolTable_1.SymbolTypeFlag.protected) {
511
+ const containingClassName = containingClassStmt === null || containingClassStmt === void 0 ? void 0 : containingClassStmt.getName(Parser_1.ParseMode.BrighterScript);
512
+ const containingNamespaceName = (_c = expression.findAncestor(reflection_1.isNamespaceStatement)) === null || _c === void 0 ? void 0 : _c.getName(Parser_1.ParseMode.BrighterScript);
513
+ const ancestorClasses = this.event.scope.getClassHierarchy(containingClassName, containingNamespaceName).map(link => link.item);
514
+ const isSubClassOfDefiningClass = ancestorClasses.includes(classStmtThatDefinesChildMember);
515
+ if (!isSubClassOfDefiningClass) {
516
+ this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch(childChainItem.name, childChainItem.data.flags, definingClassName)), { range: expression.range, file: file }));
517
+ // there's an error... don't worry about the rest of the chain
518
+ return false;
367
519
  }
368
520
  }
369
521
  }
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
522
  }
380
523
  }
381
- return diagnostics;
524
+ return true;
525
+ }
526
+ /**
527
+ * Adds a diagnostic to the first scope for this key. Prevents duplicate diagnostics
528
+ * for diagnostics where scope isn't important. (i.e. CreateObject validations)
529
+ */
530
+ addDiagnosticOnce(diagnostic) {
531
+ this.onceCache.getOrAdd(`${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
532
+ const diagnosticWithOrigin = Object.assign({}, diagnostic);
533
+ if (!diagnosticWithOrigin.origin) {
534
+ // diagnostic does not have origin.
535
+ // set the origin to the current astSegment
536
+ diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
537
+ diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
538
+ }
539
+ this.event.scope.addDiagnostics([diagnosticWithOrigin]);
540
+ return true;
541
+ });
542
+ }
543
+ addDiagnostic(diagnostic) {
544
+ const diagnosticWithOrigin = Object.assign({}, diagnostic);
545
+ if (!diagnosticWithOrigin.origin) {
546
+ // diagnostic does not have origin.
547
+ // set the origin to the current astSegment
548
+ diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
549
+ diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
550
+ }
551
+ this.event.scope.addDiagnostics([diagnosticWithOrigin]);
382
552
  }
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 }));
553
+ /**
554
+ * Add a diagnostic (to the first scope) that will have `relatedInformation` for each affected scope
555
+ */
556
+ addMultiScopeDiagnostic(diagnostic) {
557
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
558
+ 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)}`, () => {
559
+ if (!diagnostic.relatedInformation) {
560
+ diagnostic.relatedInformation = [];
561
+ }
562
+ const diagnosticWithOrigin = Object.assign({}, diagnostic);
563
+ if (!diagnosticWithOrigin.origin) {
564
+ // diagnostic does not have origin.
565
+ // set the origin to the current astSegment
566
+ diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
567
+ diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
568
+ }
569
+ this.addDiagnostic(diagnosticWithOrigin);
570
+ return diagnosticWithOrigin;
571
+ });
572
+ if ((0, reflection_1.isXmlScope)(this.event.scope) && ((_b = this.event.scope.xmlFile) === null || _b === void 0 ? void 0 : _b.srcPath)) {
573
+ diagnostic.relatedInformation.push({
574
+ 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}'`,
575
+ 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))
576
+ });
577
+ }
578
+ else {
579
+ diagnostic.relatedInformation.push({
580
+ message: `In scope '${this.event.scope.name}'`,
581
+ location: util_1.default.createLocation(vscode_uri_1.URI.file(diagnostic.file.srcPath).toString(), diagnostic.range)
582
+ });
583
+ }
387
584
  }
388
585
  }
389
586
  exports.ScopeValidator = ScopeValidator;