mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 16:06:39 +03:00
Added check for an attempt to overwrite a method that is marked @final
.
This commit is contained in:
parent
051f74cd68
commit
07892e0da7
@ -5309,6 +5309,30 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
}
|
||||
}
|
||||
} else if (isFunction(concreteSubtype) || isOverloadedFunction(concreteSubtype)) {
|
||||
// Check for an attempt to overwrite a final method.
|
||||
if (usage.method === 'set') {
|
||||
let isFinal = false;
|
||||
if (isFunction(concreteSubtype)) {
|
||||
isFinal = FunctionType.isFinal(concreteSubtype);
|
||||
} else {
|
||||
const impl = concreteSubtype.overloads.find((f) => !FunctionType.isOverloaded(f));
|
||||
if (impl) {
|
||||
isFinal = FunctionType.isFinal(impl);
|
||||
}
|
||||
}
|
||||
|
||||
if (isFinal && memberInfo && isClass(memberInfo.classType)) {
|
||||
diag?.addMessage(
|
||||
Localizer.Diagnostic.finalMethodOverride().format({
|
||||
name: memberName,
|
||||
className: memberInfo.classType.details.name,
|
||||
})
|
||||
);
|
||||
isTypeValid = false;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// If this function is an instance member (e.g. a lambda that was
|
||||
// assigned to an instance variable), don't perform any binding.
|
||||
if (!isAccessedThroughObject || (memberInfo && !memberInfo.isInstanceMember)) {
|
||||
@ -5334,11 +5358,11 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
}
|
||||
|
||||
// Check for an attempt to overwrite a final member variable.
|
||||
const finalTypeDecl = memberInfo?.symbol
|
||||
const finalVarTypeDecl = memberInfo?.symbol
|
||||
.getDeclarations()
|
||||
.find((decl) => isFinalVariableDeclaration(decl));
|
||||
|
||||
if (finalTypeDecl && !ParseTreeUtils.isNodeContainedWithin(errorNode, finalTypeDecl.node)) {
|
||||
if (finalVarTypeDecl && !ParseTreeUtils.isNodeContainedWithin(errorNode, finalVarTypeDecl.node)) {
|
||||
// If a Final instance variable is declared in the class body but is
|
||||
// being assigned within an __init__ method, it's allowed.
|
||||
const enclosingFunctionNode = ParseTreeUtils.getEnclosingFunction(errorNode);
|
||||
|
@ -29,6 +29,16 @@ class ClassA:
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error because func3 is final.
|
||||
ClassA.func3 = lambda self: None
|
||||
|
||||
# This should generate an error because func4 is final.
|
||||
ClassA.func4 = lambda cls: None
|
||||
|
||||
# This should generate an error because _func5 is final.
|
||||
ClassA._func5 = lambda self: None
|
||||
|
||||
|
||||
class ClassB(ClassA):
|
||||
def func1(self):
|
||||
pass
|
||||
|
@ -297,7 +297,7 @@ test('Final1', () => {
|
||||
|
||||
test('Final2', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['final2.py']);
|
||||
TestUtils.validateResults(analysisResults, 4);
|
||||
TestUtils.validateResults(analysisResults, 7);
|
||||
});
|
||||
|
||||
test('Final3', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user