Skip to content

Commit

Permalink
Fix crash with mismatched class members (#461)
Browse files Browse the repository at this point in the history
  • Loading branch information
TwitchBronBron authored Oct 17, 2021
1 parent 538db24 commit 4bdc99b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
26 changes: 26 additions & 0 deletions src/files/BrsFile.Class.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1178,4 +1178,30 @@ describe('BrsFile BrighterScript classes', () => {
file.parser.references.classStatements[0].getParentClassIndex(new BrsTranspileState(file));
});
});

it('does not crash when child has field with same name as sub in parent', () => {
program.addOrReplaceFile('source/main.bs', `
class Parent
public function helloWorld()
end function
end class
class Child extends Parent
public helloWorld as string
end class
`);
program.validate();
});

it('does not crash when child has method with same name as field in parent', () => {
program.addOrReplaceFile('source/main.bs', `
class Parent
public helloWorld as string
end class
class Child extends Parent
public function helloWorld()
end function
end class
`);
program.validate();
});
});
10 changes: 10 additions & 0 deletions src/parser/Expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { TranspileResult, TypedefProvider } from '../interfaces';
import { VoidType } from '../types/VoidType';
import { DynamicType } from '../types/DynamicType';
import type { BscType } from '../types/BscType';
import { FunctionType } from '../types/FunctionType';

export type ExpressionVisitor = (expression: Expression, parent: Expression) => void;

Expand Down Expand Up @@ -250,6 +251,15 @@ export class FunctionExpression extends Expression implements TypedefProvider {
}
}
}

getFunctionType(): FunctionType {
let functionType = new FunctionType(this.returnType);
functionType.isSub = this.functionType.text === 'sub';
for (let param of this.parameters) {
functionType.addParameter(param.name.text, param.type, !!param.typeToken);
}
return functionType;
}
}

export class FunctionParameterExpression extends Expression {
Expand Down
14 changes: 10 additions & 4 deletions src/validators/ClassValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Scope } from '../Scope';
import { DiagnosticMessages } from '../DiagnosticMessages';
import type { CallExpression } from '../parser/Expression';
import { ParseMode } from '../parser/Parser';
import type { ClassFieldStatement, ClassMethodStatement, ClassStatement } from '../parser/Statement';
import type { ClassMethodStatement, ClassStatement } from '../parser/Statement';
import { CancellationTokenSource, Location } from 'vscode-languageserver';
import { URI } from 'vscode-uri';
import util from '../util';
Expand All @@ -11,6 +11,7 @@ import type { BscFile, BsDiagnostic } from '../interfaces';
import { createVisitor, WalkMode } from '../astUtils';
import type { BrsFile } from '../files/BrsFile';
import { TokenKind } from '../lexer';
import { DynamicType } from '../types/DynamicType';

export class BsClassValidator {
private scope: Scope;
Expand Down Expand Up @@ -197,17 +198,22 @@ export class BsClassValidator {

//child field has same name as parent
if (isClassFieldStatement(member)) {
const ancestorFieldType = (ancestorAndMember.member as ClassFieldStatement).getType();
let ancestorMemberType = new DynamicType();
if (isClassFieldStatement(ancestorAndMember.member)) {
ancestorMemberType = ancestorAndMember.member.getType();
} else if (isClassMethodStatement(ancestorAndMember.member)) {
ancestorMemberType = ancestorAndMember.member.func.getFunctionType();
}
const childFieldType = member.getType();
if (!childFieldType.isAssignableTo(ancestorFieldType)) {
if (!childFieldType.isAssignableTo(ancestorMemberType)) {
//flag incompatible child field type to ancestor field type
this.diagnostics.push({
...DiagnosticMessages.childFieldTypeNotAssignableToBaseProperty(
classStatement.getName(ParseMode.BrighterScript),
ancestorAndMember.classStatement.getName(ParseMode.BrighterScript),
member.name.text,
childFieldType.toString(),
ancestorFieldType.toString()
ancestorMemberType.toString()
),
file: classStatement.file,
range: member.range
Expand Down

0 comments on commit 4bdc99b

Please sign in to comment.