diff --git a/src/DiagnosticMessages.ts b/src/DiagnosticMessages.ts index a02d2ac50..b1dbe9d43 100644 --- a/src/DiagnosticMessages.ts +++ b/src/DiagnosticMessages.ts @@ -822,6 +822,17 @@ export let DiagnosticMessages = { message: `Expected return statement in function`, code: 1155, severity: DiagnosticSeverity.Error + }), + cannotFindCallFuncFunction: (name: string, fullName: string, typeName: string) => ({ + message: `Cannot find callfunc function '${name}' for type '${typeName}'`, + code: 1156, + data: { + name: name, + fullName: fullName, + typeName: typeName, + isCallfunc: true + }, + severity: DiagnosticSeverity.Error }) }; export const defaultMaximumTruncationLength = 160; diff --git a/src/Program.spec.ts b/src/Program.spec.ts index 3519a5ca0..519c30ece 100644 --- a/src/Program.spec.ts +++ b/src/Program.spec.ts @@ -19,7 +19,7 @@ import type { SinonSpy } from 'sinon'; import { createSandbox } from 'sinon'; import { SymbolTypeFlag } from './SymbolTypeFlag'; import { AssetFile } from './files/AssetFile'; -import type { ProvideFileEvent, CompilerPlugin, BeforeProvideFileEvent, AfterProvideFileEvent, BeforeFileAddEvent, AfterFileAddEvent, BeforeFileRemoveEvent, AfterFileRemoveEvent } from './interfaces'; +import type { ProvideFileEvent, CompilerPlugin, BeforeProvideFileEvent, AfterProvideFileEvent, BeforeFileAddEvent, AfterFileAddEvent, BeforeFileRemoveEvent, AfterFileRemoveEvent, ScopeValidationOptions } from './interfaces'; import { StringType, TypedFunctionType, DynamicType, FloatType, IntegerType, InterfaceType, ArrayType, BooleanType, DoubleType, UnionType } from './types'; import { AssociativeArrayType } from './types/AssociativeArrayType'; import { ComponentType } from './types/ComponentType'; @@ -584,6 +584,161 @@ describe('Program', () => { program.validate(); expectZeroDiagnostics(program); }); + + describe('changed symbols', () => { + it('includes components when component interface changes', () => { + program.setFile('components/widget.xml', trim` + + + + + + `); + program.setFile('components/other.xml', trim` + + + + + + `); + program.setFile('source/main.bs', ` + sub sourceScopeFunc() + end sub + `); + program.validate(); + let options: ScopeValidationOptions = program['currentScopeValidationOptions']; + expect(options.changedSymbols.get(SymbolTypeFlag.typetime).has('rosgnodewidget')).to.be.true; + expect(options.changedSymbols.get(SymbolTypeFlag.typetime).has('rosgnodeother')).to.be.true; + + expectZeroDiagnostics(program); + //change widget + program.setFile('components/widget.xml', trim` + + + + + + `); + program.validate(); + expectZeroDiagnostics(program); + options = program['currentScopeValidationOptions']; + expect(options.changedSymbols.get(SymbolTypeFlag.typetime).has('rosgnodewidget')).to.be.true; + expect(options.changedSymbols.get(SymbolTypeFlag.typetime).has('rosgnodeother')).to.be.false; + }); + + it('includes components when component callfunc changes', () => { + program.setFile('components/widget.xml', trim` + +