brighterscript 0.66.0-alpha.7 → 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 +36 -0
- package/dist/AstValidationSegmenter.d.ts +25 -0
- package/dist/AstValidationSegmenter.js +150 -0
- package/dist/AstValidationSegmenter.js.map +1 -0
- package/dist/DiagnosticMessages.d.ts +6 -1
- package/dist/DiagnosticMessages.js +5 -0
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.js +7 -1
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Program.d.ts +24 -2
- package/dist/Program.js +112 -3
- package/dist/Program.js.map +1 -1
- package/dist/Scope.d.ts +15 -27
- package/dist/Scope.js +127 -150
- 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 +1 -1
- package/dist/XmlScope.js +5 -4
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +11 -0
- package/dist/astUtils/visitors.js +22 -2
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +51 -0
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +2 -2
- package/dist/bscPlugin/completions/CompletionsProcessor.js +76 -31
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +147 -3
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/hover/HoverProcessor.js +9 -1
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +4 -1
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.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 +199 -216
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +343 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +201 -0
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +25 -2
- package/dist/files/BrsFile.js +210 -2
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +868 -0
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +45 -5
- package/dist/interfaces.js +10 -2
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +1 -0
- package/dist/lexer/TokenKind.js +4 -0
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/Expression.d.ts +1 -1
- package/dist/parser/Expression.js +20 -10
- 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 +58 -13
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +212 -0
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/Statement.d.ts +9 -3
- package/dist/parser/Statement.js +56 -26
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +6 -6
- 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 +74 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.js +9 -0
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +8 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/roku-types/data.json +18 -51
- package/dist/types/BooleanType.d.ts +1 -1
- package/dist/types/BscType.d.ts +2 -2
- package/dist/types/BscType.js +28 -9
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BuiltInInterfaceAdder.js +6 -4
- 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/EnumType.d.ts +1 -1
- package/dist/types/EnumType.js +7 -2
- package/dist/types/EnumType.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/InterfaceType.d.ts +4 -3
- package/dist/types/InterfaceType.js +4 -4
- package/dist/types/InterfaceType.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/ReferenceType.js +40 -6
- package/dist/types/ReferenceType.js.map +1 -1
- package/dist/types/TypedFunctionType.js +5 -5
- package/dist/types/TypedFunctionType.js.map +1 -1
- package/dist/types/UnionType.js +1 -0
- package/dist/types/UnionType.js.map +1 -1
- package/dist/types/helpers.js +4 -0
- package/dist/types/helpers.js.map +1 -1
- package/dist/util.d.ts +14 -4
- package/dist/util.js +86 -32
- package/dist/util.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,13 +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
12
|
const Expression_1 = require("../../parser/Expression");
|
|
12
|
-
const Parser_1 = require("../../parser/Parser");
|
|
13
|
-
const TokenKind_1 = require("../../lexer/TokenKind");
|
|
14
13
|
const visitors_1 = require("../../astUtils/visitors");
|
|
14
|
+
const AstValidationSegmenter_1 = require("../../AstValidationSegmenter");
|
|
15
|
+
const TokenKind_1 = require("../../lexer/TokenKind");
|
|
15
16
|
/**
|
|
16
17
|
* The lower-case names of all platform-included scenegraph nodes
|
|
17
18
|
*/
|
|
@@ -25,12 +26,14 @@ const platformComponentNames = roku_types_1.components ? new Set(Object.values(r
|
|
|
25
26
|
*/
|
|
26
27
|
class ScopeValidator {
|
|
27
28
|
constructor() {
|
|
28
|
-
this.expressionsByFile = new Cache_1.Cache();
|
|
29
29
|
this.onceCache = new Cache_1.Cache();
|
|
30
30
|
this.multiScopeCache = new Cache_1.Cache();
|
|
31
31
|
}
|
|
32
32
|
processEvent(event) {
|
|
33
33
|
this.event = event;
|
|
34
|
+
if (this.event.program.globalScope === this.event.scope) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
34
37
|
this.walkFiles();
|
|
35
38
|
this.detectDuplicateEnums();
|
|
36
39
|
}
|
|
@@ -42,11 +45,32 @@ class ScopeValidator {
|
|
|
42
45
|
walkFiles() {
|
|
43
46
|
this.event.scope.enumerateOwnFiles((file) => {
|
|
44
47
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
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
|
+
},
|
|
48
71
|
CallExpression: (functionCall) => {
|
|
49
72
|
this.validateFunctionCall(file, functionCall);
|
|
73
|
+
this.validateCreateObjectCall(file, functionCall);
|
|
50
74
|
},
|
|
51
75
|
ReturnStatement: (returnStatement) => {
|
|
52
76
|
this.validateReturnStatement(file, returnStatement);
|
|
@@ -60,29 +84,21 @@ class ScopeValidator {
|
|
|
60
84
|
UnaryExpression: (unaryExpr) => {
|
|
61
85
|
this.validateUnaryExpression(file, unaryExpr);
|
|
62
86
|
}
|
|
63
|
-
}), {
|
|
64
|
-
walkMode: visitors_1.WalkMode.visitAllRecursive
|
|
65
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
|
+
}
|
|
66
99
|
}
|
|
67
100
|
});
|
|
68
101
|
}
|
|
69
|
-
checkIfUsedAsTypeExpression(expression) {
|
|
70
|
-
//TODO: this is much faster than node.findAncestor(), but may need to be updated for "complicated" type expressions
|
|
71
|
-
if ((0, reflection_1.isTypeExpression)(expression) ||
|
|
72
|
-
(0, reflection_1.isTypeExpression)(expression.parent) ||
|
|
73
|
-
(0, reflection_1.isTypedArrayExpression)(expression) ||
|
|
74
|
-
(0, reflection_1.isTypedArrayExpression)(expression.parent)) {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
if ((0, reflection_1.isBinaryExpression)(expression.parent)) {
|
|
78
|
-
let currentExpr = expression.parent;
|
|
79
|
-
while ((0, reflection_1.isBinaryExpression)(currentExpr) && currentExpr.operator.kind === TokenKind_1.TokenKind.Or) {
|
|
80
|
-
currentExpr = currentExpr.parent;
|
|
81
|
-
}
|
|
82
|
-
return (0, reflection_1.isTypeExpression)(currentExpr) || (0, reflection_1.isTypedArrayExpression)(currentExpr);
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
102
|
isTypeKnown(exprType) {
|
|
87
103
|
let isKnownType = exprType === null || exprType === void 0 ? void 0 : exprType.isResolvable();
|
|
88
104
|
return isKnownType;
|
|
@@ -90,136 +106,21 @@ class ScopeValidator {
|
|
|
90
106
|
/**
|
|
91
107
|
* If this is the lhs of an assignment, we don't need to flag it as unresolved
|
|
92
108
|
*/
|
|
93
|
-
ignoreUnresolvedAssignmentLHS(expression, exprType) {
|
|
109
|
+
ignoreUnresolvedAssignmentLHS(expression, exprType, definingNode) {
|
|
110
|
+
var _a, _b;
|
|
94
111
|
if (!(0, reflection_1.isVariableExpression)(expression)) {
|
|
95
112
|
return false;
|
|
96
113
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const { scope } = this.event;
|
|
103
|
-
//build an expression collection ONCE per file
|
|
104
|
-
const expressionInfos = this.expressionsByFile.getOrAdd(file, () => {
|
|
105
|
-
var _a, _b;
|
|
106
|
-
const result = [];
|
|
107
|
-
const expressions = [...file.parser.references.expressions];
|
|
108
|
-
for (let expression of expressions) {
|
|
109
|
-
if (!expression) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
//walk left-to-right on every expression, only keep the ones that start with VariableExpression, and then keep subsequent DottedGet parts
|
|
113
|
-
const parts = util_1.default.getDottedGetPath(expression);
|
|
114
|
-
if (parts.length > 0) {
|
|
115
|
-
result.push({
|
|
116
|
-
parts: parts,
|
|
117
|
-
expression: expression,
|
|
118
|
-
isUsedAsType: this.checkIfUsedAsTypeExpression(expression),
|
|
119
|
-
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()
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return result;
|
|
124
|
-
});
|
|
125
|
-
outer: for (const info of expressionInfos) {
|
|
126
|
-
const firstNamespacePart = info.parts[0].name.text;
|
|
127
|
-
const firstNamespacePartLower = firstNamespacePart === null || firstNamespacePart === void 0 ? void 0 : firstNamespacePart.toLowerCase();
|
|
128
|
-
//get the namespace container (accounting for namespace-relative as well)
|
|
129
|
-
const namespaceContainer = scope.getNamespace(firstNamespacePartLower, info.enclosingNamespaceNameLower);
|
|
130
|
-
let symbolType = SymbolTable_1.SymbolTypeFlag.runtime;
|
|
131
|
-
let oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.typetime;
|
|
132
|
-
if (info.isUsedAsType) {
|
|
133
|
-
// This is used in a TypeExpression - only look up types from SymbolTable
|
|
134
|
-
symbolType = SymbolTable_1.SymbolTypeFlag.typetime;
|
|
135
|
-
oppositeSymbolType = SymbolTable_1.SymbolTypeFlag.runtime;
|
|
136
|
-
}
|
|
137
|
-
// Do a complete type check on all DottedGet and Variable expressions
|
|
138
|
-
// this will create a diagnostic if an invalid member is accessed
|
|
139
|
-
const typeChain = [];
|
|
140
|
-
let exprType = info.expression.getType({
|
|
141
|
-
flags: symbolType,
|
|
142
|
-
typeChain: typeChain
|
|
143
|
-
});
|
|
144
|
-
if (!this.isTypeKnown(exprType) && !this.ignoreUnresolvedAssignmentLHS(info.expression, exprType)) {
|
|
145
|
-
if ((_a = info.expression.getType({ flags: oppositeSymbolType })) === null || _a === void 0 ? void 0 : _a.isResolvable()) {
|
|
146
|
-
const oppoSiteTypeChain = [];
|
|
147
|
-
const invalidlyUsedResolvedType = info.expression.getType({ flags: oppositeSymbolType, typeChain: oppoSiteTypeChain });
|
|
148
|
-
const typeChainScan = util_1.default.processTypeChain(oppoSiteTypeChain);
|
|
149
|
-
if (info.isUsedAsType) {
|
|
150
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsType(typeChainScan.fullChainName)), { range: info.expression.range, file: file }));
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable(invalidlyUsedResolvedType.toString())), { range: info.expression.range, file: file }));
|
|
154
|
-
}
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
const typeChainScan = util_1.default.processTypeChain(typeChain);
|
|
158
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(typeChainScan.itemName, typeChainScan.fullNameOfItem)), { range: typeChainScan.range }));
|
|
159
|
-
//skip to the next expression
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
const enumStatement = scope.getEnum(firstNamespacePartLower, info.enclosingNamespaceNameLower);
|
|
163
|
-
//if this isn't a namespace, skip it
|
|
164
|
-
if (!namespaceContainer && !enumStatement) {
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
//catch unknown namespace items
|
|
168
|
-
let entityName = firstNamespacePart;
|
|
169
|
-
let entityNameLower = firstNamespacePart.toLowerCase();
|
|
170
|
-
for (let i = 1; i < info.parts.length; i++) {
|
|
171
|
-
const part = info.parts[i];
|
|
172
|
-
entityName += '.' + part.name.text;
|
|
173
|
-
entityNameLower += '.' + part.name.text.toLowerCase();
|
|
174
|
-
//if this is an enum member, stop validating here to prevent errors further down the chain
|
|
175
|
-
if (scope.getEnumMemberFileLink(entityName, info.enclosingNamespaceNameLower)) {
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
if (!scope.getEnumMap().has(entityNameLower) &&
|
|
179
|
-
!scope.getClassMap().has(entityNameLower) &&
|
|
180
|
-
!scope.getInterfaceMap().has(entityNameLower) &&
|
|
181
|
-
!scope.getConstMap().has(entityNameLower) &&
|
|
182
|
-
!scope.getCallableByName(entityNameLower) &&
|
|
183
|
-
!scope.getNamespace(entityNameLower, info.enclosingNamespaceNameLower)) {
|
|
184
|
-
//if this looks like an enum, provide a nicer error message
|
|
185
|
-
const theEnum = (_b = this.getEnum(scope, entityNameLower)) === null || _b === void 0 ? void 0 : _b.item;
|
|
186
|
-
if (theEnum) {
|
|
187
|
-
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: [{
|
|
188
|
-
message: 'Enum declared here',
|
|
189
|
-
location: util_1.default.createLocation(vscode_uri_1.URI.file(file.srcPath).toString(), theEnum.tokens.name.range)
|
|
190
|
-
}] }));
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotFindName(part.name.text, entityName)), { range: part.name.range, file: file }));
|
|
194
|
-
}
|
|
195
|
-
//no need to add another diagnostic for future unknown items
|
|
196
|
-
continue outer;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
//if the full expression is just an enum name, this is an illegal statement because enums don't exist at runtime
|
|
200
|
-
if (!info.isUsedAsType && enumStatement && info.parts.length === 1) {
|
|
201
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('enum')), { range: info.expression.range, file: file }));
|
|
202
|
-
}
|
|
203
|
-
//if the full expression is a namespace path, this is an illegal statement because namespaces don't exist at runtme
|
|
204
|
-
if (scope.getNamespace(entityNameLower, info.enclosingNamespaceNameLower)) {
|
|
205
|
-
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: info.expression.range, file: file }));
|
|
206
|
-
}
|
|
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());
|
|
207
119
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
*/
|
|
213
|
-
getEnum(scope, name) {
|
|
214
|
-
//look for the enum directly
|
|
215
|
-
let result = scope.getEnumMap().get(name);
|
|
216
|
-
//assume we've been given the enum.member syntax, so pop the member and try again
|
|
217
|
-
if (!result) {
|
|
218
|
-
const parts = name.split('.');
|
|
219
|
-
parts.pop();
|
|
220
|
-
result = scope.getEnumMap().get(parts.join('.'));
|
|
221
|
-
}
|
|
222
|
-
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);
|
|
223
124
|
}
|
|
224
125
|
/**
|
|
225
126
|
* Flag duplicate enums
|
|
@@ -260,7 +161,7 @@ class ScopeValidator {
|
|
|
260
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: [{
|
|
261
162
|
message: 'Enum declared here',
|
|
262
163
|
location: util_1.default.createLocation(vscode_uri_1.URI.file(primaryEnum.file.srcPath).toString(), primaryEnum.statement.tokens.name.range)
|
|
263
|
-
}] }));
|
|
164
|
+
}], origin: interfaces_1.DiagnosticOrigin.Scope }));
|
|
264
165
|
}
|
|
265
166
|
}
|
|
266
167
|
this.event.scope.addDiagnostics(diagnostics);
|
|
@@ -271,64 +172,60 @@ class ScopeValidator {
|
|
|
271
172
|
* what these calls are supposed to look like, and this is a very common thing for brs devs to do, so just
|
|
272
173
|
* do this manually for now.
|
|
273
174
|
*/
|
|
274
|
-
|
|
275
|
-
var _a, _b, _c, _d, _e, _f
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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;
|
|
281
190
|
}
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
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;
|
|
287
|
-
//don't validate any components with a colon in their name (probably component libraries, but regular components can have them too).
|
|
288
|
-
if ((_j = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _j === void 0 ? void 0 : _j.includes(':')) {
|
|
289
|
-
continue;
|
|
290
|
-
}
|
|
291
|
-
//add diagnostic for unknown components
|
|
292
|
-
const unquotedComponentName = (_k = componentName === null || componentName === void 0 ? void 0 : componentName.text) === null || _k === void 0 ? void 0 : _k.replace(/"/g, '');
|
|
293
|
-
if (unquotedComponentName && !platformNodeNames.has(unquotedComponentName.toLowerCase()) && !this.event.program.getComponent(unquotedComponentName)) {
|
|
294
|
-
this.addDiagnosticOnce(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.unknownRoSGNode(unquotedComponentName)), { range: componentName.range }));
|
|
295
|
-
}
|
|
296
|
-
else if ((call === null || call === void 0 ? void 0 : call.args.length) !== 2) {
|
|
297
|
-
// roSgNode should only ever have 2 args in `createObject`
|
|
298
|
-
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 }));
|
|
299
|
-
}
|
|
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 }));
|
|
300
195
|
}
|
|
301
|
-
else if (
|
|
302
|
-
|
|
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 }));
|
|
303
199
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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 }));
|
|
322
221
|
}
|
|
323
222
|
}
|
|
324
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
325
223
|
}
|
|
326
224
|
/**
|
|
327
225
|
* Detect calls to functions with the incorrect number of parameters, or wrong types of arguments
|
|
328
226
|
*/
|
|
329
227
|
validateFunctionCall(file, expression) {
|
|
330
228
|
var _a, _b;
|
|
331
|
-
const diagnostics = [];
|
|
332
229
|
const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
333
230
|
let funcType = (_a = expression === null || expression === void 0 ? void 0 : expression.callee) === null || _a === void 0 ? void 0 : _a.getType(getTypeOptions);
|
|
334
231
|
if ((funcType === null || funcType === void 0 ? void 0 : funcType.isResolvable()) && (0, reflection_1.isClassType)(funcType)) {
|
|
@@ -355,7 +252,7 @@ class ScopeValidator {
|
|
|
355
252
|
let expCallArgCount = expression.args.length;
|
|
356
253
|
if (expCallArgCount > maxParams || expCallArgCount < minParams) {
|
|
357
254
|
let minMaxParamsText = minParams === maxParams ? maxParams : `${minParams}-${maxParams}`;
|
|
358
|
-
|
|
255
|
+
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expression.callee.range,
|
|
359
256
|
//TODO detect end of expression call
|
|
360
257
|
file: file }));
|
|
361
258
|
}
|
|
@@ -376,14 +273,12 @@ class ScopeValidator {
|
|
|
376
273
|
paramIndex++;
|
|
377
274
|
}
|
|
378
275
|
}
|
|
379
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
380
276
|
}
|
|
381
277
|
/**
|
|
382
278
|
* Detect return statements with incompatible types vs. declared return type
|
|
383
279
|
*/
|
|
384
280
|
validateReturnStatement(file, returnStmt) {
|
|
385
281
|
var _a;
|
|
386
|
-
const diagnostics = [];
|
|
387
282
|
const getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
388
283
|
let funcType = returnStmt.findAncestor(reflection_1.isFunctionExpression).getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
|
|
389
284
|
if ((0, reflection_1.isTypedFunctionType)(funcType)) {
|
|
@@ -393,14 +288,12 @@ class ScopeValidator {
|
|
|
393
288
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch(actualReturnType.toString(), funcType.returnType.toString(), compatibilityData)), { range: returnStmt.value.range, file: file }));
|
|
394
289
|
}
|
|
395
290
|
}
|
|
396
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
397
291
|
}
|
|
398
292
|
/**
|
|
399
293
|
* Detect return statements with incompatible types vs. declared return type
|
|
400
294
|
*/
|
|
401
295
|
validateDottedSetStatement(file, dottedSetStmt) {
|
|
402
296
|
var _a, _b, _c;
|
|
403
|
-
const diagnostics = [];
|
|
404
297
|
const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
405
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);
|
|
406
299
|
const actualRHSType = (_c = dottedSetStmt === null || dottedSetStmt === void 0 ? void 0 : dottedSetStmt.value) === null || _c === void 0 ? void 0 : _c.getType(getTypeOpts);
|
|
@@ -408,15 +301,13 @@ class ScopeValidator {
|
|
|
408
301
|
if ((expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isResolvable()) && !(expectedLHSType === null || expectedLHSType === void 0 ? void 0 : expectedLHSType.isTypeCompatible(actualRHSType, compatibilityData))) {
|
|
409
302
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch(actualRHSType.toString(), expectedLHSType.toString(), compatibilityData)), { range: dottedSetStmt.range, file: file }));
|
|
410
303
|
}
|
|
411
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
412
304
|
}
|
|
413
305
|
/**
|
|
414
306
|
* Detect invalid use of a binary operator
|
|
415
307
|
*/
|
|
416
308
|
validateBinaryExpression(file, binaryExpr) {
|
|
417
|
-
const diagnostics = [];
|
|
418
309
|
const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
419
|
-
if (
|
|
310
|
+
if (util_1.default.isInTypeExpression(binaryExpr)) {
|
|
420
311
|
return;
|
|
421
312
|
}
|
|
422
313
|
let leftType = binaryExpr.left.getType(getTypeOpts);
|
|
@@ -455,13 +346,11 @@ class ScopeValidator {
|
|
|
455
346
|
// if the result was dynamic, that means there wasn't a valid operation
|
|
456
347
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(binaryExpr.operator.text, leftType.toString(), rightType.toString())), { range: binaryExpr.range, file: file }));
|
|
457
348
|
}
|
|
458
|
-
this.event.scope.addDiagnostics(diagnostics);
|
|
459
349
|
}
|
|
460
350
|
/**
|
|
461
351
|
* Detect invalid use of a Unary operator
|
|
462
352
|
*/
|
|
463
353
|
validateUnaryExpression(file, unaryExpr) {
|
|
464
|
-
const diagnostics = [];
|
|
465
354
|
const getTypeOpts = { flags: SymbolTable_1.SymbolTypeFlag.runtime };
|
|
466
355
|
let rightType = unaryExpr.right.getType(getTypeOpts);
|
|
467
356
|
if (!rightType.isResolvable()) {
|
|
@@ -475,11 +364,9 @@ class ScopeValidator {
|
|
|
475
364
|
if ((0, reflection_1.isUnionType)(rightTypeToTest)) {
|
|
476
365
|
// TODO: it is possible to validate based on innerTypes, but more complicated
|
|
477
366
|
// Because you need to verify each combination of types
|
|
478
|
-
return;
|
|
479
367
|
}
|
|
480
368
|
else if ((0, reflection_1.isDynamicType)(rightTypeToTest) || (0, reflection_1.isObjectType)(rightTypeToTest)) {
|
|
481
369
|
// operand is basically "any" type... ignore;
|
|
482
|
-
return;
|
|
483
370
|
}
|
|
484
371
|
else if ((0, reflection_1.isPrimitiveType)(rightType)) {
|
|
485
372
|
const opResult = util_1.default.unaryOperatorResultType(unaryExpr.operator, rightTypeToTest);
|
|
@@ -491,7 +378,82 @@ class ScopeValidator {
|
|
|
491
378
|
// rhs is not a primitive, so no binary operator is allowed
|
|
492
379
|
this.addMultiScopeDiagnostic(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch(unaryExpr.operator.text, rightType.toString())), { range: unaryExpr.range, file: file }));
|
|
493
380
|
}
|
|
494
|
-
|
|
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
|
+
}
|
|
495
457
|
}
|
|
496
458
|
/**
|
|
497
459
|
* Adds a diagnostic to the first scope for this key. Prevents duplicate diagnostics
|
|
@@ -499,12 +461,26 @@ class ScopeValidator {
|
|
|
499
461
|
*/
|
|
500
462
|
addDiagnosticOnce(diagnostic) {
|
|
501
463
|
this.onceCache.getOrAdd(`${diagnostic.code}-${diagnostic.message}-${util_1.default.rangeToString(diagnostic.range)}`, () => {
|
|
502
|
-
|
|
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]);
|
|
503
472
|
return true;
|
|
504
473
|
});
|
|
505
474
|
}
|
|
506
475
|
addDiagnostic(diagnostic) {
|
|
507
|
-
|
|
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]);
|
|
508
484
|
}
|
|
509
485
|
/**
|
|
510
486
|
* Add a diagnostic (to the first scope) that will have `relatedInformation` for each affected scope
|
|
@@ -515,8 +491,15 @@ class ScopeValidator {
|
|
|
515
491
|
if (!diagnostic.relatedInformation) {
|
|
516
492
|
diagnostic.relatedInformation = [];
|
|
517
493
|
}
|
|
518
|
-
|
|
519
|
-
|
|
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;
|
|
520
503
|
});
|
|
521
504
|
if ((0, reflection_1.isXmlScope)(this.event.scope) && ((_b = this.event.scope.xmlFile) === null || _b === void 0 ? void 0 : _b.srcPath)) {
|
|
522
505
|
diagnostic.relatedInformation.push({
|