diff --git a/docs/readme.md b/docs/readme.md index 44a410938..d8b21ce98 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -111,7 +111,10 @@ authStatus = user <> invalid ? "logged in" : "not logged in" ## [Union Types](union-types.md) ```brighterscript -sub log(data as string or number) +sub logData(data as string or number) print data.toStr() end sub -``` \ No newline at end of file +``` + +## [Variable Shadowing](variable-shadowing.md) +Name resolution rules for various types of shadowing. \ No newline at end of file diff --git a/docs/variable-shadowing.md b/docs/variable-shadowing.md new file mode 100644 index 000000000..a392b30d0 --- /dev/null +++ b/docs/variable-shadowing.md @@ -0,0 +1,104 @@ +# Variable Shadowing and Name Collisions in BrighterScript + +BrighterScript allows various kinds of [variable name shadowing](https://en.wikipedia.org/wiki/Variable_shadowing). In general, variables and types refer to items defined in the current scope/namespace if available. + +However, due to the limitations of BrightScript, there are some name collisions that lead to unpredictable behavior, and so they cause diagnostic errors. + +## Name Resolution Rules + +**1. Local variables CAN shadow names of global functions.** + +✅ + +```brighterscipt +sub test() + log = "value" ' identifier shadows global function log() - no error + upTime = 0 ' identifier shadows global function Uptime() - no error +end sub +``` + +**2. Local variables CANNOT shadow names of functions or classes defined at the same scope.** + +❌ + +```brighterscipt +sub test() + pi = "Apple" ' identifier shadows function pi() - causes validation error + data = 1234 ' identifier shadows class Data - causes validation error +end sub + +function pi() as float + return 3.14 +function + +class Data + value = {} +end class +``` + +**3. Custom types and definitions (enums, classes, interfaces, functions, consts) CANNOT have the same name if they are in the same namespace.** + +❌ + +```brighterscipt +function someName() +end function + +class SomeName ' class shadows local function - causes validation error + sub foo() + end sub +end class + +namespace alpha + class OtherName ' class in namespace shadows function in same namespace - causes validation error + sub foo() + end sub + end class + + function otherName() + end function +end namespace +``` + +**4. Functions and classes outside of namespaces CANNOT shadow standard global functions (eg. `ParseJson`, `LCase`, etc.)** + +❌ + +```brighterscipt +class log ' class shadows global function - causes validation error + sub foo() + end sub +end class + + +``` + +**5. Definitions inside namespaces CAN shadow standard global functions, or functions at a difference namespace-level. In this way, the outer item is unavailable, and only the item defined at the current scope is accessible.** + +✅ + +```brighterscipt +class SomeName() +end class + +namespace alpha + class SomeName ' class in namespace shadows function in upper scope + sub foo() + print "foo" + end sub + end class + + sub test() + myKlass = new SomeName() ' refers to alpha.SomeName + myKlass.foo() ' will print "foo" + end sub + + sub log(data) ' function defined as alpha.log - this is ok + print "LOG: ";data + end sub + + sub foo() + log("Hello world") ' refers to alpha.log - will print "LOG: Hello world" + end sub +end namespace +``` diff --git a/src/AstValidationSegmenter.ts b/src/AstValidationSegmenter.ts index 3f0bbbb20..a04cef576 100644 --- a/src/AstValidationSegmenter.ts +++ b/src/AstValidationSegmenter.ts @@ -1,11 +1,11 @@ import type { DottedGetExpression, TypeExpression, VariableExpression } from './parser/Expression'; -import { SymbolTypeFlag } from './SymbolTableFlag'; import { isBody, isClassStatement, isInterfaceStatement, isNamespaceStatement, isVariableExpression } from './astUtils/reflection'; import { ChildrenSkipper, WalkMode, createVisitor } from './astUtils/visitors'; import type { GetTypeOptions, TypeChainEntry } from './interfaces'; import type { AstNode } from './parser/AstNode'; import { util } from './util'; import type { NamespaceStatement } from './parser/Statement'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; // eslint-disable-next-line no-bitwise export const InsideSegmentWalkMode = WalkMode.visitStatements | WalkMode.visitExpressions | WalkMode.recurseChildFunctions; diff --git a/src/DiagnosticMessages.ts b/src/DiagnosticMessages.ts index 2337f9b26..81cc6e99a 100644 --- a/src/DiagnosticMessages.ts +++ b/src/DiagnosticMessages.ts @@ -3,7 +3,7 @@ import { DiagnosticSeverity } from 'vscode-languageserver'; import type { BsDiagnostic, TypeCompatibilityData } from './interfaces'; import { TokenKind } from './lexer/TokenKind'; import util from './util'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; /** * An object that keeps track of all possible error messages. diff --git a/src/Program.spec.ts b/src/Program.spec.ts index 7c16f0fdc..dcb72e1e5 100644 --- a/src/Program.spec.ts +++ b/src/Program.spec.ts @@ -21,7 +21,7 @@ import * as path from 'path'; import type { SinonSpy } from 'sinon'; import { createSandbox } from 'sinon'; import type { AfterFileAddEvent, AfterFileRemoveEvent, AfterProvideFileEvent, BeforeFileAddEvent, BeforeFileRemoveEvent, BeforeProvideFileEvent, CompilerPlugin, ProvideFileEvent } from './interfaces'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { StringType } from './types/StringType'; import { TypedFunctionType } from './types/TypedFunctionType'; import { DynamicType } from './types/DynamicType'; diff --git a/src/Program.ts b/src/Program.ts index 605f739b3..8893ae52c 100644 --- a/src/Program.ts +++ b/src/Program.ts @@ -28,7 +28,7 @@ import { SignatureHelpUtil } from './bscPlugin/SignatureHelpUtil'; import { DiagnosticSeverityAdjuster } from './DiagnosticSeverityAdjuster'; import { IntegerType } from './types/IntegerType'; import { StringType } from './types/StringType'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { BooleanType } from './types/BooleanType'; import { DoubleType } from './types/DoubleType'; import { DynamicType } from './types/DynamicType'; diff --git a/src/Scope.spec.ts b/src/Scope.spec.ts index f2b83805a..5be4a386a 100644 --- a/src/Scope.spec.ts +++ b/src/Scope.spec.ts @@ -11,7 +11,7 @@ import type { BrsFile } from './files/BrsFile'; import type { NamespaceStatement } from './parser/Statement'; import type { CompilerPlugin, OnScopeValidateEvent } from './interfaces'; import { DiagnosticOrigin } from './interfaces'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { EnumMemberType, EnumType } from './types/EnumType'; import { ClassType } from './types/ClassType'; import { BooleanType } from './types/BooleanType'; @@ -145,7 +145,7 @@ describe('Scope', () => { ]); }); - it('does flag namespaced const and un-namespaced function collision', () => { + it('does not flag namespaced const and un-namespaced function collision', () => { program.setFile('source/main.bs', ` namespace alpha const options = {} @@ -155,9 +155,7 @@ describe('Scope', () => { end sub `); program.validate(); - expectDiagnostics(program, [ - DiagnosticMessages.nameCollision('Const', 'Function', 'options').message - ]); + expectZeroDiagnostics(program); }); it('flags parameter with same name as namespace', () => { @@ -1265,7 +1263,7 @@ describe('Scope', () => { }); describe('name collisions', () => { - it('should validate when class and interfaces have name collisions', () => { + it('should validate when class have name collisions with global function', () => { program.setFile('source/main.bs', ` class Log end class @@ -1277,11 +1275,21 @@ describe('Scope', () => { `); program.validate(); expectDiagnosticsIncludes(program, [ - DiagnosticMessages.nameCollision('Class', 'Global Function', 'Log').message, - DiagnosticMessages.nameCollision('Interface', 'Global Function', 'Lcase').message + DiagnosticMessages.nameCollision('Class', 'Global Function', 'Log').message ]); }); + it('should not validate when interfaces have name collisions with global function', () => { + program.setFile('source/main.bs', ` + interface Lcase + name as string + end interface + + `); + program.validate(); + expectZeroDiagnostics(program); + }); + it('should validate when a namespace has a name collision with a class', () => { program.setFile('source/main.bs', ` namespace SomeKlass @@ -1342,7 +1350,7 @@ describe('Scope', () => { ]); }); - it('should validate when a const has a name collision with something else', () => { + it('should not validate when a const has a name collision with something else in different namespace', () => { program.setFile('source/main.bs', ` namespace SomeEnum const MY_CONST = "hello" @@ -1353,6 +1361,20 @@ describe('Scope', () => { `); program.validate(); let diagnostics = program.getDiagnostics(); + expectZeroDiagnostics(diagnostics); + }); + + it('should validate when a const has a name collision with something else in same namespace', () => { + program.setFile('source/main.bs', ` + namespace SomeEnum + const MY_CONST = "hello" + + function MY_CONST() + end function + end namespace + `); + program.validate(); + let diagnostics = program.getDiagnostics(); expectDiagnosticsIncludes(diagnostics, [ DiagnosticMessages.nameCollision('Const', 'Function', 'MY_CONST').message ]); @@ -3757,6 +3779,275 @@ describe('Scope', () => { }); + describe('shadowing', () => { + it('allows namespaces shadowing global function names', () => { + program.setFile('source/file1.bs', ` + namespace log + sub doLog(x) + ? x + end sub + end namespace + `); + program.setFile('source/file2.bs', ` + sub foo() + log.doLog("hello") + end sub + `); + + program.validate(); + expectZeroDiagnostics(program); + }); + + it('allows enums shadowing global function names', () => { + program.setFile('source/file1.bs', ` + enum log + debug = "DEBUG" + error = "ERROR" + end enum + `); + program.setFile('source/file2.bs', ` + sub foo(message) + print log.debug;" ";message + end sub + `); + + program.validate(); + expectZeroDiagnostics(program); + }); + + it('allows interfaces shadowing global function names', () => { + program.setFile('source/file1.bs', ` + interface log + abs + function formatJson(input) + end interface + `); + program.setFile('source/file2.bs', ` + sub foo(logger as log) + print logger.abs;" ";logger.formatJson("message") + end sub + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('allows consts shadowing global function names', () => { + program.setFile('source/file1.bs', ` + const log = "hello" ' const shadows global function + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + + it('disallows enum/const shadowing', () => { + program.setFile('source/file1.bs', ` + enum SomeName + opt1 + opt2 + end enum + + const SomeName = "hello" ' const and enum have same name + `); + program.validate(); + expectDiagnostics(program, [ + DiagnosticMessages.nameCollision('Enum', 'Const', 'SomeName').message, + DiagnosticMessages.nameCollision('Const', 'Enum', 'SomeName').message + ]); + }); + + it('disallows enum/namespace shadowing', () => { + program.setFile('source/file1.bs', ` + enum SomeName + opt1 + opt2 + end enum + + namespace SomeName + sub foo() + end sub + end namespace + `); + program.validate(); + expectDiagnostics(program, [ + DiagnosticMessages.nameCollision('Enum', 'Namespace', 'SomeName').message, + DiagnosticMessages.nameCollision('Namespace', 'Enum', 'SomeName').message + ]); + }); + + it('disallows interface/namespace shadowing', () => { + program.setFile('source/file1.bs', ` + interface SomeName ' interface has same name as namespace + opt1 + opt2 + end interface + + namespace SomeName + sub foo() + end sub + end namespace + `); + program.validate(); + expectDiagnostics(program, [ + DiagnosticMessages.nameCollision('Interface', 'Namespace', 'SomeName').message, + DiagnosticMessages.nameCollision('Namespace', 'Interface', 'SomeName').message + ]); + }); + + it('disallows class/namespace shadowing', () => { + program.setFile('source/file1.bs', ` + class SomeName ' class has same name as namespace + opt1 + opt2 + end class + + namespace SomeName + sub foo() + end sub + end namespace + `); + program.validate(); + expectDiagnostics(program, [ + DiagnosticMessages.nameCollision('Class', 'Namespace', 'SomeName').message, + DiagnosticMessages.nameCollision('Namespace', 'Class', 'SomeName').message + ]); + }); + + it('allows namespaced functions shadowing upper scope function names', () => { + program.setFile('source/file.bs', ` + namespace alpha + sub log(input) + print "in namespace" + end sub + + sub test() + log(44) ' prints "in namespace" + end sub + end namespace + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('allows namespaced functions shadowing upper scope function names', () => { + program.setFile('source/file.bs', ` + sub someFunc() + print "outside" + end sub + + namespace alpha + sub someFunc() + print "inside" + end sub + + sub test() + someFunc() ' prints "inside" + end sub + end namespace + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('disallows class/global function shadowing', () => { + program.setFile('source/file.bs', ` + class log ' class shadows global function + sub foo() + end sub + end class + `); + program.validate(); + expectDiagnostics(program, [ + DiagnosticMessages.nameCollision('Class', 'Global Function', 'log') + ]); + }); + + it('disallows class/local function shadowing', () => { + program.setFile('source/file.bs', ` + function someName() + end function + + class SomeName ' class shadows local function + sub foo() + end sub + end class + `); + program.validate(); + expectDiagnostics(program, [ + DiagnosticMessages.functionCannotHaveSameNameAsClass('someName'), + DiagnosticMessages.nameCollision('Class', 'Function', 'SomeName') + ]); + }); + + + it('allows function having same name as class in namespace', () => { + program.setFile('source/file.bs', ` + function someName() + end function + + namespace alpha + class SomeName ' class in namespace shadows function in upper scope + sub foo() + end sub + end class + end namespace + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('allows class in namespace having same name as global function', () => { + program.setFile('source/file.bs', ` + namespace alpha + class log ' class in namespace shadows global function + text = "hello" + end class + + sub foo() + myLog = new Log() + print myLog.text ' prints "hello" + end sub + end namespace + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('disallows reusing a class name as "for each" variable in a function', () => { + program.setFile('source/file.bs', ` + class Person + name as string + end class + + sub foo(people as Person[]) + for each person in people + print person.name + end for + end sub + `); + program.validate(); + expectDiagnosticsIncludes(program, DiagnosticMessages.localVarSameNameAsClass('Person').message); + }); + + it('disallows reusing a class name as "for each" variable in a method', () => { + program.setFile('source/file.bs', ` + class Person + name as string + children as Person[] + + sub test() + for each person in m.children + print person.name + end for + end sub + end class + `); + program.validate(); + expectDiagnosticsIncludes(program, DiagnosticMessages.localVarSameNameAsClass('Person').message); + }); + }); + + describe('performance', () => { // eslint-disable-next-line func-names, prefer-arrow-callback diff --git a/src/Scope.ts b/src/Scope.ts index 0ac6eacdb..cf5c1053c 100644 --- a/src/Scope.ts +++ b/src/Scope.ts @@ -4,10 +4,10 @@ import chalk from 'chalk'; import type { DiagnosticInfo } from './DiagnosticMessages'; import { DiagnosticMessages } from './DiagnosticMessages'; import { DiagnosticOrigin } from './interfaces'; -import type { CallableContainer, BsDiagnosticWithOrigin, FileReference, CallableContainerMap, FileLink, Callable, NamespaceContainer, ScopeValidationOptions, BsDiagnostic } from './interfaces'; +import type { CallableContainer, BsDiagnosticWithOrigin, FileReference, FileLink, Callable, NamespaceContainer, ScopeValidationOptions, BsDiagnostic } from './interfaces'; import type { Program } from './Program'; import { BsClassValidator } from './validators/ClassValidator'; -import type { NamespaceStatement, ClassStatement, EnumStatement, InterfaceStatement, EnumMemberStatement, ConstStatement } from './parser/Statement'; +import { type NamespaceStatement, type ClassStatement, type EnumStatement, type InterfaceStatement, type EnumMemberStatement, type ConstStatement } from './parser/Statement'; import { ParseMode } from './parser/Parser'; import { util } from './util'; import { globalCallableMap } from './globalCallables'; @@ -16,9 +16,9 @@ import { URI } from 'vscode-uri'; import { LogLevel } from './Logger'; import type { BrsFile } from './files/BrsFile'; import type { DependencyGraph, DependencyChangedEvent } from './DependencyGraph'; -import { isBrsFile, isXmlFile, isEnumMemberStatement, isNamespaceStatement, isNamespaceType, isReferenceType, isCallableType, isFunctionStatement } from './astUtils/reflection'; +import { isBrsFile, isXmlFile, isEnumMemberStatement, isNamespaceStatement, isNamespaceType, isReferenceType, isCallableType, isFunctionStatement, isEnumStatement, isConstStatement, isInterfaceStatement } from './astUtils/reflection'; import { SymbolTable } from './SymbolTable'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import type { BscFile } from './files/BscFile'; import type { BscType } from './types/BscType'; import { NamespaceType } from './types/NamespaceType'; @@ -26,9 +26,9 @@ import { referenceTypeFactory } from './types/ReferenceType'; import { unionTypeFactory } from './types/UnionType'; import { AssociativeArrayType } from './types/AssociativeArrayType'; import type { AstNode, Statement } from './parser/AstNode'; -import { AstNodeKind } from './parser/AstNode'; import { WalkMode, createVisitor } from './astUtils/visitors'; import type { Token } from './lexer/Token'; +import type { Range } from 'vscode-languageserver'; /** * Assign some few factories to the SymbolTable to prevent cyclical imports. This file seems like the most intuitive place to do the linking @@ -69,6 +69,7 @@ export class Scope { * "namea", "namea.nameb", "namea.nameb.namec" */ public get namespaceLookup() { + let allFilesValidated = true; for (const file of this.getAllFiles()) { if (isBrsFile(file) && !file.hasTypedef) { @@ -83,7 +84,6 @@ export class Scope { // Since the files have not been validated, all namespace info might not have been available return this.buildNamespaceLookup(); } - return this.cache.getOrAdd('namespaceLookup', () => this.buildNamespaceLookup()); } @@ -248,14 +248,19 @@ export class Scope { return result; } - public getAllFileLinks(name: string, containingNamespace?: string): FileLink[] { + public getAllFileLinks(name: string, containingNamespace?: string, includeNameShadowsOutsideNamespace = false): FileLink[] { let links: FileLink[] = []; - links.push(this.getClassFileLink(name) ?? this.getClassFileLink(name, containingNamespace), - this.getInterfaceFileLink(name) ?? this.getInterfaceFileLink(name, containingNamespace), - this.getConstFileLink(name) ?? this.getConstFileLink(name, containingNamespace), - this.getEnumFileLink(name) ?? this.getEnumFileLink(name, containingNamespace)); - + links.push(this.getClassFileLink(name, containingNamespace), + this.getInterfaceFileLink(name, containingNamespace), + this.getConstFileLink(name, containingNamespace), + this.getEnumFileLink(name, containingNamespace)); + if (includeNameShadowsOutsideNamespace && containingNamespace) { + links.push(this.getClassFileLink(name), + this.getInterfaceFileLink(name), + this.getConstFileLink(name), + this.getEnumFileLink(name)); + } const nameSpaces = this.getNamespacesWithRoot(name, containingNamespace); if (nameSpaces?.length > 0) { @@ -267,7 +272,7 @@ export class Scope { const fullNameLower = (containingNamespace ? `${containingNamespace}.${name}` : name).toLowerCase(); const callable = this.getCallableByName(name); if (callable) { - if (!callable.hasNamespace || callable.getName(ParseMode.BrighterScript).toLowerCase() === fullNameLower) { + if ((!callable.hasNamespace && includeNameShadowsOutsideNamespace) || callable.getName(ParseMode.BrighterScript).toLowerCase() === fullNameLower) { // this callable has no namespace, or has same namespace links.push({ item: callable.functionStatement, file: callable.file as BrsFile }); } @@ -594,6 +599,37 @@ export class Scope { }); } + public getCallableContainerMap() { + return this.cache.getOrAdd('callableContainerMap', () => { + let callables = this.getAllCallables(); + + //sort the callables by filepath and then method name, so the errors will be consistent + // eslint-disable-next-line prefer-arrow-callback + callables = callables.sort((a, b) => { + const pathA = a.callable.file.srcPath; + const pathB = b.callable.file.srcPath; + //sort by path + if (pathA < pathB) { + return -1; + } else if (pathA > pathB) { + return 1; + } + //sort by function name + const funcA = b.callable.name; + const funcB = b.callable.name; + if (funcA < funcB) { + return -1; + } else if (funcA > funcB) { + return 1; + } + return 0; + }); + + //get a list of all callables, indexed by their lower case names + return util.getCallableContainersByLowerName(callables); + }); + } + /** * Iterate over Brs files not shadowed by typedefs */ @@ -709,32 +745,7 @@ export class Scope { //clear the scope's errors list (we will populate them from this method) this.clearScopeLevelDiagnostics(); - let callables = this.getAllCallables(); - - //sort the callables by filepath and then method name, so the errors will be consistent - // eslint-disable-next-line prefer-arrow-callback - callables = callables.sort((a, b) => { - const pathA = a.callable.file.srcPath; - const pathB = b.callable.file.srcPath; - //sort by path - if (pathA < pathB) { - return -1; - } else if (pathA > pathB) { - return 1; - } - //sort by function name - const funcA = b.callable.name; - const funcB = b.callable.name; - if (funcA < funcB) { - return -1; - } else if (funcA > funcB) { - return 1; - } - return 0; - }); - //get a list of all callables, indexed by their lower case names - let callableContainerMap = util.getCallableContainersByLowerName(callables); //Since statements from files are shared across multiple scopes, we need to link those statements to the current scope this.linkSymbolTable(); const scopeValidateEvent = { @@ -745,7 +756,7 @@ export class Scope { }; this.program.plugins.emit('beforeScopeValidate', scopeValidateEvent); this.program.plugins.emit('onScopeValidate', scopeValidateEvent); - this._validate(callableContainerMap); + this._validate(); this.program.plugins.emit('afterScopeValidate', scopeValidateEvent); //unlink all symbol tables from this scope (so they don't accidentally stick around) this.unlinkSymbolTable(); @@ -754,9 +765,9 @@ export class Scope { }); } - protected _validate(callableContainerMap: CallableContainerMap) { + protected _validate() { //find all duplicate function declarations - this.diagnosticFindDuplicateFunctionDeclarations(callableContainerMap); + this.diagnosticFindDuplicateFunctionDeclarations(); //detect missing and incorrect-case script imports this.diagnosticValidateScriptImportPaths(); @@ -766,7 +777,6 @@ export class Scope { //do many per-file checks this.enumerateBrsFiles((file) => { - this.diagnosticDetectShadowedLocalVars(file, callableContainerMap); this.diagnosticDetectFunctionCollisions(file); this.detectVariableNamespaceCollisions(file); this.detectNameCollisions(file); @@ -848,7 +858,6 @@ export class Scope { // eslint-disable-next-line no-bitwise let getTypeOptions = { flags: SymbolTypeFlag.runtime | SymbolTypeFlag.typetime }; - for (const [nsName, nsContainer] of this.namespaceLookup) { let currentNSType: BscType = null; let parentNSType: BscType = null; @@ -879,7 +888,7 @@ export class Scope { this.symbolsAddedDuringLinking.push({ symbolTable: this.symbolTable, name: nsContainer.lastPartName, flags: getTypeOptions.flags }); } } else { - this.program.logger.error(`Invalid existing type for namespace ${nsName} - ${currentNSType.toString()}`); + // Something else already used the name this namespace is using. continue; } } else { @@ -1016,9 +1025,24 @@ export class Scope { }, EnumStatement: (enumStmt) => { this.validateNameCollision(file, enumStmt, enumStmt.tokens.name); + }, + AssignmentStatement: (assignStmt) => { + // Note: this also includes For statements + this.detectShadowedLocalVar(file, { + name: assignStmt.tokens.name.text, + type: assignStmt.getType({ flags: SymbolTypeFlag.runtime }), + nameRange: assignStmt.tokens.name.range + }); + }, + ForEachStatement: (forEachStmt) => { + this.detectShadowedLocalVar(file, { + name: forEachStmt.tokens.item.text, + type: forEachStmt.getType({ flags: SymbolTypeFlag.runtime }), + nameRange: forEachStmt.tokens.item.range + }); } }), { - walkMode: WalkMode.visitStatements + walkMode: WalkMode.visitAllRecursive }); } @@ -1031,6 +1055,7 @@ export class Scope { const nameRange = nameIdentifier.range; const containingNamespace = node.findAncestor(isNamespaceStatement)?.getName(ParseMode.BrighterScript); + const containingNamespaceLower = containingNamespace?.toLowerCase(); const links = this.getAllFileLinks(name, containingNamespace); for (let link of links) { if (!link || link.item === node) { @@ -1042,10 +1067,17 @@ export class Scope { continue; } if (isFunctionStatement(link.item) || link.file?.destPath === 'global') { - // the thing found is a function OR from global (which is also a function) - if (isNamespaceStatement(node)) { - // these are not callable functions in transpiled code - ignore them - continue; + const linkItemNamespaceLower = link.item?.findAncestor(isNamespaceStatement)?.getName(ParseMode.BrighterScript)?.toLowerCase(); + if (!(containingNamespaceLower && linkItemNamespaceLower) || linkItemNamespaceLower !== containingNamespaceLower) { + + // the thing found is a function OR from global (which is also a function) + if (isNamespaceStatement(node) || + isEnumStatement(node) || + isConstStatement(node) || + isInterfaceStatement(node)) { + // these are not callable functions in transpiled code - ignore them + continue; + } } } @@ -1054,16 +1086,8 @@ export class Scope { let thatNameRange = (link.item as any)?.tokens?.name?.range ?? link.item?.range; - // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check - switch (link.item?.kind) { - case AstNodeKind.ClassStatement: { - thatNameRange = (link.item as ClassStatement).tokens.name?.range; - break; - } - case AstNodeKind.NamespaceStatement: { - thatNameRange = (link.item as NamespaceStatement).getNameParts()?.[0]?.range; - break; - } + if (isNamespaceStatement(link.item)) { + thatNameRange = (link.item as NamespaceStatement).getNameParts()?.[0]?.range; } const relatedInformation = thatNameRange ? [{ @@ -1093,71 +1117,88 @@ export class Scope { })); } - /** - * Detect local variables (function scope) that have the same name as scope calls - */ - private diagnosticDetectShadowedLocalVars(file: BrsFile, callableContainerMap: CallableContainerMap) { + + private detectShadowedLocalVar(file: BrsFile, varDeclaration: { name: string; type: BscType; nameRange: Range }) { + const varName = varDeclaration.name; + const lowerVarName = varName.toLowerCase(); const classMap = this.getClassMap(); - //loop through every function scope - for (let funcScope of file.functionScopes) { - //every var declaration in this function scope - for (let varDeclaration of funcScope.variableDeclarations) { - const varName = varDeclaration.name; - const lowerVarName = varName.toLowerCase(); - - const varIsFunction = () => { - return isCallableType(varDeclaration.getType()); - }; - - if ( - //has same name as stdlib - globalCallableMap.has(lowerVarName) - ) { - //local var function with same name as stdlib function - if (varIsFunction()) { - this.diagnostics.push({ - ...DiagnosticMessages.localVarFunctionShadowsParentFunction('stdlib'), - range: varDeclaration.nameRange, - file: file, - origin: DiagnosticOrigin.Scope - }); - } - } else if (callableContainerMap.has(lowerVarName)) { - //is same name as a callable - if (varIsFunction()) { - this.diagnostics.push({ - ...DiagnosticMessages.localVarFunctionShadowsParentFunction('scope'), - range: varDeclaration.nameRange, - file: file, - origin: DiagnosticOrigin.Scope - }); - } else { - this.diagnostics.push({ - ...DiagnosticMessages.localVarShadowedByScopedFunction(), - range: varDeclaration.nameRange, - file: file, - origin: DiagnosticOrigin.Scope - }); - } - //has the same name as an in-scope class - } else if (classMap.has(lowerVarName)) { - this.diagnostics.push({ - ...DiagnosticMessages.localVarSameNameAsClass(classMap.get(lowerVarName)?.item.getName(ParseMode.BrighterScript)), - range: varDeclaration.nameRange, - file: file, - origin: DiagnosticOrigin.Scope - }); - } + const callableContainerMap = this.getCallableContainerMap(); + + const varIsFunction = () => { + return isCallableType(varDeclaration.type); + }; + + if ( + //has same name as stdlib + globalCallableMap.has(lowerVarName) + ) { + //local var function with same name as stdlib function + if (varIsFunction()) { + this.diagnostics.push({ + ...DiagnosticMessages.localVarFunctionShadowsParentFunction('stdlib'), + range: varDeclaration.nameRange, + file: file, + origin: DiagnosticOrigin.Scope + }); + } + } else if (callableContainerMap.has(lowerVarName)) { + const callable = callableContainerMap.get(lowerVarName); + //is same name as a callable + if (varIsFunction()) { + this.diagnostics.push({ + ...DiagnosticMessages.localVarFunctionShadowsParentFunction('scope'), + range: varDeclaration.nameRange, + file: file, + origin: DiagnosticOrigin.Scope, + relatedInformation: [{ + message: 'Function declared here', + location: util.createLocation( + URI.file(callable[0].callable.file.srcPath).toString(), + callable[0].callable.nameRange + ) + }] + }); + } else { + this.diagnostics.push({ + ...DiagnosticMessages.localVarShadowedByScopedFunction(), + range: varDeclaration.nameRange, + file: file, + origin: DiagnosticOrigin.Scope, + relatedInformation: [{ + message: 'Function declared here', + location: util.createLocation( + URI.file(callable[0].callable.file.srcPath).toString(), + callable[0].callable.nameRange + ) + }] + }); } + //has the same name as an in-scope class + } else if (classMap.has(lowerVarName)) { + const classStmtLink = classMap.get(lowerVarName); + this.diagnostics.push({ + ...DiagnosticMessages.localVarSameNameAsClass(classStmtLink?.item?.getName(ParseMode.BrighterScript)), + range: varDeclaration.nameRange, + file: file, + origin: DiagnosticOrigin.Scope, + relatedInformation: [{ + message: 'Class declared here', + location: util.createLocation( + URI.file(classStmtLink.file.srcPath).toString(), + classStmtLink?.item.tokens.name.range + ) + }] + }); } } /** * Create diagnostics for any duplicate function declarations */ - private diagnosticFindDuplicateFunctionDeclarations(callableContainersByLowerName: CallableContainerMap) { + private diagnosticFindDuplicateFunctionDeclarations() { + //for each list of callables with the same name - for (let [lowerName, callableContainers] of callableContainersByLowerName) { + for (let [lowerName, callableContainers] of this.getCallableContainerMap()) { let globalCallables = [] as CallableContainer[]; let nonGlobalCallables = [] as CallableContainer[]; diff --git a/src/SymbolTable.spec.ts b/src/SymbolTable.spec.ts index a8c4974d8..698eff1cb 100644 --- a/src/SymbolTable.spec.ts +++ b/src/SymbolTable.spec.ts @@ -3,7 +3,7 @@ import { expect } from './chai-config.spec'; import { StringType } from './types/StringType'; import { IntegerType } from './types/IntegerType'; import { BooleanType } from './types/BooleanType'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { expectTypeToBe } from './testHelpers.spec'; describe('SymbolTable', () => { diff --git a/src/SymbolTable.ts b/src/SymbolTable.ts index fa1d2eba3..2856942cc 100644 --- a/src/SymbolTable.ts +++ b/src/SymbolTable.ts @@ -5,7 +5,7 @@ import type { ReferenceType } from './types/ReferenceType'; import type { UnionType } from './types/UnionType'; import { getUniqueType } from './types/helpers'; import { isAnyReferenceType, isReferenceType } from './astUtils/reflection'; -import type { SymbolTypeFlag } from './SymbolTableFlag'; +import type { SymbolTypeFlag } from './SymbolTypeFlag'; /** * Stores the types associated with variables and functions in the Brighterscript code diff --git a/src/SymbolTableFlag.ts b/src/SymbolTypeFlag.ts similarity index 100% rename from src/SymbolTableFlag.ts rename to src/SymbolTypeFlag.ts diff --git a/src/XmlScope.spec.ts b/src/XmlScope.spec.ts index 6d7ce6e3a..0ed337c01 100644 --- a/src/XmlScope.spec.ts +++ b/src/XmlScope.spec.ts @@ -8,7 +8,7 @@ import { standardizePath as s, util } from './util'; let rootDir = s`${process.cwd()}/rootDir`; import { createSandbox } from 'sinon'; import { ComponentType } from './types/ComponentType'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { AssociativeArrayType } from './types/AssociativeArrayType'; import { ArrayType, BooleanType, DoubleType, DynamicType, FloatType, IntegerType, StringType, TypedFunctionType, UnionType } from './types'; const sinon = createSandbox(); diff --git a/src/XmlScope.ts b/src/XmlScope.ts index 5d1f6b2e5..7fea08aff 100644 --- a/src/XmlScope.ts +++ b/src/XmlScope.ts @@ -1,13 +1,13 @@ import { Scope } from './Scope'; import { DiagnosticMessages } from './DiagnosticMessages'; import type { XmlFile } from './files/XmlFile'; -import type { CallableContainerMap, FileReference } from './interfaces'; +import type { FileReference } from './interfaces'; import { DiagnosticOrigin } from './interfaces'; import type { Program } from './Program'; import type { SGElement } from './parser/SGTypes'; import { SGFieldTypes } from './parser/SGTypes'; import util from './util'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import type { BscFile } from './files/BscFile'; import { DynamicType } from './types/DynamicType'; import type { BaseFunctionType } from './types/BaseFunctionType'; @@ -81,23 +81,23 @@ export class XmlScope extends Scope { return result; } - protected _validate(callableContainerMap: CallableContainerMap) { + protected _validate() { //validate brs files - super._validate(callableContainerMap); + super._validate(); //detect when the child imports a script that its ancestor also imports this.diagnosticDetectDuplicateAncestorScriptImports(); //validate component interface - this.diagnosticValidateInterface(callableContainerMap); + this.diagnosticValidateInterface(); } - private diagnosticValidateInterface(callableContainerMap: CallableContainerMap) { + private diagnosticValidateInterface() { if (!this.xmlFile.parser.ast?.componentElement?.interfaceElement) { return; } const iface = this.xmlFile.parser.ast.componentElement.interfaceElement; - + const callableContainerMap = this.getCallableContainerMap(); //validate functions for (const func of iface.functions) { const name = func.name; diff --git a/src/bscPlugin/completions/CompletionsProcessor.ts b/src/bscPlugin/completions/CompletionsProcessor.ts index cd1903ca2..eb4e9ab2e 100644 --- a/src/bscPlugin/completions/CompletionsProcessor.ts +++ b/src/bscPlugin/completions/CompletionsProcessor.ts @@ -9,7 +9,7 @@ import { ParseMode } from '../../parser/Parser'; import type { CompletionItem, Position } from 'vscode-languageserver'; import { CompletionItemKind, TextEdit } from 'vscode-languageserver'; import type { BscSymbol } from '../../SymbolTable'; -import { SymbolTypeFlag } from '../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../SymbolTypeFlag'; import type { XmlFile } from '../../files/XmlFile'; import type { Program } from '../../Program'; import type { BrsFile } from '../../files/BrsFile'; diff --git a/src/bscPlugin/hover/HoverProcessor.ts b/src/bscPlugin/hover/HoverProcessor.ts index 8c7e88068..bb29ac518 100644 --- a/src/bscPlugin/hover/HoverProcessor.ts +++ b/src/bscPlugin/hover/HoverProcessor.ts @@ -7,7 +7,7 @@ import { TokenKind } from '../../lexer/TokenKind'; import { BrsTranspileState } from '../../parser/BrsTranspileState'; import { ParseMode } from '../../parser/Parser'; import util from '../../util'; -import { SymbolTypeFlag } from '../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../SymbolTypeFlag'; import type { AstNode, Expression } from '../../parser/AstNode'; import type { Scope } from '../../Scope'; import type { FunctionScope } from '../../FunctionScope'; diff --git a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts index c06e8e6f7..601722de3 100644 --- a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts +++ b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts @@ -8,7 +8,7 @@ import type { Locatable } from '../../lexer/Token'; import { ParseMode } from '../../parser/Parser'; import type { NamespaceStatement } from '../../parser/Statement'; import util from '../../util'; -import { SymbolTypeFlag } from '../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../SymbolTypeFlag'; import type { BscType } from '../../types/BscType'; export class BrsFileSemanticTokensProcessor { diff --git a/src/bscPlugin/validation/BrsFileValidator.ts b/src/bscPlugin/validation/BrsFileValidator.ts index a0b4540ae..061d632b7 100644 --- a/src/bscPlugin/validation/BrsFileValidator.ts +++ b/src/bscPlugin/validation/BrsFileValidator.ts @@ -8,7 +8,7 @@ import type { AstNode, Expression, Statement } from '../../parser/AstNode'; import type { FunctionExpression, LiteralExpression } from '../../parser/Expression'; import { ParseMode } from '../../parser/Parser'; import type { ContinueStatement, EnumMemberStatement, EnumStatement, ForEachStatement, ForStatement, ImportStatement, LibraryStatement, WhileStatement } from '../../parser/Statement'; -import { SymbolTypeFlag } from '../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../SymbolTypeFlag'; import { AssociativeArrayType } from '../../types/AssociativeArrayType'; import { DynamicType } from '../../types/DynamicType'; import util from '../../util'; diff --git a/src/bscPlugin/validation/ScopeValidator.spec.ts b/src/bscPlugin/validation/ScopeValidator.spec.ts index 797099ebf..a9da2526e 100644 --- a/src/bscPlugin/validation/ScopeValidator.spec.ts +++ b/src/bscPlugin/validation/ScopeValidator.spec.ts @@ -8,7 +8,7 @@ import { IntegerType } from '../../types/IntegerType'; import { StringType } from '../../types/StringType'; import type { BrsFile } from '../../files/BrsFile'; import { FloatType } from '../../types'; -import { SymbolTypeFlag } from '../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../SymbolTypeFlag'; describe('ScopeValidator', () => { diff --git a/src/bscPlugin/validation/ScopeValidator.ts b/src/bscPlugin/validation/ScopeValidator.ts index 0f17b9a19..1f2db4998 100644 --- a/src/bscPlugin/validation/ScopeValidator.ts +++ b/src/bscPlugin/validation/ScopeValidator.ts @@ -5,7 +5,7 @@ import { DiagnosticMessages } from '../../DiagnosticMessages'; import type { BrsFile } from '../../files/BrsFile'; import { DiagnosticOrigin } from '../../interfaces'; import type { BsDiagnostic, BsDiagnosticWithOrigin, ExtraSymbolData, OnScopeValidateEvent, TypeChainEntry, TypeCompatibilityData } from '../../interfaces'; -import { SymbolTypeFlag } from '../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../SymbolTypeFlag'; import type { AssignmentStatement, ClassStatement, DottedSetStatement, EnumStatement, NamespaceStatement, ReturnStatement } from '../../parser/Statement'; import util from '../../util'; import { nodes, components } from '../../roku-types'; diff --git a/src/files/BrsFile.Class.spec.ts b/src/files/BrsFile.Class.spec.ts index c29abcca8..20fedfd76 100644 --- a/src/files/BrsFile.Class.spec.ts +++ b/src/files/BrsFile.Class.spec.ts @@ -1677,19 +1677,24 @@ describe('BrsFile BrighterScript classes', () => { ]); }); - it('catches namespaced class name which is the same as a global class', () => { + it('allows namespaced class name which is the same as a global class', () => { program.setFile('source/main.bs', ` namespace NameA.NameB class Animal + name as string end class + + sub printThisAnimalName(ani as Animal) ' this refers to NameA.NameB.Animal + print ani.name + end sub end namespace + class Animal + doesNotHaveName as string end class `); program.validate(); - expectDiagnostics(program, [ - DiagnosticMessages.nameCollision('Class', 'Class', 'Animal').message - ]); + expectZeroDiagnostics(program); }); it('catches class with same name as function', () => { diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts index 50908c1a6..fd9c6af92 100644 --- a/src/files/BrsFile.spec.ts +++ b/src/files/BrsFile.spec.ts @@ -21,7 +21,7 @@ import * as fsExtra from 'fs-extra'; import { URI } from 'vscode-uri'; import undent from 'undent'; import { tempDir, rootDir } from '../testHelpers.spec'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { ClassType, EnumType, FloatType, InterfaceType } from '../types'; import type { StandardizedFileEntry } from 'roku-deploy'; import * as fileUrl from 'file-url'; diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 4a59fe3be..22f3edc1e 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -30,7 +30,7 @@ import type { UnresolvedSymbol } from '../AstValidationSegmenter'; import { AstValidationSegmenter } from '../AstValidationSegmenter'; import type { BscSymbol } from '../SymbolTable'; import { SymbolTable } from '../SymbolTable'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import type { BscFileLike } from '../astUtils/CachedLookups'; import { CachedLookups } from '../astUtils/CachedLookups'; import { Editor } from '../astUtils/Editor'; diff --git a/src/interfaces.ts b/src/interfaces.ts index b484c3aa4..5e256f268 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -17,7 +17,7 @@ import type { BscFile } from './files/BscFile'; import type { FileFactory } from './files/Factory'; import type { LazyFileData } from './files/LazyFileData'; import type { SymbolTable } from './SymbolTable'; -import type { SymbolTypeFlag } from './SymbolTableFlag'; +import type { SymbolTypeFlag } from './SymbolTypeFlag'; import { createToken } from './astUtils/creators'; import { TokenKind } from './lexer/TokenKind'; diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index 9f9ac7555..b4e4a1c76 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -28,8 +28,8 @@ import { ArrayType } from '../types/ArrayType'; import { AssociativeArrayType } from '../types/AssociativeArrayType'; import type { ComponentType } from '../types/ComponentType'; import { createToken } from '../astUtils/creators'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; import { TypedFunctionType } from '../types'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; export type ExpressionVisitor = (expression: Expression, parent: Expression) => void; diff --git a/src/parser/Parser.Class.spec.ts b/src/parser/Parser.Class.spec.ts index af208b7c5..9e2d0a426 100644 --- a/src/parser/Parser.Class.spec.ts +++ b/src/parser/Parser.Class.spec.ts @@ -9,7 +9,7 @@ import { NewExpression } from './Expression'; import { expectDiagnosticsIncludes, expectZeroDiagnostics } from '../testHelpers.spec'; import { isClassStatement } from '../astUtils/reflection'; import { StringType } from '../types/StringType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; describe('parser class', () => { it('throws exception when used in brightscript scope', () => { diff --git a/src/parser/Parser.spec.ts b/src/parser/Parser.spec.ts index 370260b64..3a8c79d2a 100644 --- a/src/parser/Parser.spec.ts +++ b/src/parser/Parser.spec.ts @@ -12,7 +12,7 @@ import { isAssignmentStatement, isBinaryExpression, isBlock, isCallExpression, i import { expectDiagnosticsIncludes, expectTypeToBe, expectZeroDiagnostics } from '../testHelpers.spec'; import { createVisitor, WalkMode } from '../astUtils/visitors'; import type { Expression, Statement } from './AstNode'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { IntegerType } from '../types/IntegerType'; import { FloatType } from '../types/FloatType'; import { StringType } from '../types/StringType'; diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts index 77659b58a..3fbde335f 100644 --- a/src/parser/Statement.ts +++ b/src/parser/Statement.ts @@ -25,7 +25,7 @@ import { InterfaceType } from '../types/InterfaceType'; import { VoidType } from '../types/VoidType'; import { TypedFunctionType } from '../types/TypedFunctionType'; import { ArrayType } from '../types/ArrayType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; export class EmptyStatement extends Statement { constructor(options?: { range?: Range } diff --git a/src/parser/tests/expression/TypeExpression.spec.ts b/src/parser/tests/expression/TypeExpression.spec.ts index 69cb2e08b..4d0d9c3eb 100644 --- a/src/parser/tests/expression/TypeExpression.spec.ts +++ b/src/parser/tests/expression/TypeExpression.spec.ts @@ -3,7 +3,7 @@ import { ParseMode } from '../../Parser'; import { parse } from '../../Parser.spec'; import { expectTypeToBe, expectZeroDiagnostics } from '../../../testHelpers.spec'; import { isFunctionStatement, isReferenceType, isTypeExpression } from '../../../astUtils/reflection'; -import { SymbolTypeFlag } from '../../../SymbolTableFlag'; +import { SymbolTypeFlag } from '../../../SymbolTypeFlag'; import { IntegerType } from '../../../types/IntegerType'; import { StringType } from '../../../types/StringType'; import { UnionType } from '../../../types/UnionType'; diff --git a/src/types/ArrayType.spec.ts b/src/types/ArrayType.spec.ts index f5a6b9cd4..9732101c7 100644 --- a/src/types/ArrayType.spec.ts +++ b/src/types/ArrayType.spec.ts @@ -4,7 +4,7 @@ import { ArrayType } from './ArrayType'; import { DynamicType } from './DynamicType'; import { BooleanType } from './BooleanType'; import { StringType } from './StringType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { TypedFunctionType } from './TypedFunctionType'; import { expectTypeToBe } from '../testHelpers.spec'; import { IntegerType } from './IntegerType'; diff --git a/src/types/ArrayType.ts b/src/types/ArrayType.ts index 0966b470d..cce27f1b9 100644 --- a/src/types/ArrayType.ts +++ b/src/types/ArrayType.ts @@ -1,5 +1,5 @@ -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { isArrayType, isDynamicType, isObjectType } from '../astUtils/reflection'; import type { TypeCompatibilityData } from '../interfaces'; import { BscType } from './BscType'; diff --git a/src/types/AssociativeArrayType.ts b/src/types/AssociativeArrayType.ts index fc255f1ef..b0c286dfb 100644 --- a/src/types/AssociativeArrayType.ts +++ b/src/types/AssociativeArrayType.ts @@ -1,4 +1,4 @@ -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { isAssociativeArrayType, isClassType, isDynamicType, isObjectType } from '../astUtils/reflection'; import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces'; import { BscType } from './BscType'; diff --git a/src/types/BscType.ts b/src/types/BscType.ts index 5374ec62d..469e05bb9 100644 --- a/src/types/BscType.ts +++ b/src/types/BscType.ts @@ -1,6 +1,6 @@ import type { GetSymbolTypeOptions, SymbolTableProvider } from '../SymbolTable'; import { SymbolTable } from '../SymbolTable'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { BuiltInInterfaceAdder } from './BuiltInInterfaceAdder'; import type { ExtraSymbolData, TypeCompatibilityData } from '../interfaces'; import { isArrayType, isInheritableType, isReferenceType } from '../astUtils/reflection'; diff --git a/src/types/BuiltInInterfaceAdder.spec.ts b/src/types/BuiltInInterfaceAdder.spec.ts index 34c4cc98a..55a1a6a04 100644 --- a/src/types/BuiltInInterfaceAdder.spec.ts +++ b/src/types/BuiltInInterfaceAdder.spec.ts @@ -2,7 +2,7 @@ import { BuiltInInterfaceAdder } from './BuiltInInterfaceAdder'; import { StringType } from './StringType'; import { expectTypeToBe } from '../testHelpers.spec'; import { IntegerType } from './IntegerType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { TypedFunctionType } from './TypedFunctionType'; import { BooleanType } from './BooleanType'; import { FunctionType } from './FunctionType'; diff --git a/src/types/BuiltInInterfaceAdder.ts b/src/types/BuiltInInterfaceAdder.ts index dfd37d402..b6aeaa98f 100644 --- a/src/types/BuiltInInterfaceAdder.ts +++ b/src/types/BuiltInInterfaceAdder.ts @@ -3,7 +3,7 @@ import { components, events, interfaces, nodes } from '../roku-types'; import { Cache } from '../Cache'; import type { TypedFunctionType } from './TypedFunctionType'; import type { SymbolTable } from '../SymbolTable'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import type { BscType } from './BscType'; import { isArrayType, isAssociativeArrayType, isBooleanType, isCallableType, isComponentType, isDoubleType, isEnumMemberType, isFloatType, isIntegerType, isInterfaceType, isInvalidType, isLongIntegerType, isStringType } from '../astUtils/reflection'; import type { ComponentType } from './ComponentType'; diff --git a/src/types/ClassType.spec.ts b/src/types/ClassType.spec.ts index 4f07993dd..df4210a9b 100644 --- a/src/types/ClassType.spec.ts +++ b/src/types/ClassType.spec.ts @@ -6,7 +6,7 @@ import { expectTypeToBe } from '../testHelpers.spec'; import { ReferenceType } from './ReferenceType'; import { isReferenceType } from '../astUtils/reflection'; import { IntegerType } from './IntegerType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; describe('ClassType', () => { diff --git a/src/types/ComponentType.ts b/src/types/ComponentType.ts index 001925505..623a2a733 100644 --- a/src/types/ComponentType.ts +++ b/src/types/ComponentType.ts @@ -1,5 +1,5 @@ import type { GetSymbolTypeOptions } from '../SymbolTable'; -import type { SymbolTypeFlag } from '../SymbolTableFlag'; +import type { SymbolTypeFlag } from '../SymbolTypeFlag'; import { SymbolTable } from '../SymbolTable'; import { isComponentType, isDynamicType, isObjectType } from '../astUtils/reflection'; import type { ExtraSymbolData, TypeCompatibilityData } from '../interfaces'; diff --git a/src/types/EnumType.ts b/src/types/EnumType.ts index 4183fe923..7498694fd 100644 --- a/src/types/EnumType.ts +++ b/src/types/EnumType.ts @@ -1,4 +1,4 @@ -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { isDynamicType, isEnumMemberType, isEnumType, isObjectType } from '../astUtils/reflection'; import type { TypeCompatibilityData } from '../interfaces'; import { BscType } from './BscType'; diff --git a/src/types/InheritableType.ts b/src/types/InheritableType.ts index 891937c4f..a02e369c3 100644 --- a/src/types/InheritableType.ts +++ b/src/types/InheritableType.ts @@ -1,6 +1,6 @@ import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces'; import { isInheritableType, isReferenceType } from '../astUtils/reflection'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { BscType } from './BscType'; import type { ReferenceType } from './ReferenceType'; diff --git a/src/types/InterfaceType.spec.ts b/src/types/InterfaceType.spec.ts index aa93891a9..5665fd220 100644 --- a/src/types/InterfaceType.spec.ts +++ b/src/types/InterfaceType.spec.ts @@ -7,7 +7,7 @@ import { InterfaceType } from './InterfaceType'; import { ObjectType } from './ObjectType'; import { StringType } from './StringType'; import type { ReferenceType } from './ReferenceType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { AssociativeArrayType } from './AssociativeArrayType'; import { ArrayType } from './ArrayType'; import { BooleanType } from './BooleanType'; diff --git a/src/types/InterfaceType.ts b/src/types/InterfaceType.ts index bf3ecdb42..5c65668b0 100644 --- a/src/types/InterfaceType.ts +++ b/src/types/InterfaceType.ts @@ -1,5 +1,5 @@ import type { TypeCompatibilityData } from '../interfaces'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { isDynamicType, isInterfaceType, isObjectType } from '../astUtils/reflection'; import type { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; diff --git a/src/types/ObjectType.ts b/src/types/ObjectType.ts index 8463a5a3d..0bff8c6b5 100644 --- a/src/types/ObjectType.ts +++ b/src/types/ObjectType.ts @@ -1,4 +1,4 @@ -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { isObjectType } from '../astUtils/reflection'; import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces'; import { BscType } from './BscType'; diff --git a/src/types/ReferenceType.spec.ts b/src/types/ReferenceType.spec.ts index 6888c1286..142a6bf2a 100644 --- a/src/types/ReferenceType.spec.ts +++ b/src/types/ReferenceType.spec.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { SymbolTable } from '../SymbolTable'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { expectTypeToBe } from '../testHelpers.spec'; import { DynamicType } from './DynamicType'; import { IntegerType } from './IntegerType'; diff --git a/src/types/ReferenceType.ts b/src/types/ReferenceType.ts index b583fa5d1..781ce3f66 100644 --- a/src/types/ReferenceType.ts +++ b/src/types/ReferenceType.ts @@ -1,6 +1,6 @@ import type { GetTypeOptions, TypeChainEntry, TypeCompatibilityData } from '../interfaces'; import type { GetSymbolTypeOptions, SymbolTypeGetterProvider } from '../SymbolTable'; -import type { SymbolTypeFlag } from '../SymbolTableFlag'; +import type { SymbolTypeFlag } from '../SymbolTypeFlag'; import { isAnyReferenceType, isComponentType, isDynamicType, isReferenceType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; diff --git a/src/types/UnionType.spec.ts b/src/types/UnionType.spec.ts index 24bac9d63..e4a4056f7 100644 --- a/src/types/UnionType.spec.ts +++ b/src/types/UnionType.spec.ts @@ -4,7 +4,7 @@ import { IntegerType } from './IntegerType'; import { UnionType } from './UnionType'; import { FloatType } from './FloatType'; import { InterfaceType } from './InterfaceType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { BooleanType } from './BooleanType'; import { expectTypeToBe } from '../testHelpers.spec'; import { isReferenceType } from '../astUtils/reflection'; diff --git a/src/types/UnionType.ts b/src/types/UnionType.ts index ce9ea457c..608fbc389 100644 --- a/src/types/UnionType.ts +++ b/src/types/UnionType.ts @@ -6,7 +6,7 @@ import { findTypeUnion, getUniqueType, isEnumTypeCompatible } from './helpers'; import { BscTypeKind } from './BscTypeKind'; import type { TypeCacheEntry } from '../SymbolTable'; import { SymbolTable } from '../SymbolTable'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { BuiltInInterfaceAdder } from './BuiltInInterfaceAdder'; export function unionTypeFactory(types: BscType[]) { diff --git a/src/types/helper.spec.ts b/src/types/helper.spec.ts index ace96306a..df265bc56 100644 --- a/src/types/helper.spec.ts +++ b/src/types/helper.spec.ts @@ -9,7 +9,7 @@ import { StringType } from './StringType'; import { UnionType, unionTypeFactory } from './UnionType'; import { findTypeIntersection, findTypeUnion, getUniqueType, getUniqueTypesFromArray } from './helpers'; import { InterfaceType } from './InterfaceType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import { DoubleType } from './DoubleType'; import { BooleanType } from './BooleanType'; import { EnumType, EnumMemberType } from './EnumType'; diff --git a/src/util.spec.ts b/src/util.spec.ts index 6a29402a4..de379ed7c 100644 --- a/src/util.spec.ts +++ b/src/util.spec.ts @@ -13,7 +13,7 @@ import { TypeChainEntry } from './interfaces'; import { NamespaceType } from './types/NamespaceType'; import { ClassType } from './types/ClassType'; import { ReferenceType } from './types/ReferenceType'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { BooleanType, DoubleType, DynamicType, FloatType, IntegerType, InvalidType, LongIntegerType, StringType, TypedFunctionType, VoidType } from './types'; import { TokenKind } from './lexer/TokenKind'; import { createToken } from './astUtils/creators'; diff --git a/src/util.ts b/src/util.ts index 1725d4fb0..5239ab39e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -36,7 +36,7 @@ import type { AstNode, Expression, Statement } from './parser/AstNode'; import { AstNodeKind } from './parser/AstNode'; import type { UnresolvedSymbol } from './AstValidationSegmenter'; import type { SymbolTable } from './SymbolTable'; -import { SymbolTypeFlag } from './SymbolTableFlag'; +import { SymbolTypeFlag } from './SymbolTypeFlag'; import { createIdentifier, createToken } from './astUtils/creators'; import { MAX_RELATED_INFOS_COUNT } from './diagnosticUtils'; import type { BscType } from './types/BscType'; diff --git a/src/validators/ClassValidator.ts b/src/validators/ClassValidator.ts index 2f5a02fde..cb90a59e4 100644 --- a/src/validators/ClassValidator.ts +++ b/src/validators/ClassValidator.ts @@ -11,7 +11,7 @@ import type { BrsFile } from '../files/BrsFile'; import { TokenKind } from '../lexer/TokenKind'; import { DynamicType } from '../types/DynamicType'; import type { BscType } from '../types/BscType'; -import { SymbolTypeFlag } from '../SymbolTableFlag'; +import { SymbolTypeFlag } from '../SymbolTypeFlag'; import type { BscFile } from '../files/BscFile'; export class BsClassValidator {