From b1ab2b98be801f5cd0ed668e978687466ab66a4e Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Apr 2021 09:20:21 -0700 Subject: [PATCH] Wire up 'writing' parameter through protected derived class detection (#43455) Fixes #43443 --- src/compiler/checker.ts | 6 +- ...rotectedSetterFromThisParameter.errors.txt | 45 ++++++ ...cGetterProtectedSetterFromThisParameter.js | 91 +++++++++++ ...erProtectedSetterFromThisParameter.symbols | 119 +++++++++++++++ ...tterProtectedSetterFromThisParameter.types | 141 ++++++++++++++++++ ...cGetterProtectedSetterFromThisParameter.ts | 37 +++++ 6 files changed, 436 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.errors.txt create mode 100644 tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.js create mode 100644 tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.symbols create mode 100644 tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.types create mode 100644 tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dfc0e5bb5cb..2e49c7db455 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19676,8 +19676,8 @@ namespace ts { // Return true if the given class derives from each of the declaring classes of the protected // constituents of the given property. - function isClassDerivedFromDeclaringClasses(checkClass: Type, prop: Symbol) { - return forEachProperty(prop, p => getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.Protected ? + function isClassDerivedFromDeclaringClasses(checkClass: Type, prop: Symbol, writing: boolean) { + return forEachProperty(prop, p => getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected ? !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; } @@ -26907,7 +26907,7 @@ namespace ts { // of the property as base classes let enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => { const enclosingClass = getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingDeclaration)!); - return isClassDerivedFromDeclaringClasses(enclosingClass, prop) ? enclosingClass : undefined; + return isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing) ? enclosingClass : undefined; }); // A protected property is accessible if the property is within the declaring class or classes derived from it if (!enclosingClass) { diff --git a/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.errors.txt b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.errors.txt new file mode 100644 index 00000000000..afe32e1150c --- /dev/null +++ b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.errors.txt @@ -0,0 +1,45 @@ +tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts(33,7): error TS2446: Property 'q' is protected and only accessible through an instance of class 'A'. This is an instance of class 'B'. +tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts(34,7): error TS2446: Property 'u' is protected and only accessible through an instance of class 'A'. This is an instance of class 'B'. + + +==== tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts (2 errors) ==== + class A { + get x() { return 0; } + protected set x(v: number) { } + + public get y() { return 0; } + protected set y(v: number) { } + } + + class B { + get q() { return 0; } + protected set q(v: number) { } + + protected get u() { return 0; } + protected set u(v: number) { } + + foo(this: A, a: A, b: B) { + // Should have no errors in this block + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + b.q = 0; + b.u = 0; + } + } + + function bar(this: A, a: A, b: B) { + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + // These should error + b.q = 0; + ~ +!!! error TS2446: Property 'q' is protected and only accessible through an instance of class 'A'. This is an instance of class 'B'. + b.u = 0; + ~ +!!! error TS2446: Property 'u' is protected and only accessible through an instance of class 'A'. This is an instance of class 'B'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.js b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.js new file mode 100644 index 00000000000..a0e14789f0c --- /dev/null +++ b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.js @@ -0,0 +1,91 @@ +//// [publicGetterProtectedSetterFromThisParameter.ts] +class A { + get x() { return 0; } + protected set x(v: number) { } + + public get y() { return 0; } + protected set y(v: number) { } +} + +class B { + get q() { return 0; } + protected set q(v: number) { } + + protected get u() { return 0; } + protected set u(v: number) { } + + foo(this: A, a: A, b: B) { + // Should have no errors in this block + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + b.q = 0; + b.u = 0; + } +} + +function bar(this: A, a: A, b: B) { + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + // These should error + b.q = 0; + b.u = 0; +} + + +//// [publicGetterProtectedSetterFromThisParameter.js] +var A = /** @class */ (function () { + function A() { + } + Object.defineProperty(A.prototype, "x", { + get: function () { return 0; }, + set: function (v) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(A.prototype, "y", { + get: function () { return 0; }, + set: function (v) { }, + enumerable: false, + configurable: true + }); + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + Object.defineProperty(B.prototype, "q", { + get: function () { return 0; }, + set: function (v) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(B.prototype, "u", { + get: function () { return 0; }, + set: function (v) { }, + enumerable: false, + configurable: true + }); + B.prototype.foo = function (a, b) { + // Should have no errors in this block + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + b.q = 0; + b.u = 0; + }; + return B; +}()); +function bar(a, b) { + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + // These should error + b.q = 0; + b.u = 0; +} diff --git a/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.symbols b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.symbols new file mode 100644 index 00000000000..9eb1dceaaf1 --- /dev/null +++ b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.symbols @@ -0,0 +1,119 @@ +=== tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts === +class A { +>A : Symbol(A, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 0)) + + get x() { return 0; } +>x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) + + protected set x(v: number) { } +>x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) +>v : Symbol(v, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 18)) + + public get y() { return 0; } +>y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) + + protected set y(v: number) { } +>y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) +>v : Symbol(v, Decl(publicGetterProtectedSetterFromThisParameter.ts, 5, 18)) +} + +class B { +>B : Symbol(B, Decl(publicGetterProtectedSetterFromThisParameter.ts, 6, 1)) + + get q() { return 0; } +>q : Symbol(B.q, Decl(publicGetterProtectedSetterFromThisParameter.ts, 8, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 9, 23)) + + protected set q(v: number) { } +>q : Symbol(B.q, Decl(publicGetterProtectedSetterFromThisParameter.ts, 8, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 9, 23)) +>v : Symbol(v, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 18)) + + protected get u() { return 0; } +>u : Symbol(B.u, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 12, 33)) + + protected set u(v: number) { } +>u : Symbol(B.u, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 12, 33)) +>v : Symbol(v, Decl(publicGetterProtectedSetterFromThisParameter.ts, 13, 18)) + + foo(this: A, a: A, b: B) { +>foo : Symbol(B.foo, Decl(publicGetterProtectedSetterFromThisParameter.ts, 13, 32)) +>this : Symbol(this, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 6)) +>A : Symbol(A, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 0)) +>a : Symbol(a, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 14)) +>A : Symbol(A, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 0)) +>b : Symbol(b, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 20)) +>B : Symbol(B, Decl(publicGetterProtectedSetterFromThisParameter.ts, 6, 1)) + + // Should have no errors in this block + this.x = 0; +>this.x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) +>this : Symbol(this, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 6)) +>x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) + + this.y = 0; +>this.y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) +>this : Symbol(this, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 6)) +>y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) + + a.x = 0; +>a.x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) +>a : Symbol(a, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 14)) +>x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) + + a.y = 0; +>a.y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) +>a : Symbol(a, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 14)) +>y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) + + b.q = 0; +>b.q : Symbol(B.q, Decl(publicGetterProtectedSetterFromThisParameter.ts, 8, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 9, 23)) +>b : Symbol(b, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 20)) +>q : Symbol(B.q, Decl(publicGetterProtectedSetterFromThisParameter.ts, 8, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 9, 23)) + + b.u = 0; +>b.u : Symbol(B.u, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 12, 33)) +>b : Symbol(b, Decl(publicGetterProtectedSetterFromThisParameter.ts, 15, 20)) +>u : Symbol(B.u, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 12, 33)) + } +} + +function bar(this: A, a: A, b: B) { +>bar : Symbol(bar, Decl(publicGetterProtectedSetterFromThisParameter.ts, 24, 1)) +>this : Symbol(this, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 13)) +>A : Symbol(A, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 0)) +>a : Symbol(a, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 21)) +>A : Symbol(A, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 0)) +>b : Symbol(b, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 27)) +>B : Symbol(B, Decl(publicGetterProtectedSetterFromThisParameter.ts, 6, 1)) + + this.x = 0; +>this.x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) +>this : Symbol(this, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 13)) +>x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) + + this.y = 0; +>this.y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) +>this : Symbol(this, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 13)) +>y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) + + a.x = 0; +>a.x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) +>a : Symbol(a, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 21)) +>x : Symbol(A.x, Decl(publicGetterProtectedSetterFromThisParameter.ts, 0, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 1, 23)) + + a.y = 0; +>a.y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) +>a : Symbol(a, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 21)) +>y : Symbol(A.y, Decl(publicGetterProtectedSetterFromThisParameter.ts, 2, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 4, 30)) + + // These should error + b.q = 0; +>b.q : Symbol(B.q, Decl(publicGetterProtectedSetterFromThisParameter.ts, 8, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 9, 23)) +>b : Symbol(b, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 27)) +>q : Symbol(B.q, Decl(publicGetterProtectedSetterFromThisParameter.ts, 8, 9), Decl(publicGetterProtectedSetterFromThisParameter.ts, 9, 23)) + + b.u = 0; +>b.u : Symbol(B.u, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 12, 33)) +>b : Symbol(b, Decl(publicGetterProtectedSetterFromThisParameter.ts, 26, 27)) +>u : Symbol(B.u, Decl(publicGetterProtectedSetterFromThisParameter.ts, 10, 32), Decl(publicGetterProtectedSetterFromThisParameter.ts, 12, 33)) +} + diff --git a/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.types b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.types new file mode 100644 index 00000000000..a7141d4515b --- /dev/null +++ b/tests/baselines/reference/publicGetterProtectedSetterFromThisParameter.types @@ -0,0 +1,141 @@ +=== tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts === +class A { +>A : A + + get x() { return 0; } +>x : number +>0 : 0 + + protected set x(v: number) { } +>x : number +>v : number + + public get y() { return 0; } +>y : number +>0 : 0 + + protected set y(v: number) { } +>y : number +>v : number +} + +class B { +>B : B + + get q() { return 0; } +>q : number +>0 : 0 + + protected set q(v: number) { } +>q : number +>v : number + + protected get u() { return 0; } +>u : number +>0 : 0 + + protected set u(v: number) { } +>u : number +>v : number + + foo(this: A, a: A, b: B) { +>foo : (this: A, a: A, b: B) => void +>this : A +>a : A +>b : B + + // Should have no errors in this block + this.x = 0; +>this.x = 0 : 0 +>this.x : number +>this : A +>x : number +>0 : 0 + + this.y = 0; +>this.y = 0 : 0 +>this.y : number +>this : A +>y : number +>0 : 0 + + a.x = 0; +>a.x = 0 : 0 +>a.x : number +>a : A +>x : number +>0 : 0 + + a.y = 0; +>a.y = 0 : 0 +>a.y : number +>a : A +>y : number +>0 : 0 + + b.q = 0; +>b.q = 0 : 0 +>b.q : number +>b : B +>q : number +>0 : 0 + + b.u = 0; +>b.u = 0 : 0 +>b.u : number +>b : B +>u : number +>0 : 0 + } +} + +function bar(this: A, a: A, b: B) { +>bar : (this: A, a: A, b: B) => void +>this : A +>a : A +>b : B + + this.x = 0; +>this.x = 0 : 0 +>this.x : number +>this : A +>x : number +>0 : 0 + + this.y = 0; +>this.y = 0 : 0 +>this.y : number +>this : A +>y : number +>0 : 0 + + a.x = 0; +>a.x = 0 : 0 +>a.x : number +>a : A +>x : number +>0 : 0 + + a.y = 0; +>a.y = 0 : 0 +>a.y : number +>a : A +>y : number +>0 : 0 + + // These should error + b.q = 0; +>b.q = 0 : 0 +>b.q : number +>b : B +>q : number +>0 : 0 + + b.u = 0; +>b.u = 0 : 0 +>b.u : number +>b : B +>u : number +>0 : 0 +} + diff --git a/tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts b/tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts new file mode 100644 index 00000000000..04c269cb928 --- /dev/null +++ b/tests/cases/compiler/publicGetterProtectedSetterFromThisParameter.ts @@ -0,0 +1,37 @@ +// @target: ES5 + +class A { + get x() { return 0; } + protected set x(v: number) { } + + public get y() { return 0; } + protected set y(v: number) { } +} + +class B { + get q() { return 0; } + protected set q(v: number) { } + + protected get u() { return 0; } + protected set u(v: number) { } + + foo(this: A, a: A, b: B) { + // Should have no errors in this block + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + b.q = 0; + b.u = 0; + } +} + +function bar(this: A, a: A, b: B) { + this.x = 0; + this.y = 0; + a.x = 0; + a.y = 0; + // These should error + b.q = 0; + b.u = 0; +}