diff --git a/src/DiagnosticMessages.ts b/src/DiagnosticMessages.ts index 482356ff0..980edd1f4 100644 --- a/src/DiagnosticMessages.ts +++ b/src/DiagnosticMessages.ts @@ -696,7 +696,7 @@ export let DiagnosticMessages = { severity: DiagnosticSeverity.Error }), detectedTooDeepFileSource: (numberOfParentDirectories: number) => ({ - message: `Expected directory depth no larger than 7, but found ${numberOfParentDirectories}.`, + message: `Expected directory depth no larger than 7, but found ${numberOfParentDirectories}`, code: 1134, severity: DiagnosticSeverity.Error }), @@ -709,6 +709,11 @@ export let DiagnosticMessages = { message: `${keyword} must be declared at the root level or within a namespace`, code: 1136, severity: DiagnosticSeverity.Error + }), + namespaceCannotBeReferencedDirectly: () => ({ + message: `Namespace cannot be referenced directly`, + code: 1137, + severity: DiagnosticSeverity.Error }) }; diff --git a/src/Scope.spec.ts b/src/Scope.spec.ts index 8e8d08ab2..ee9cbad33 100644 --- a/src/Scope.spec.ts +++ b/src/Scope.spec.ts @@ -119,7 +119,8 @@ describe('Scope', () => { program.validate(); expectDiagnostics(program, [ DiagnosticMessages.variableMayNotHaveSameNameAsNamespace('namea'), - DiagnosticMessages.variableMayNotHaveSameNameAsNamespace('NAMEA') + DiagnosticMessages.variableMayNotHaveSameNameAsNamespace('NAMEA'), + DiagnosticMessages.namespaceCannotBeReferencedDirectly() ]); }); diff --git a/src/bscPlugin/validation/ScopeValidator.ts b/src/bscPlugin/validation/ScopeValidator.ts index 87df3dc9b..297de5e5b 100644 --- a/src/bscPlugin/validation/ScopeValidator.ts +++ b/src/bscPlugin/validation/ScopeValidator.ts @@ -108,12 +108,12 @@ export class ScopeValidator { continue; } //catch unknown namespace items - const processedNames: string[] = [firstNamespacePart]; + let entityName = firstNamespacePart; + let entityNameLower = firstNamespacePart.toLowerCase(); for (let i = 1; i < info.parts.length; i++) { const part = info.parts[i]; - processedNames.push(part.name.text); - const entityName = processedNames.join('.'); - const entityNameLower = entityName.toLowerCase(); + entityName += '.' + part.name.text; + entityNameLower += '.' + part.name.text.toLowerCase(); //if this is an enum member, stop validating here to prevent errors further down the chain if (scope.getEnumMemberMap().has(entityNameLower)) { @@ -153,6 +153,14 @@ export class ScopeValidator { continue outer; } } + //if the full expression is a namespace path, this is an illegal statement because namespaces don't exist at runtme + if (scope.namespaceLookup.has(entityNameLower)) { + this.addMultiScopeDiagnostic({ + ...DiagnosticMessages.namespaceCannotBeReferencedDirectly(), + range: info.expression.range, + file: file + }, 'When used in scope'); + } } } diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts index e28579fca..cddb07581 100644 --- a/src/files/BrsFile.spec.ts +++ b/src/files/BrsFile.spec.ts @@ -68,6 +68,37 @@ describe('BrsFile', () => { }); }); + it('flags namespaces used as variables', () => { + program.setFile('source/main.bs', ` + sub main() + alpha.beta.charlie.test() + print alpha + print alpha.beta + print alpha.beta.charlie + end sub + + namespace alpha + namespace beta + namespace charlie + sub test() + end sub + end namespace + end namespace + end namespace + `); + program.validate(); + expectDiagnostics(program, [{ + ...DiagnosticMessages.namespaceCannotBeReferencedDirectly(), + range: util.createRange(3, 22, 3, 27) + }, { + ...DiagnosticMessages.namespaceCannotBeReferencedDirectly(), + range: util.createRange(4, 22, 4, 32) + }, { + ...DiagnosticMessages.namespaceCannotBeReferencedDirectly(), + range: util.createRange(5, 22, 5, 40) + }]); + }); + it('supports the third parameter in CreateObject', () => { program.setFile('source/main.brs', ` sub main()