brighterscript 0.66.0-alpha.6 → 0.66.0-alpha.8
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 +88 -10
- package/README.md +16 -0
- package/bsconfig.schema.json +15 -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 +150 -0
- package/dist/AstValidationSegmenter.js.map +1 -0
- package/dist/BsConfig.d.ts +15 -1
- package/dist/CommentFlagProcessor.d.ts +4 -3
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +8 -1
- package/dist/DiagnosticMessages.js +30 -13
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.js +7 -1
- package/dist/LanguageServer.js.map +1 -1
- package/dist/PluginInterface.d.ts +11 -2
- package/dist/PluginInterface.js +69 -10
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +107 -38
- package/dist/Program.js +502 -270
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +10 -4
- package/dist/ProgramBuilder.js +44 -54
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +26 -38
- package/dist/Scope.js +153 -174
- package/dist/Scope.js.map +1 -1
- package/dist/SymbolTable.d.ts +4 -1
- package/dist/SymbolTable.js +19 -7
- package/dist/SymbolTable.js.map +1 -1
- package/dist/XmlScope.d.ts +5 -4
- package/dist/XmlScope.js +16 -14
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +6 -1
- package/dist/astUtils/{AstEditor.js → Editor.js} +9 -3
- package/dist/astUtils/Editor.js.map +1 -0
- package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +10 -6
- package/dist/astUtils/Editor.spec.js.map +1 -0
- package/dist/astUtils/reflection.d.ts +9 -4
- package/dist/astUtils/reflection.js +23 -7
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +2 -2
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +14 -3
- package/dist/astUtils/visitors.js +22 -2
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +58 -7
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +10 -2
- package/dist/bscPlugin/BscPlugin.js +24 -4
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- 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/codeActions/CodeActionsProcessor.js +8 -8
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +7 -2
- package/dist/bscPlugin/completions/CompletionsProcessor.js +112 -44
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +212 -6
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
- 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 +1 -7
- package/dist/bscPlugin/hover/HoverProcessor.js +10 -8
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +43 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +22 -0
- 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} +29 -5
- 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 +2 -2
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.js +8 -3
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +5 -9
- package/dist/bscPlugin/validation/ScopeValidator.js +214 -222
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +669 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
- package/dist/bscPlugin/validation/XmlFileValidator.js +2 -2
- package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/deferred.d.ts +2 -2
- package/dist/deferred.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +1 -0
- package/dist/diagnosticUtils.js +4 -3
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +1 -1
- 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 +241 -40
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +66 -16
- package/dist/files/BrsFile.js +330 -80
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +1134 -167
- package/dist/files/BrsFile.spec.js.map +1 -1
- 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/File.d.ts +106 -0
- package/dist/files/File.js +16 -0
- package/dist/files/File.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 +55 -17
- package/dist/files/XmlFile.js +88 -47
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +64 -57
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +21 -8
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.js +14 -14
- package/dist/files/tests/optionalChaning.spec.js.map +1 -1
- package/dist/globalCallables.js +1 -1
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +357 -89
- package/dist/interfaces.js +10 -2
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Lexer.js +1 -1
- package/dist/lexer/TokenKind.d.ts +1 -0
- package/dist/lexer/TokenKind.js +4 -1
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/AstNode.d.ts +2 -2
- package/dist/parser/AstNode.js +1 -1
- package/dist/parser/AstNode.js.map +1 -1
- package/dist/parser/BrsTranspileState.d.ts +3 -2
- package/dist/parser/BrsTranspileState.js +3 -2
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +2 -2
- package/dist/parser/Expression.js +23 -19
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +103 -0
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.js +61 -13
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +227 -1
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +2 -2
- package/dist/parser/SGParser.js +3 -3
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +2 -2
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +1 -1
- package/dist/parser/Statement.d.ts +12 -5
- package/dist/parser/Statement.js +56 -26
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +16 -16
- package/dist/parser/tests/expression/NullCoalescenceExpression.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/SourceLiteralExpression.spec.js +24 -24
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +64 -36
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +34 -34
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- 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/ConstStatement.spec.js +90 -16
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Continue.spec.js +2 -2
- package/dist/parser/tests/statement/Continue.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.js +35 -26
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
- package/dist/parser/tests/statement/For.spec.js +6 -6
- package/dist/parser/tests/statement/For.spec.js.map +1 -1
- package/dist/parser/tests/statement/ForEach.spec.js +4 -4
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +20 -12
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +10 -10
- package/dist/parser/tests/statement/PrintStatement.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/roku-types/data.json +98 -193
- package/dist/roku-types/index.d.ts +15 -11
- package/dist/types/ArrayType.d.ts +1 -1
- package/dist/types/ArrayType.js +4 -0
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +1 -1
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +1 -1
- package/dist/types/AssociativeArrayType.js +1 -1
- package/dist/types/AssociativeArrayType.js.map +1 -1
- package/dist/types/BooleanType.d.ts +1 -1
- package/dist/types/BooleanType.js +2 -1
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BscType.d.ts +2 -2
- package/dist/types/BscType.js +30 -9
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BuiltInInterfaceAdder.d.ts +3 -0
- package/dist/types/BuiltInInterfaceAdder.js +37 -16
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
- package/dist/types/BuiltInInterfaceAdder.spec.js +7 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -1
- package/dist/types/ClassType.d.ts +4 -3
- package/dist/types/ClassType.js +6 -3
- package/dist/types/ClassType.js.map +1 -1
- package/dist/types/ClassType.spec.js +5 -3
- package/dist/types/ClassType.spec.js.map +1 -1
- package/dist/types/ComponentType.d.ts +1 -1
- package/dist/types/ComponentType.js +3 -0
- package/dist/types/ComponentType.js.map +1 -1
- package/dist/types/DoubleType.js +3 -1
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/EnumType.d.ts +1 -1
- package/dist/types/EnumType.js +7 -2
- package/dist/types/EnumType.js.map +1 -1
- package/dist/types/FloatType.js +3 -1
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/InheritableType.d.ts +7 -4
- package/dist/types/InheritableType.js +67 -3
- package/dist/types/InheritableType.js.map +1 -1
- package/dist/types/IntegerType.js +3 -1
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +5 -4
- package/dist/types/InterfaceType.js +5 -12
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.js +23 -0
- package/dist/types/InterfaceType.spec.js.map +1 -1
- package/dist/types/LongIntegerType.js +3 -1
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/NamespaceType.d.ts +2 -1
- package/dist/types/NamespaceType.js +3 -0
- package/dist/types/NamespaceType.js.map +1 -1
- package/dist/types/ObjectType.d.ts +1 -1
- package/dist/types/ReferenceType.js +40 -6
- package/dist/types/ReferenceType.js.map +1 -1
- package/dist/types/StringType.js +2 -2
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +6 -1
- package/dist/types/TypedFunctionType.js +46 -16
- package/dist/types/TypedFunctionType.js.map +1 -1
- package/dist/types/TypedFunctionType.spec.js +99 -0
- package/dist/types/TypedFunctionType.spec.js.map +1 -1
- package/dist/types/UnionType.js +8 -0
- package/dist/types/UnionType.js.map +1 -1
- package/dist/types/helper.spec.js +15 -0
- package/dist/types/helper.spec.js.map +1 -1
- package/dist/types/helpers.d.ts +3 -0
- package/dist/types/helpers.js +33 -1
- package/dist/types/helpers.js.map +1 -1
- package/dist/util.d.ts +25 -9
- package/dist/util.js +165 -72
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +2 -2
- 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 -31
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.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 → serialize/BslibInjector.spec.d.ts} +0 -0
|
@@ -5,12 +5,14 @@ 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");
|
|
8
9
|
const SymbolTable_1 = require("../../SymbolTable");
|
|
9
10
|
const util_1 = require("../../util");
|
|
10
11
|
const roku_types_1 = require("../../roku-types");
|
|
11
|
-
const
|
|
12
|
-
const TokenKind_1 = require("../../lexer/TokenKind");
|
|
12
|
+
const Expression_1 = require("../../parser/Expression");
|
|
13
13
|
const visitors_1 = require("../../astUtils/visitors");
|
|
14
|
+
const AstValidationSegmenter_1 = require("../../AstValidationSegmenter");
|
|
15
|
+
const TokenKind_1 = require("../../lexer/TokenKind");
|
|
14
16
|
/**
|
|
15
17
|
* The lower-case names of all platform-included scenegraph nodes
|
|
16
18
|
*/
|
|
@@ -24,12 +26,14 @@ const platformComponentNames = roku_types_1.components ? new Set(Object.values(r
|
|
|
24
26
|
*/
|
|
25
27
|
class ScopeValidator {
|
|
26
28
|
constructor() {
|
|
27
|
-
this.expressionsByFile = new Cache_1.Cache();
|
|
28
29
|
this.onceCache = new Cache_1.Cache();
|
|
29
30
|
this.multiScopeCache = new Cache_1.Cache();
|
|
30
31
|
}
|
|
31
32
|
processEvent(event) {
|
|
32
33
|
this.event = event;
|
|
34
|
+
if (this.event.program.globalScope === this.event.scope) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
33
37
|
this.walkFiles();
|
|
34
38
|
this.detectDuplicateEnums();
|
|
35
39
|
}
|
|
@@ -41,11 +45,32 @@ class ScopeValidator {
|
|
|
41
45
|
walkFiles() {
|
|
42
46
|
this.event.scope.enumerateOwnFiles((file) => {
|
|
43
47
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
const hasChangeInfo = this.event.changedFiles && this.event.changedSymbols;
|
|
49
|
+
let thisFileRequiresChangedSymbol = false;
|
|
50
|
+
for (let requiredSymbol of file.requiredSymbols) {
|
|
51
|
+
const changeSymbolSetForFlag = this.event.changedSymbols.get(requiredSymbol.flags);
|
|
52
|
+
if (util_1.default.setContainsUnresolvedSymbol(changeSymbolSetForFlag, requiredSymbol)) {
|
|
53
|
+
thisFileRequiresChangedSymbol = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const thisFileHasChanges = this.event.changedFiles.includes(file);
|
|
57
|
+
if (hasChangeInfo && !thisFileRequiresChangedSymbol && !thisFileHasChanges) {
|
|
58
|
+
// this file does not require a symbol that has changed, and this file has not changed
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (thisFileHasChanges) {
|
|
62
|
+
this.event.scope.clearAstSegmentDiagnosticsByFile(file);
|
|
63
|
+
}
|
|
64
|
+
const validationVisitor = (0, visitors_1.createVisitor)({
|
|
65
|
+
VariableExpression: (varExpr) => {
|
|
66
|
+
this.validateVariableAndDottedGetExpressions(file, varExpr);
|
|
67
|
+
},
|
|
68
|
+
DottedGetExpression: (dottedGet) => {
|
|
69
|
+
this.validateVariableAndDottedGetExpressions(file, dottedGet);
|
|
70
|
+
},
|
|
47
71
|
CallExpression: (functionCall) => {
|
|
48
72
|
this.validateFunctionCall(file, functionCall);
|
|
73
|
+
this.validateCreateObjectCall(file, functionCall);
|
|
49
74
|
},
|
|
50
75
|
ReturnStatement: (returnStatement) => {
|
|
51
76
|
this.validateReturnStatement(file, returnStatement);
|
|
@@ -59,27 +84,21 @@ class ScopeValidator {
|
|
|
59
84
|
UnaryExpression: (unaryExpr) => {
|
|
60
85
|
this.validateUnaryExpression(file, unaryExpr);
|
|
61
86
|
}
|
|
62
|
-
}), {
|
|
63
|
-
walkMode: visitors_1.WalkMode.visitAllRecursive
|
|
64
87
|
});
|
|
88
|
+
const segmentsToWalkForValidation = (thisFileHasChanges || !hasChangeInfo)
|
|
89
|
+
? file.validationSegmenter.segmentsForValidation // validate everything in the file
|
|
90
|
+
: file.getValidationSegments(this.event.changedSymbols); // validate only what's needed in the file
|
|
91
|
+
for (const segment of segmentsToWalkForValidation) {
|
|
92
|
+
this.currentSegmentBeingValidated = segment;
|
|
93
|
+
this.event.scope.clearAstSegmentDiagnostics(segment);
|
|
94
|
+
segment.walk(validationVisitor, {
|
|
95
|
+
walkMode: AstValidationSegmenter_1.InsideSegmentWalkMode
|
|
96
|
+
});
|
|
97
|
+
file.markSegmentAsValidated(segment);
|
|
98
|
+
}
|
|
65
99
|
}
|
|
66
100
|
});
|
|
67
101
|
}
|
|
68
|
-
checkIfUsedAsTypeExpression(expression) {
|
|
69
|
-
//TODO: this is much faster than node.findAncestor(), but will not work for "complicated" type expressions like UnionTypes
|
|
70
|
-
if ((0, reflection_1.isTypeExpression)(expression) ||
|
|
71
|
-
(0, reflection_1.isTypeExpression)(expression.parent)) {
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
if ((0, reflection_1.isBinaryExpression)(expression.parent)) {
|
|
75
|
-
let currentExpr = expression.parent;
|
|
76
|
-
while ((0, reflection_1.isBinaryExpression)(currentExpr) && currentExpr.operator.kind === TokenKind_1.TokenKind.Or) {
|
|
77
|
-
currentExpr = currentExpr.parent;
|
|
78
|
-
}
|
|
79
|
-
return (0, reflection_1.isTypeExpression)(currentExpr);
|
|
80
|
-
}
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
102
|
isTypeKnown(exprType) {
|
|
84
103
|
let isKnownType = exprType === null || exprType === void 0 ? void 0 : exprType.isResolvable();
|
|
85
104
|
return isKnownType;
|
|
@@ -87,136 +106,21 @@ class ScopeValidator {
|
|
|
87
106
|
/**
|
|
88
107
|
* If this is the lhs of an assignment, we don't need to flag it as unresolved
|
|
89
108
|
*/
|
|
90
|
-
ignoreUnresolvedAssignmentLHS(expression, exprType) {
|
|
109
|
+
ignoreUnresolvedAssignmentLHS(expression, exprType, definingNode) {
|
|
110
|
+
var _a, _b;
|
|
91
111
|
if (!(0, reflection_1.isVariableExpression)(expression)) {
|
|
92
112
|
return false;
|
|
93
113
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const { scope } = this.event;
|
|
100
|
-
//build an expression collection ONCE per file
|
|
101
|
-
const expressionInfos = this.expressionsByFile.getOrAdd(file, () => {
|
|
102
|
-
var _a, _b;
|
|
103
|
-
const result = [];
|
|
104
|
-
const expressions = [...file.parser.references.expressions];
|
|
105
|
-
for (let expression of expressions) {
|
|
106
|
-
if (!expression) {
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
//walk left-to-right on every expression, only keep the ones that start with VariableExpression, and then keep subsequent DottedGet parts
|
|
110
|
-
const parts = util_1.default.getDottedGetPath(expression);
|
|
111
|
-
if (parts.length > 0) {
|
|
112
|
-
result.push({
|
|
113
|
-
parts: parts,
|
|
114
|
-
expression: expression,
|
|
115
|
-
isUsedAsType: this.checkIfUsedAsTypeExpression(expression),
|
|
116
|
-
enclosingNamespaceNameLower: (_b = (_a = expression.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript)) === null || _b === void 0 ? void 0 : _b.toLowerCase()
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return result;
|
|
121
|
-
});
|
|
122
|
-
outer: for (const info of expressionInfos) {
|
|
123
|
-
const firstNamespacePart = info.parts[0].name.text;
|
|
124
|
-
const firstNamespacePartLower = firstNamespacePart === null || firstNamespacePart === void 0 ? void 0 : firstNamespacePart.toLowerCase();
|
|
125
|
-
//get the namespace container (accounting for namespace-relative as well)
|
|
126
|
-
const namespaceContainer = scope.getNamespace(firstNamespacePartLower, info.enclosingNamespaceNameLower);
|
|
127
|
-
let symbolType = SymbolTable_1.SymbolTypeFlag.runtime;
|
|
128
|
-
let oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.typetime;
|
|
129
|
-
if (info.isUsedAsType) {
|
|
130
|
-
// This is used in a TypeExpression - only look up types from SymbolTable
|
|
131
|
-
symbolType = SymbolTable_1.SymbolTypeFlag.typetime;
|
|
132
|
-
oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.runtime;
|
|
133
|
-
}
|
|
134
|
-
// Do a complete type check on all DottedGet and Variable expressions
|
|
135
|
-
// this will create a diagnostic if an invalid member is accessed
|
|
136
|
-
const typeChain = [];
|
|
137
|
-
let exprType = info.expression.getType({
|
|
138
|
-
flags: symbolType,
|
|
139
|
-
typeChain: typeChain
|
|
140
|
-
});
|
|
141
|
-
if (!this.isTypeKnown(exprType) && !this.ignoreUnresolvedAssignmentLHS(info.expression, exprType)) {
|
|
142
|
-
if ((_a = info.expression.getType({ flags: oppositeSymbolType })) === null || _a === void 0 ? void 0 : _a.isResolvable()) {
|
|
143
|
-
const oppoSiteTypeChain = [];
|
|
144
|
-
const invalidlyUsedResolvedType = info.expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain });
|
|
145
|
-
const typeChainScan = util_1.default.processTypeChain(oppoSiteTypeChain);
|
|
146
|
-
if (info.isUsedAsType) {
|
|
147
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsType(typeChainScan.fullChainName)), { range: info.expression.range, file: file }), 'When used in scope');
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: info.expression.range, file: file }), 'When used in scope');
|
|
151
|
-
}
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
const typeChainScan = util_1.default.processTypeChain(typeChain);
|
|
155
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
|
|
156
|
-
//skip to the next expression
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
const enumStatement = scope.getEnum(firstNamespacePartLower, info.enclosingNamespaceNameLower);
|
|
160
|
-
//if this isn't a namespace, skip it
|
|
161
|
-
if (!namespaceContainer && !enumStatement) {
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
//catch unknown namespace items
|
|
165
|
-
let entityName = firstNamespacePart;
|
|
166
|
-
let entityNameLower = firstNamespacePart.toLowerCase();
|
|
167
|
-
for (let i = 1; i < info.parts.length; i++) {
|
|
168
|
-
const part = info.parts[i];
|
|
169
|
-
entityName += '.' + part.name.text;
|
|
170
|
-
entityNameLower += '.' + part.name.text.toLowerCase();
|
|
171
|
-
//if this is an enum member, stop validating here to prevent errors further down the chain
|
|
172
|
-
if (scope.getEnumMemberFileLink(entityName, info.enclosingNamespaceNameLower)) {
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
if (!scope.getEnumMap().has(entityNameLower) &&
|
|
176
|
-
!scope.getClassMap().has(entityNameLower) &&
|
|
177
|
-
!scope.getInterfaceMap().has(entityNameLower) &&
|
|
178
|
-
!scope.getConstMap().has(entityNameLower) &&
|
|
179
|
-
!scope.getCallableByName(entityNameLower) &&
|
|
180
|
-
!scope.getNamespace(entityNameLower, info.enclosingNamespaceNameLower)) {
|
|
181
|
-
//if this looks like an enum, provide a nicer error message
|
|
182
|
-
const theEnum = (_b = this.getEnum(scope, entityNameLower)) === null || _b === void 0 ? void 0 : _b.item;
|
|
183
|
-
if (theEnum) {
|
|
184
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownEnumValue((_c = part.name.text) === null || _c === void 0 ? void 0 : _c.split('.').pop(), theEnum.fullName)), { range: part.name.range, relatedInformation: [{
|
|
185
|
-
message: 'Enum declared here',
|
|
186
|
-
location: util_1.default.createLocation(vscode_uri_1.URI.file(file.srcPath).toString(), theEnum.tokens.name.range)
|
|
187
|
-
}] }));
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(part.name.text, entityName)), { range: part.name.range, file: file }));
|
|
191
|
-
}
|
|
192
|
-
//no need to add another diagnostic for future unknown items
|
|
193
|
-
continue outer;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
//if the full expression is just an enum name, this is an illegal statement because enums don't exist at runtime
|
|
197
|
-
if (!info.isUsedAsType && enumStatement && info.parts.length === 1) {
|
|
198
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('enum')), { range: info.expression.range, file: file }), 'When used in scope');
|
|
199
|
-
}
|
|
200
|
-
//if the full expression is a namespace path, this is an illegal statement because namespaces don't exist at runtme
|
|
201
|
-
if (scope.getNamespace(entityNameLower, info.enclosingNamespaceNameLower)) {
|
|
202
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: info.expression.range, file: file }), 'When used in scope');
|
|
203
|
-
}
|
|
114
|
+
let assignmentAncestor;
|
|
115
|
+
if ((0, reflection_1.isAssignmentStatement)(definingNode) && definingNode.equals.kind === TokenKind_1.TokenKind.Equal) {
|
|
116
|
+
// this symbol was defined in a "normal" assignment (eg. not a compound assignment)
|
|
117
|
+
assignmentAncestor = definingNode;
|
|
118
|
+
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());
|
|
204
119
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
*/
|
|
210
|
-
getEnum(scope, name) {
|
|
211
|
-
//look for the enum directly
|
|
212
|
-
let result = scope.getEnumMap().get(name);
|
|
213
|
-
//assume we've been given the enum.member syntax, so pop the member and try again
|
|
214
|
-
if (!result) {
|
|
215
|
-
const parts = name.split('.');
|
|
216
|
-
parts.pop();
|
|
217
|
-
result = scope.getEnumMap().get(parts.join('.'));
|
|
218
|
-
}
|
|
219
|
-
return result;
|
|
120
|
+
else {
|
|
121
|
+
assignmentAncestor = expression === null || expression === void 0 ? void 0 : expression.findAncestor(reflection_1.isAssignmentStatement);
|
|
122
|
+
}
|
|
123
|
+
return (assignmentAncestor === null || assignmentAncestor === void 0 ? void 0 : assignmentAncestor.name) === (expression === null || expression === void 0 ? void 0 : expression.name) && (0, reflection_1.isUnionType)(exprType);
|
|
220
124
|
}
|
|
221
125
|
/**
|
|
222
126
|
* Flag duplicate enums
|
|
@@ -257,7 +161,7 @@ class ScopeValidator {
|
|
|
257
161
|
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: [{
|
|
258
162
|
message: 'Enum declared here',
|
|
259
163
|
location: util_1.default.createLocation(vscode_uri_1.URI.file(primaryEnum.file.srcPath).toString(), primaryEnum.statement.tokens.name.range)
|
|
260
|
-
}] }));
|
|
164
|
+
}], origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
261
165
|
}
|
|
262
166
|
}
|
|
263
167
|
this.event.scope.addDiagnostics(diagnostics);
|
|
@@ -268,64 +172,60 @@ class ScopeValidator {
|
|
|
268
172
|
* what these calls are supposed to look like, and this is a very common thing for brs devs to do, so just
|
|
269
173
|
* do this manually for now.
|
|
270
174
|
*/
|
|
271
|
-
|
|
272
|
-
var _a, _b, _c, _d, _e, _f
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
175
|
+
validateCreateObjectCall(file, call) {
|
|
176
|
+
var _a, _b, _c, _d, _e, _f;
|
|
177
|
+
//skip non CreateObject function calls
|
|
178
|
+
const callName = (_a = util_1.default.getAllDottedGetPartsAsString(call.callee)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
179
|
+
if (callName !== 'createobject' || !(0, reflection_1.isLiteralExpression)(call === null || call === void 0 ? void 0 : call.args[0])) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const firstParamToken = (_b = call === null || call === void 0 ? void 0 : call.args[0]) === null || _b === void 0 ? void 0 : _b.token;
|
|
183
|
+
const firstParamStringValue = (_c = firstParamToken === null || firstParamToken === void 0 ? void 0 : firstParamToken.text) === null || _c === void 0 ? void 0 : _c.replace(/"/g, '');
|
|
184
|
+
//if this is a `createObject('roSGNode'` call, only support known sg node types
|
|
185
|
+
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])) {
|
|
186
|
+
const componentName = (_d = call === null || call === void 0 ? void 0 : call.args[1]) === null || _d === void 0 ? void 0 : _d.token;
|
|
187
|
+
//don't validate any components with a colon in their name (probably component libraries, but regular components can have them too).
|
|
188
|
+
if ((_e = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _e === void 0 ? void 0 : _e.includes(':')) {
|
|
189
|
+
return;
|
|
278
190
|
}
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
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;
|
|
284
|
-
//don't validate any components with a colon in their name (probably component libraries, but regular components can have them too).
|
|
285
|
-
if ((_j = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _j === void 0 ? void 0 : _j.includes(':')) {
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
//add diagnostic for unknown components
|
|
289
|
-
const unquotedComponentName = (_k = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _k === void 0 ? void 0 : _k.replace(/"/g, '');
|
|
290
|
-
if (unquotedComponentName && !platformNodeNames.has(unquotedComponentName.toLowerCase()) && !this.event.program.getComponent(unquotedComponentName)) {
|
|
291
|
-
this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownRoSGNode(unquotedComponentName)), { range: componentName.range }));
|
|
292
|
-
}
|
|
293
|
-
else if ((call === null || call === void 0 ? void 0 : call.args.length) !== 2) {
|
|
294
|
-
// roSgNode should only ever have 2 args in `createObject`
|
|
295
|
-
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 }));
|
|
296
|
-
}
|
|
191
|
+
//add diagnostic for unknown components
|
|
192
|
+
const unquotedComponentName = (_f = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _f === void 0 ? void 0 : _f.replace(/"/g, '');
|
|
193
|
+
if (unquotedComponentName && !platformNodeNames.has(unquotedComponentName.toLowerCase()) && !this.event.program.getComponent(unquotedComponentName)) {
|
|
194
|
+
this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownRoSGNode(unquotedComponentName)), { range: componentName.range }));
|
|
297
195
|
}
|
|
298
|
-
else if (
|
|
299
|
-
|
|
196
|
+
else if ((call === null || call === void 0 ? void 0 : call.args.length) !== 2) {
|
|
197
|
+
// roSgNode should only ever have 2 args in `createObject`
|
|
198
|
+
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 }));
|
|
300
199
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
200
|
+
}
|
|
201
|
+
else if (!platformComponentNames.has(firstParamStringValue.toLowerCase())) {
|
|
202
|
+
this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownBrightScriptComponent(firstParamStringValue)), { range: firstParamToken.range }));
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// This is valid brightscript component
|
|
206
|
+
// Test for invalid arg counts
|
|
207
|
+
const brightScriptComponent = roku_types_1.components[firstParamStringValue.toLowerCase()];
|
|
208
|
+
// Valid arg counts for createObject are 1+ number of args for constructor
|
|
209
|
+
let validArgCounts = brightScriptComponent.constructors.map(cnstr => cnstr.params.length + 1);
|
|
210
|
+
if (validArgCounts.length === 0) {
|
|
211
|
+
// no constructors for this component, so createObject only takes 1 arg
|
|
212
|
+
validArgCounts = [1];
|
|
213
|
+
}
|
|
214
|
+
if (!validArgCounts.includes(call === null || call === void 0 ? void 0 : call.args.length)) {
|
|
215
|
+
// Incorrect number of arguments included in `createObject()`
|
|
216
|
+
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 }));
|
|
217
|
+
}
|
|
218
|
+
// Test for deprecation
|
|
219
|
+
if (brightScriptComponent.isDeprecated) {
|
|
220
|
+
this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.deprecatedBrightScriptComponent(firstParamStringValue, brightScriptComponent.deprecatedDescription)), { range: call.range }));
|
|
319
221
|
}
|
|
320
222
|
}
|
|
321
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
322
223
|
}
|
|
323
224
|
/**
|
|
324
225
|
* Detect calls to functions with the incorrect number of parameters, or wrong types of arguments
|
|
325
226
|
*/
|
|
326
227
|
validateFunctionCall(file, expression) {
|
|
327
228
|
var _a, _b;
|
|
328
|
-
const diagnostics = [];
|
|
329
229
|
const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
330
230
|
let funcType = (_a = expression === null || expression === void 0 ? void 0 : expression.callee) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
|
|
331
231
|
if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isClassType)(funcType)) {
|
|
@@ -345,10 +245,14 @@ class ScopeValidator {
|
|
|
345
245
|
minParams++;
|
|
346
246
|
}
|
|
347
247
|
}
|
|
248
|
+
if (funcType.isVariadic) {
|
|
249
|
+
// function accepts variable number of arguments
|
|
250
|
+
maxParams = Expression_1.CallExpression.MaximumArguments;
|
|
251
|
+
}
|
|
348
252
|
let expCallArgCount = expression.args.length;
|
|
349
253
|
if (expCallArgCount > maxParams || expCallArgCount < minParams) {
|
|
350
254
|
let minMaxParamsText = minParams === maxParams ? maxParams : `${minParams}-${maxParams}`;
|
|
351
|
-
|
|
255
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expression.callee.range,
|
|
352
256
|
//TODO detect end of expression call
|
|
353
257
|
file: file }));
|
|
354
258
|
}
|
|
@@ -369,14 +273,12 @@ class ScopeValidator {
|
|
|
369
273
|
paramIndex++;
|
|
370
274
|
}
|
|
371
275
|
}
|
|
372
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
373
276
|
}
|
|
374
277
|
/**
|
|
375
278
|
* Detect return statements with incompatible types vs. declared return type
|
|
376
279
|
*/
|
|
377
280
|
validateReturnStatement(file, returnStmt) {
|
|
378
281
|
var _a;
|
|
379
|
-
const diagnostics = [];
|
|
380
282
|
const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
381
283
|
let funcType = returnStmt.findAncestor(reflection_1.isFunctionExpression).getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
|
|
382
284
|
if ((0, reflection_1.isTypedFunctionType)(funcType)) {
|
|
@@ -386,14 +288,12 @@ class ScopeValidator {
|
|
|
386
288
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch(actualReturnType.toString(), funcType.returnType.toString(), compatibilityData)), { range: returnStmt.value.range, file: file }));
|
|
387
289
|
}
|
|
388
290
|
}
|
|
389
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
390
291
|
}
|
|
391
292
|
/**
|
|
392
293
|
* Detect return statements with incompatible types vs. declared return type
|
|
393
294
|
*/
|
|
394
295
|
validateDottedSetStatement(file, dottedSetStmt) {
|
|
395
296
|
var _a, _b, _c;
|
|
396
|
-
const diagnostics = [];
|
|
397
297
|
const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
398
298
|
const expectedLHSType = (_b = (_a = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.obj) === null || _a === void 0 ? void 0 : _a.getType(getTypeOpts)) === null || _b === void 0 ? void 0 : _b.getMemberType(dottedSetStmt.name.text, getTypeOpts);
|
|
399
299
|
const actualRHSType = (_c = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.value) === null || _c === void 0 ? void 0 : _c.getType(getTypeOpts);
|
|
@@ -401,15 +301,13 @@ class ScopeValidator {
|
|
|
401
301
|
if ((expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isResolvable()) && !(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
|
|
402
302
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch(actualRHSType.toString(), expectedLHSType.toString(), compatibilityData)), { range: dottedSetStmt.range, file: file }));
|
|
403
303
|
}
|
|
404
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
405
304
|
}
|
|
406
305
|
/**
|
|
407
306
|
* Detect invalid use of a binary operator
|
|
408
307
|
*/
|
|
409
308
|
validateBinaryExpression(file, binaryExpr) {
|
|
410
|
-
const diagnostics = [];
|
|
411
309
|
const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
412
|
-
if (
|
|
310
|
+
if (util_1.default.isInTypeExpression(binaryExpr)) {
|
|
413
311
|
return;
|
|
414
312
|
}
|
|
415
313
|
let leftType = binaryExpr.left.getType(getTypeOpts);
|
|
@@ -448,13 +346,11 @@ class ScopeValidator {
|
|
|
448
346
|
// if the result was dynamic, that means there wasn't a valid operation
|
|
449
347
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(binaryExpr.operator.text, leftType.toString(), rightType.toString())), { range: binaryExpr.range, file: file }));
|
|
450
348
|
}
|
|
451
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
452
349
|
}
|
|
453
350
|
/**
|
|
454
351
|
* Detect invalid use of a Unary operator
|
|
455
352
|
*/
|
|
456
353
|
validateUnaryExpression(file, unaryExpr) {
|
|
457
|
-
const diagnostics = [];
|
|
458
354
|
const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
459
355
|
let rightType = unaryExpr.right.getType(getTypeOpts);
|
|
460
356
|
if (!rightType.isResolvable()) {
|
|
@@ -468,11 +364,9 @@ class ScopeValidator {
|
|
|
468
364
|
if ((0, reflection_1.isUnionType)(rightTypeToTest)) {
|
|
469
365
|
// TODO: it is possible to validate based on innerTypes, but more complicated
|
|
470
366
|
// Because you need to verify each combination of types
|
|
471
|
-
return;
|
|
472
367
|
}
|
|
473
368
|
else if ((0, reflection_1.isDynamicType)(rightTypeToTest) || (0, reflection_1.isObjectType)(rightTypeToTest)) {
|
|
474
369
|
// operand is basically "any" type... ignore;
|
|
475
|
-
return;
|
|
476
370
|
}
|
|
477
371
|
else if ((0, reflection_1.isPrimitiveType)(rightType)) {
|
|
478
372
|
const opResult = util_1.default.unaryOperatorResultType(unaryExpr.operator, rightTypeToTest);
|
|
@@ -484,7 +378,82 @@ class ScopeValidator {
|
|
|
484
378
|
// rhs is not a primitive, so no binary operator is allowed
|
|
485
379
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(unaryExpr.operator.text, rightType.toString())), { range: unaryExpr.range, file: file }));
|
|
486
380
|
}
|
|
487
|
-
|
|
381
|
+
}
|
|
382
|
+
validateVariableAndDottedGetExpressions(file, expression) {
|
|
383
|
+
var _a, _b;
|
|
384
|
+
if ((0, reflection_1.isDottedGetExpression)(expression.parent)) {
|
|
385
|
+
// We validate dottedGetExpressions at the top-most level
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if ((0, reflection_1.isVariableExpression)(expression)) {
|
|
389
|
+
if ((0, reflection_1.isAssignmentStatement)(expression.parent) && expression.parent.name === expression.name) {
|
|
390
|
+
// Don't validate LHS of assignments
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
else if ((0, reflection_1.isNamespaceStatement)(expression.parent)) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
let symbolType = SymbolTable_1.SymbolTypeFlag.runtime;
|
|
398
|
+
let oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.typetime;
|
|
399
|
+
const isUsedAsType = util_1.default.isInTypeExpression(expression);
|
|
400
|
+
if (isUsedAsType) {
|
|
401
|
+
// This is used in a TypeExpression - only look up types from SymbolTable
|
|
402
|
+
symbolType = SymbolTable_1.SymbolTypeFlag.typetime;
|
|
403
|
+
oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.runtime;
|
|
404
|
+
}
|
|
405
|
+
// Do a complete type check on all DottedGet and Variable expressions
|
|
406
|
+
// this will create a diagnostic if an invalid member is accessed
|
|
407
|
+
const typeChain = [];
|
|
408
|
+
const typeData = {};
|
|
409
|
+
let exprType = expression.getType({
|
|
410
|
+
flags: symbolType,
|
|
411
|
+
typeChain: typeChain,
|
|
412
|
+
data: typeData
|
|
413
|
+
});
|
|
414
|
+
const shouldIgnoreLHS = this.ignoreUnresolvedAssignmentLHS(expression, exprType, typeData === null || typeData === void 0 ? void 0 : typeData.definingNode);
|
|
415
|
+
if (!this.isTypeKnown(exprType) && !shouldIgnoreLHS) {
|
|
416
|
+
if ((_a = expression.getType({ flags: oppositeSymbolType })) === null || _a === void 0 ? void 0 : _a.isResolvable()) {
|
|
417
|
+
const oppoSiteTypeChain = [];
|
|
418
|
+
const invalidlyUsedResolvedType = expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain });
|
|
419
|
+
const typeChainScan = util_1.default.processTypeChain(oppoSiteTypeChain);
|
|
420
|
+
if (isUsedAsType) {
|
|
421
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsType(typeChainScan.fullChainName)), { range: expression.range, file: file }));
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: expression.range, file: file }));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
const typeChainScan = util_1.default.processTypeChain(typeChain);
|
|
429
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (isUsedAsType) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const lastTypeInfo = typeChain[typeChain.length - 1];
|
|
436
|
+
const parentTypeInfo = typeChain[typeChain.length - 2];
|
|
437
|
+
if ((0, reflection_1.isNamespaceType)(exprType)) {
|
|
438
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: expression.range, file: file }));
|
|
439
|
+
}
|
|
440
|
+
else if ((0, reflection_1.isEnumType)(exprType)) {
|
|
441
|
+
const enumStatement = this.event.scope.getEnum(util_1.default.getAllDottedGetPartsAsString(expression));
|
|
442
|
+
if (enumStatement) {
|
|
443
|
+
// there's an enum with this name
|
|
444
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('enum')), { range: expression.range, file: file }));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
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)) {
|
|
448
|
+
const enumFileLink = this.event.scope.getEnumFileLink(util_1.default.getAllDottedGetPartsAsString(expression.obj));
|
|
449
|
+
const typeChainScanForParent = util_1.default.processTypeChain(typeChain.slice(0, -1));
|
|
450
|
+
if (enumFileLink) {
|
|
451
|
+
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: [{
|
|
452
|
+
message: 'Enum declared here',
|
|
453
|
+
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)
|
|
454
|
+
}] }));
|
|
455
|
+
}
|
|
456
|
+
}
|
|
488
457
|
}
|
|
489
458
|
/**
|
|
490
459
|
* Adds a diagnostic to the first scope for this key. Prevents duplicate diagnostics
|
|
@@ -492,35 +461,58 @@ class ScopeValidator {
|
|
|
492
461
|
*/
|
|
493
462
|
addDiagnosticOnce(diagnostic) {
|
|
494
463
|
this.onceCache.getOrAdd(`${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
|
|
495
|
-
|
|
464
|
+
const diagnosticWithOrigin = Object.assign({}, diagnostic);
|
|
465
|
+
if (!diagnosticWithOrigin.origin) {
|
|
466
|
+
// diagnostic does not have origin.
|
|
467
|
+
// set the origin to the current astSegment
|
|
468
|
+
diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
|
|
469
|
+
diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
|
|
470
|
+
}
|
|
471
|
+
this.event.scope.addDiagnostics([diagnosticWithOrigin]);
|
|
496
472
|
return true;
|
|
497
473
|
});
|
|
498
474
|
}
|
|
499
475
|
addDiagnostic(diagnostic) {
|
|
500
|
-
|
|
476
|
+
const diagnosticWithOrigin = Object.assign({}, diagnostic);
|
|
477
|
+
if (!diagnosticWithOrigin.origin) {
|
|
478
|
+
// diagnostic does not have origin.
|
|
479
|
+
// set the origin to the current astSegment
|
|
480
|
+
diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
|
|
481
|
+
diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
|
|
482
|
+
}
|
|
483
|
+
this.event.scope.addDiagnostics([diagnosticWithOrigin]);
|
|
501
484
|
}
|
|
502
485
|
/**
|
|
503
486
|
* Add a diagnostic (to the first scope) that will have `relatedInformation` for each affected scope
|
|
504
487
|
*/
|
|
505
|
-
addMultiScopeDiagnostic(diagnostic
|
|
506
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
488
|
+
addMultiScopeDiagnostic(diagnostic) {
|
|
489
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
507
490
|
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)}`, () => {
|
|
508
491
|
if (!diagnostic.relatedInformation) {
|
|
509
492
|
diagnostic.relatedInformation = [];
|
|
510
493
|
}
|
|
511
|
-
|
|
512
|
-
|
|
494
|
+
const diagnosticWithOrigin = Object.assign({}, diagnostic);
|
|
495
|
+
if (!diagnosticWithOrigin.origin) {
|
|
496
|
+
// diagnostic does not have origin.
|
|
497
|
+
// set the origin to the current astSegment
|
|
498
|
+
diagnosticWithOrigin.origin = interfaces_1.DiagnosticOrigin.ASTSegment;
|
|
499
|
+
diagnosticWithOrigin.astSegment = this.currentSegmentBeingValidated;
|
|
500
|
+
}
|
|
501
|
+
this.addDiagnostic(diagnosticWithOrigin);
|
|
502
|
+
return diagnosticWithOrigin;
|
|
513
503
|
});
|
|
514
|
-
const info = {
|
|
515
|
-
message: `${message} '${this.event.scope.name}'`
|
|
516
|
-
};
|
|
517
504
|
if ((0, reflection_1.isXmlScope)(this.event.scope) && ((_b = this.event.scope.xmlFile) === null || _b === void 0 ? void 0 : _b.srcPath)) {
|
|
518
|
-
|
|
505
|
+
diagnostic.relatedInformation.push({
|
|
506
|
+
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}'`,
|
|
507
|
+
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))
|
|
508
|
+
});
|
|
519
509
|
}
|
|
520
510
|
else {
|
|
521
|
-
|
|
511
|
+
diagnostic.relatedInformation.push({
|
|
512
|
+
message: `In scope '${this.event.scope.name}'`,
|
|
513
|
+
location: util_1.default.createLocation(vscode_uri_1.URI.file(diagnostic.file.srcPath).toString(), diagnostic.range)
|
|
514
|
+
});
|
|
522
515
|
}
|
|
523
|
-
diagnostic.relatedInformation.push(info);
|
|
524
516
|
}
|
|
525
517
|
}
|
|
526
518
|
exports.ScopeValidator = ScopeValidator;
|