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.
- package/CHANGELOG.md +493 -233
- package/README.md +45 -139
- package/bsconfig.schema.json +41 -0
- package/dist/ActionPipeline.d.ts +10 -0
- package/dist/ActionPipeline.js +40 -0
- package/dist/ActionPipeline.js.map +1 -0
- package/dist/AstValidationSegmenter.d.ts +25 -0
- package/dist/AstValidationSegmenter.js +152 -0
- package/dist/AstValidationSegmenter.js.map +1 -0
- package/dist/BsConfig.d.ts +39 -4
- package/dist/BusyStatusTracker.d.ts +31 -0
- package/dist/BusyStatusTracker.js +83 -0
- package/dist/BusyStatusTracker.js.map +1 -0
- package/dist/Cache.js +3 -3
- package/dist/Cache.js.map +1 -1
- package/dist/CacheVerifier.d.ts +7 -0
- package/dist/CacheVerifier.js +20 -0
- package/dist/CacheVerifier.js.map +1 -0
- package/dist/CodeActionUtil.d.ts +3 -3
- package/dist/CodeActionUtil.js.map +1 -1
- package/dist/CommentFlagProcessor.d.ts +3 -2
- package/dist/CommentFlagProcessor.js +5 -4
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/DependencyGraph.d.ts +3 -2
- package/dist/DependencyGraph.js +11 -10
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticCollection.js +9 -5
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.d.ts +1 -0
- package/dist/DiagnosticFilterer.js +5 -3
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +61 -13
- package/dist/DiagnosticMessages.js +116 -19
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
- package/dist/DiagnosticSeverityAdjuster.js +41 -0
- package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
- package/dist/FunctionScope.d.ts +28 -0
- package/dist/FunctionScope.js +52 -0
- package/dist/FunctionScope.js.map +1 -0
- package/dist/KeyedThrottler.d.ts +3 -3
- package/dist/KeyedThrottler.js +3 -3
- package/dist/KeyedThrottler.js.map +1 -1
- package/dist/LanguageServer.d.ts +23 -11
- package/dist/LanguageServer.js +150 -69
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +3 -2
- package/dist/Logger.js +11 -3
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +21 -3
- package/dist/PluginInterface.js +74 -6
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +158 -79
- package/dist/Program.js +831 -695
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +22 -12
- package/dist/ProgramBuilder.js +130 -103
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +87 -133
- package/dist/Scope.js +450 -510
- package/dist/Scope.js.map +1 -1
- package/dist/Stopwatch.js +1 -1
- package/dist/Stopwatch.js.map +1 -1
- package/dist/SymbolTable.d.ts +89 -34
- package/dist/SymbolTable.js +239 -114
- package/dist/SymbolTable.js.map +1 -1
- package/dist/Throttler.d.ts +12 -0
- package/dist/Throttler.js +39 -0
- package/dist/Throttler.js.map +1 -1
- package/dist/Watcher.d.ts +0 -3
- package/dist/Watcher.js +0 -3
- package/dist/Watcher.js.map +1 -1
- package/dist/XmlScope.d.ts +4 -6
- package/dist/XmlScope.js +74 -69
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/CachedLookups.d.ts +48 -0
- package/dist/astUtils/CachedLookups.js +323 -0
- package/dist/astUtils/CachedLookups.js.map +1 -0
- package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
- package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
- package/dist/astUtils/Editor.js.map +1 -0
- package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +68 -64
- package/dist/astUtils/Editor.spec.js.map +1 -0
- package/dist/astUtils/creators.d.ts +10 -10
- package/dist/astUtils/creators.js +26 -16
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/creators.spec.js +5 -5
- package/dist/astUtils/creators.spec.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +132 -104
- package/dist/astUtils/reflection.js +220 -174
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +208 -126
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/stackedVisitor.spec.js +12 -12
- package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +53 -35
- package/dist/astUtils/visitors.js +29 -3
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +178 -33
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/astUtils/xml.d.ts +9 -9
- package/dist/astUtils/xml.js +9 -9
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +10 -2
- package/dist/bscPlugin/BscPlugin.js +33 -3
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
- package/dist/bscPlugin/CallExpressionInfo.js +131 -0
- package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
- package/dist/bscPlugin/FileWriter.d.ts +6 -0
- package/dist/bscPlugin/FileWriter.js +24 -0
- package/dist/bscPlugin/FileWriter.js.map +1 -0
- package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
- package/dist/bscPlugin/SignatureHelpUtil.js +135 -0
- package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +14 -11
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
- package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
- package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
- package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +85 -23
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
- package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
- package/dist/bscPlugin/serialize/BslibManager.js +40 -0
- package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
- package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
- package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
- package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
- package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
- package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +33 -9
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
- package/dist/bscPlugin/validation/BrsFileValidator.js +259 -49
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
- package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
- package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
- package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +54 -27
- package/dist/bscPlugin/validation/ScopeValidator.js +483 -286
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
- package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
- package/dist/cli.js +104 -13
- package/dist/cli.js.map +1 -1
- package/dist/deferred.d.ts +3 -3
- package/dist/deferred.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +8 -2
- package/dist/diagnosticUtils.js +47 -17
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +8 -10
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/AssetFile.d.ts +26 -0
- package/dist/files/AssetFile.js +26 -0
- package/dist/files/AssetFile.js.map +1 -0
- package/dist/files/BrsFile.Class.spec.js +523 -493
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +112 -111
- package/dist/files/BrsFile.js +741 -1032
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +1728 -1232
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/BscFile.d.ts +104 -0
- package/dist/files/BscFile.js +16 -0
- package/dist/files/BscFile.js.map +1 -0
- package/dist/files/Factory.d.ts +25 -0
- package/dist/files/Factory.js +22 -0
- package/dist/files/Factory.js.map +1 -0
- package/dist/files/LazyFileData.d.ts +20 -0
- package/dist/files/LazyFileData.js +54 -0
- package/dist/files/LazyFileData.js.map +1 -0
- package/dist/files/LazyFileData.spec.d.ts +1 -0
- package/dist/files/LazyFileData.spec.js +27 -0
- package/dist/files/LazyFileData.spec.js.map +1 -0
- package/dist/files/XmlFile.d.ts +70 -32
- package/dist/files/XmlFile.js +106 -118
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +325 -262
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +48 -40
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.js +84 -24
- package/dist/files/tests/optionalChaning.spec.js.map +1 -1
- package/dist/globalCallables.js +16 -21
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +389 -161
- package/dist/interfaces.js +27 -0
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Character.spec.js +5 -5
- package/dist/lexer/Character.spec.js.map +1 -1
- package/dist/lexer/Lexer.d.ts +12 -5
- package/dist/lexer/Lexer.js +28 -13
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +181 -135
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/Token.d.ts +9 -1
- package/dist/lexer/Token.js +9 -1
- package/dist/lexer/Token.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +8 -0
- package/dist/lexer/TokenKind.js +24 -4
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/AstNode.d.ts +162 -0
- package/dist/parser/AstNode.js +225 -0
- package/dist/parser/AstNode.js.map +1 -0
- package/dist/parser/AstNode.spec.d.ts +1 -0
- package/dist/parser/AstNode.spec.js +165 -0
- package/dist/parser/AstNode.spec.js.map +1 -0
- package/dist/parser/BrsTranspileState.d.ts +4 -7
- package/dist/parser/BrsTranspileState.js +4 -12
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +126 -176
- package/dist/parser/Expression.js +523 -405
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +151 -145
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +43 -201
- package/dist/parser/Parser.js +446 -962
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.d.ts +3 -1
- package/dist/parser/Parser.spec.js +1002 -846
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +9 -8
- package/dist/parser/SGParser.js +10 -8
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +27 -38
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +98 -35
- package/dist/parser/SGTypes.js +169 -99
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/Statement.d.ts +183 -131
- package/dist/parser/Statement.js +549 -387
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +45 -21
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +1 -1
- package/dist/parser/TranspileState.js +7 -12
- package/dist/parser/TranspileState.js.map +1 -1
- package/dist/parser/tests/Parser.spec.js +3 -2
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +33 -23
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +96 -94
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +22 -16
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +8 -8
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +8 -8
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +129 -21
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +5 -5
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +36 -36
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +67 -22
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +12 -12
- package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/Relational.spec.js +13 -13
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
- package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Continue.spec.js +119 -0
- package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
- package/dist/parser/tests/statement/Declaration.spec.js +19 -19
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/Dim.spec.js +22 -22
- package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.js +98 -302
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
- package/dist/parser/tests/statement/For.spec.js +9 -10
- package/dist/parser/tests/statement/For.spec.js.map +1 -1
- package/dist/parser/tests/statement/ForEach.spec.js +8 -9
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/statement/Function.spec.js +44 -35
- package/dist/parser/tests/statement/Function.spec.js.map +1 -1
- package/dist/parser/tests/statement/Goto.spec.js +5 -5
- package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
- package/dist/parser/tests/statement/Increment.spec.js +20 -20
- package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +16 -78
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +35 -33
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Set.spec.js +48 -35
- package/dist/parser/tests/statement/Set.spec.js.map +1 -1
- package/dist/parser/tests/statement/Stop.spec.js +6 -6
- package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
- package/dist/parser/tests/statement/Throw.spec.js +6 -6
- package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
- package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
- package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
- package/dist/preprocessor/Manifest.d.ts +1 -1
- package/dist/preprocessor/Manifest.js +2 -2
- package/dist/preprocessor/Manifest.js.map +1 -1
- package/dist/preprocessor/Manifest.spec.js +8 -8
- package/dist/preprocessor/Manifest.spec.js.map +1 -1
- package/dist/preprocessor/Preprocessor.d.ts +5 -6
- package/dist/preprocessor/Preprocessor.js +5 -5
- package/dist/preprocessor/Preprocessor.js.map +1 -1
- package/dist/preprocessor/Preprocessor.spec.js +25 -25
- package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
- package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
- package/dist/preprocessor/PreprocessorParser.js +7 -1
- package/dist/preprocessor/PreprocessorParser.js.map +1 -1
- package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
- package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
- package/dist/roku-types/data.json +5892 -10081
- package/dist/roku-types/index.d.ts +622 -1719
- package/dist/types/ArrayType.d.ts +10 -9
- package/dist/types/ArrayType.js +65 -60
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +36 -68
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +11 -0
- package/dist/types/AssociativeArrayType.js +52 -0
- package/dist/types/AssociativeArrayType.js.map +1 -0
- package/dist/types/BaseFunctionType.d.ts +9 -0
- package/dist/types/BaseFunctionType.js +25 -0
- package/dist/types/BaseFunctionType.js.map +1 -0
- package/dist/types/BooleanType.d.ts +8 -5
- package/dist/types/BooleanType.js +14 -7
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BooleanType.spec.js +10 -6
- package/dist/types/BooleanType.spec.js.map +1 -1
- package/dist/types/BscType.d.ts +32 -21
- package/dist/types/BscType.js +118 -21
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BscTypeKind.d.ts +25 -0
- package/dist/types/BscTypeKind.js +30 -0
- package/dist/types/BscTypeKind.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
- package/dist/types/BuiltInInterfaceAdder.js +164 -0
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
- package/dist/types/ClassType.d.ts +17 -0
- package/dist/types/ClassType.js +58 -0
- package/dist/types/ClassType.js.map +1 -0
- package/dist/types/ClassType.spec.d.ts +1 -0
- package/dist/types/ClassType.spec.js +77 -0
- package/dist/types/ClassType.spec.js.map +1 -0
- package/dist/types/ComponentType.d.ts +26 -0
- package/dist/types/ComponentType.js +83 -0
- package/dist/types/ComponentType.js.map +1 -0
- package/dist/types/DoubleType.d.ts +8 -5
- package/dist/types/DoubleType.js +18 -16
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DoubleType.spec.js +12 -6
- package/dist/types/DoubleType.spec.js.map +1 -1
- package/dist/types/DynamicType.d.ts +9 -5
- package/dist/types/DynamicType.js +15 -4
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/DynamicType.spec.js +16 -5
- package/dist/types/DynamicType.spec.js.map +1 -1
- package/dist/types/EnumType.d.ts +30 -12
- package/dist/types/EnumType.js +43 -17
- package/dist/types/EnumType.js.map +1 -1
- package/dist/types/EnumType.spec.d.ts +1 -0
- package/dist/types/EnumType.spec.js +33 -0
- package/dist/types/EnumType.spec.js.map +1 -0
- package/dist/types/FloatType.d.ts +8 -5
- package/dist/types/FloatType.js +18 -16
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FloatType.spec.js +4 -6
- package/dist/types/FloatType.spec.js.map +1 -1
- package/dist/types/FunctionType.d.ts +13 -8
- package/dist/types/FunctionType.js +30 -14
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/InheritableType.d.ts +28 -0
- package/dist/types/InheritableType.js +152 -0
- package/dist/types/InheritableType.js.map +1 -0
- package/dist/types/IntegerType.d.ts +8 -5
- package/dist/types/IntegerType.js +18 -16
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/IntegerType.spec.js +8 -6
- package/dist/types/IntegerType.spec.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +12 -13
- package/dist/types/InterfaceType.js +20 -48
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.js +90 -56
- package/dist/types/InterfaceType.spec.js.map +1 -1
- package/dist/types/InvalidType.d.ts +7 -5
- package/dist/types/InvalidType.js +13 -7
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/InvalidType.spec.js +8 -6
- package/dist/types/InvalidType.spec.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +8 -5
- package/dist/types/LongIntegerType.js +17 -15
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/LongIntegerType.spec.js +10 -6
- package/dist/types/LongIntegerType.spec.js.map +1 -1
- package/dist/types/NamespaceType.d.ts +12 -0
- package/dist/types/NamespaceType.js +28 -0
- package/dist/types/NamespaceType.js.map +1 -0
- package/dist/types/ObjectType.d.ts +9 -8
- package/dist/types/ObjectType.js +21 -11
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/ObjectType.spec.js +3 -3
- package/dist/types/ObjectType.spec.js.map +1 -1
- package/dist/types/ReferenceType.d.ts +63 -0
- package/dist/types/ReferenceType.js +423 -0
- package/dist/types/ReferenceType.js.map +1 -0
- package/dist/types/ReferenceType.spec.d.ts +1 -0
- package/dist/types/ReferenceType.spec.js +137 -0
- package/dist/types/ReferenceType.spec.js.map +1 -0
- package/dist/types/StringType.d.ts +11 -5
- package/dist/types/StringType.js +18 -7
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/StringType.spec.js +3 -5
- package/dist/types/StringType.spec.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +22 -17
- package/dist/types/TypedFunctionType.js +78 -60
- package/dist/types/TypedFunctionType.js.map +1 -1
- package/dist/types/TypedFunctionType.spec.js +105 -20
- package/dist/types/TypedFunctionType.spec.js.map +1 -1
- package/dist/types/UninitializedType.d.ts +8 -6
- package/dist/types/UninitializedType.js +13 -7
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/UnionType.d.ts +20 -0
- package/dist/types/UnionType.js +123 -0
- package/dist/types/UnionType.js.map +1 -0
- package/dist/types/UnionType.spec.d.ts +1 -0
- package/dist/types/UnionType.spec.js +130 -0
- package/dist/types/UnionType.spec.js.map +1 -0
- package/dist/types/VoidType.d.ts +8 -5
- package/dist/types/VoidType.js +14 -7
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/VoidType.spec.js +3 -3
- package/dist/types/VoidType.spec.js.map +1 -1
- package/dist/types/helper.spec.d.ts +1 -0
- package/dist/types/helper.spec.js +145 -0
- package/dist/types/helper.spec.js.map +1 -0
- package/dist/types/helpers.d.ts +19 -37
- package/dist/types/helpers.js +159 -99
- package/dist/types/helpers.js.map +1 -1
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.js +39 -0
- package/dist/types/index.js.map +1 -0
- package/dist/util.d.ts +132 -137
- package/dist/util.js +796 -362
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +8 -25
- package/dist/validators/ClassValidator.js +96 -176
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +165 -152
- package/dist/astUtils/AstEditor.js.map +0 -1
- package/dist/astUtils/AstEditor.spec.js.map +0 -1
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
- package/dist/parser/SGTypes.spec.js +0 -351
- package/dist/parser/SGTypes.spec.js.map +0 -1
- package/dist/types/CustomType.d.ts +0 -12
- package/dist/types/CustomType.js +0 -44
- package/dist/types/CustomType.js.map +0 -1
- package/dist/types/LazyType.d.ts +0 -16
- package/dist/types/LazyType.js +0 -44
- package/dist/types/LazyType.js.map +0 -1
- /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
- /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
- /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
|
|
11
|
-
const
|
|
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
|
-
|
|
16
|
-
const
|
|
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.
|
|
30
|
-
event.scope
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
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
|
-
|
|
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
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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(
|
|
135
|
+
detectDuplicateEnums() {
|
|
197
136
|
const diagnostics = [];
|
|
198
137
|
const enumLocationsByName = new Cache_1.Cache();
|
|
199
|
-
event.scope.enumerateBrsFiles((file) => {
|
|
200
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
272
|
-
|
|
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
|
-
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
});
|
|
304
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
var _a
|
|
311
|
-
const
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
-
|
|
334
|
-
|
|
446
|
+
else {
|
|
447
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: expression.range, file: file }));
|
|
335
448
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
366
|
-
|
|
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
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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;
|