Skip to content

allow access protected member in this parameter context #24645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17101,20 +17101,28 @@ namespace ts {

// Find the first enclosing class that has the declaring classes of the protected constituents
// of the property as base classes
const enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => {
let enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => {
const enclosingClass = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingDeclaration)!);
return isClassDerivedFromDeclaringClasses(enclosingClass, prop) ? enclosingClass : undefined;
});
// A protected property is accessible if the property is within the declaring class or classes derived from it
if (!enclosingClass) {
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || type));
return false;
// allow PropertyAccessibility if context is in function with this parameter
// static member access is disallow
let thisParameter: ParameterDeclaration | undefined;
if (flags & ModifierFlags.Static || !(thisParameter = getThisParameterFromNodeContext(node)) || !thisParameter.type) {
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || type));
return false;
}

const thisType = getTypeFromTypeNode(thisParameter.type);
enclosingClass = ((thisType.flags & TypeFlags.TypeParameter) ? getConstraintFromTypeParameter(<TypeParameter>thisType) : thisType) as InterfaceType;
}
// No further restrictions for static properties
if (flags & ModifierFlags.Static) {
return true;
}
if (type.flags & TypeFlags.TypeParameter) {
if (type.flags & TypeFlags.TypeParameter) {
// get the original type -- represented as the type constraint of the 'this' type
type = (type as TypeParameter).isThisType ? getConstraintOfTypeParameter(<TypeParameter>type)! : getBaseConstraintOfType(<TypeParameter>type)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined
}
Expand All @@ -17125,6 +17133,11 @@ namespace ts {
return true;
}

function getThisParameterFromNodeContext (node: Node) {
const thisContainer = getThisContainer(node, /* includeArrowFunctions */ false);
return thisContainer && isFunctionLike(thisContainer) ? getThisParameter(thisContainer) : undefined;
}

function symbolHasNonMethodDeclaration(symbol: Symbol) {
return forEachProperty(symbol, prop => {
const propKind = getDeclarationKindFromSymbol(prop);
Expand Down
74 changes: 74 additions & 0 deletions tests/baselines/reference/thisTypeAccessibility.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(17,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(20,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(21,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(26,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(29,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(30,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(35,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(38,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(39,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.


==== tests/cases/conformance/types/thisType/thisTypeAccessibility.ts (9 errors) ====
class MyClass {
private p: number = 123;
protected pp: number = 123;
public ppp: number = 123;
private static sp: number = 123;
protected static spp: number = 123;
public static sppp: number = 123;
}

interface MyClass {
extension1(p: number): void;
extension2(p: number): void;
extension3(p: number): void;
}

MyClass.prototype.extension1 = function (this: MyClass, p: number) {
this.p = p;
~
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
this.pp = p;
this.ppp = p;
MyClass.sp = p;
~~
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
MyClass.spp = p;
~~~
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
MyClass.sppp = p;
}

MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
this.p = p;
~
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
this.pp = p;
this.ppp = p;
MyClass.sp = p;
~~
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
MyClass.spp = p;
~~~
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
MyClass.sppp = p;
}

function extension3<T extends MyClass> (this: T, p: number) {
this.p = p;
~
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
this.pp = p;
this.ppp = p;
MyClass.sp = p;
~~
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
MyClass.spp = p;
~~~
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
MyClass.sppp = p;
}

MyClass.prototype.extension3 = extension3;

83 changes: 83 additions & 0 deletions tests/baselines/reference/thisTypeAccessibility.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//// [thisTypeAccessibility.ts]
class MyClass {
private p: number = 123;
protected pp: number = 123;
public ppp: number = 123;
private static sp: number = 123;
protected static spp: number = 123;
public static sppp: number = 123;
}

interface MyClass {
extension1(p: number): void;
extension2(p: number): void;
extension3(p: number): void;
}

MyClass.prototype.extension1 = function (this: MyClass, p: number) {
this.p = p;
this.pp = p;
this.ppp = p;
MyClass.sp = p;
MyClass.spp = p;
MyClass.sppp = p;
}

MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
this.p = p;
this.pp = p;
this.ppp = p;
MyClass.sp = p;
MyClass.spp = p;
MyClass.sppp = p;
}

function extension3<T extends MyClass> (this: T, p: number) {
this.p = p;
this.pp = p;
this.ppp = p;
MyClass.sp = p;
MyClass.spp = p;
MyClass.sppp = p;
}

MyClass.prototype.extension3 = extension3;


//// [thisTypeAccessibility.js]
var MyClass = /** @class */ (function () {
function MyClass() {
this.p = 123;
this.pp = 123;
this.ppp = 123;
}
MyClass.sp = 123;
MyClass.spp = 123;
MyClass.sppp = 123;
return MyClass;
}());
MyClass.prototype.extension1 = function (p) {
this.p = p;
this.pp = p;
this.ppp = p;
MyClass.sp = p;
MyClass.spp = p;
MyClass.sppp = p;
};
MyClass.prototype.extension2 = function (p) {
this.p = p;
this.pp = p;
this.ppp = p;
MyClass.sp = p;
MyClass.spp = p;
MyClass.sppp = p;
};
function extension3(p) {
this.p = p;
this.pp = p;
this.ppp = p;
MyClass.sp = p;
MyClass.spp = p;
MyClass.sppp = p;
}
MyClass.prototype.extension3 = extension3;
188 changes: 188 additions & 0 deletions tests/baselines/reference/thisTypeAccessibility.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
=== tests/cases/conformance/types/thisType/thisTypeAccessibility.ts ===
class MyClass {
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))

private p: number = 123;
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))

protected pp: number = 123;
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))

public ppp: number = 123;
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))

private static sp: number = 123;
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))

protected static spp: number = 123;
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))

public static sppp: number = 123;
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
}

interface MyClass {
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))

extension1(p: number): void;
>extension1 : Symbol(MyClass.extension1, Decl(thisTypeAccessibility.ts, 9, 19))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 10, 15))

extension2(p: number): void;
>extension2 : Symbol(MyClass.extension2, Decl(thisTypeAccessibility.ts, 10, 32))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 11, 15))

extension3(p: number): void;
>extension3 : Symbol(MyClass.extension3, Decl(thisTypeAccessibility.ts, 11, 32))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 12, 15))
}

MyClass.prototype.extension1 = function (this: MyClass, p: number) {
>MyClass.prototype.extension1 : Symbol(MyClass.extension1, Decl(thisTypeAccessibility.ts, 9, 19))
>MyClass.prototype : Symbol(MyClass.prototype)
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>prototype : Symbol(MyClass.prototype)
>extension1 : Symbol(MyClass.extension1, Decl(thisTypeAccessibility.ts, 9, 19))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))

this.p = p;
>this.p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))

this.pp = p;
>this.pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))

this.ppp = p;
>this.ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))

MyClass.sp = p;
>MyClass.sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))

MyClass.spp = p;
>MyClass.spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))

MyClass.sppp = p;
>MyClass.sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
}

MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
>MyClass.prototype.extension2 : Symbol(MyClass.extension2, Decl(thisTypeAccessibility.ts, 10, 32))
>MyClass.prototype : Symbol(MyClass.prototype)
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>prototype : Symbol(MyClass.prototype)
>extension2 : Symbol(MyClass.extension2, Decl(thisTypeAccessibility.ts, 10, 32))
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 24, 40))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 24, 40))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))

this.p = p;
>this.p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))

this.pp = p;
>this.pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))

this.ppp = p;
>this.ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))

MyClass.sp = p;
>MyClass.sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))

MyClass.spp = p;
>MyClass.spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))

MyClass.sppp = p;
>MyClass.sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
}

function extension3<T extends MyClass> (this: T, p: number) {
>extension3 : Symbol(extension3, Decl(thisTypeAccessibility.ts, 31, 1))
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 33, 20))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 33, 20))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))

this.p = p;
>this.p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))

this.pp = p;
>this.pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))

this.ppp = p;
>this.ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))

MyClass.sp = p;
>MyClass.sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))

MyClass.spp = p;
>MyClass.spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))

MyClass.sppp = p;
>MyClass.sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
}

MyClass.prototype.extension3 = extension3;
>MyClass.prototype.extension3 : Symbol(MyClass.extension3, Decl(thisTypeAccessibility.ts, 11, 32))
>MyClass.prototype : Symbol(MyClass.prototype)
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
>prototype : Symbol(MyClass.prototype)
>extension3 : Symbol(MyClass.extension3, Decl(thisTypeAccessibility.ts, 11, 32))
>extension3 : Symbol(extension3, Decl(thisTypeAccessibility.ts, 31, 1))

Loading