Skip to content

Commit 41f395a

Browse files
authored
fix: add diagnose when getter is not as accessible as the setter (#2801)
1 parent 5ee17be commit 41f395a

File tree

5 files changed

+44
-22
lines changed

5 files changed

+44
-22
lines changed

Diff for: src/diagnosticMessages.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@
151151
"Operator '{0}' cannot be applied to types '{1}' and '{2}'.": 2365,
152152
"A 'super' call must be the first statement in the constructor.": 2376,
153153
"Constructors for derived classes must contain a 'super' call.": 2377,
154-
"Getter and setter accessors do not agree in visibility.": 2379,
155154
"'get' and 'set' accessor must have the same type.": 2380,
156155
"Overload signatures must all be public, private or protected.": 2385,
157156
"Constructor implementation is missing.": 2390,
@@ -200,6 +199,7 @@
200199
"Duplicate property '{0}'.": 2718,
201200
"Property '{0}' is missing in type '{1}' but required in type '{2}'.": 2741,
202201
"Type '{0}' has no call signatures.": 2757,
202+
"Get accessor '{0}' must be at least as accessible as the setter.": 2808,
203203
"This member cannot have an 'override' modifier because it is not declared in the base class '{0}'.": 4117,
204204

205205
"File '{0}' not found.": 6054,

Diff for: src/program.ts

+18
Original file line numberDiff line numberDiff line change
@@ -3088,6 +3088,13 @@ export abstract class Element {
30883088
return (this.flags & vis) == (other.flags & vis);
30893089
}
30903090

3091+
visibilityNoLessThan(other: Element): bool {
3092+
if (this.isPublic) return true; // public is a most frequent case
3093+
if (this.is(CommonFlags.Private)) return other.is(CommonFlags.Private);
3094+
if (this.is(CommonFlags.Protected)) return other.isAny(CommonFlags.Private | CommonFlags.Protected);
3095+
return assert(false);
3096+
}
3097+
30913098
/** Tests if this element is bound to a class. */
30923099
get isBound(): bool {
30933100
let parent = this.parent;
@@ -4174,6 +4181,17 @@ export class Property extends VariableLikeElement {
41744181
get isField(): bool {
41754182
return this.prototype.isField;
41764183
}
4184+
4185+
checkVisibility(diag: DiagnosticEmitter): void {
4186+
let propertyGetter = this.getterInstance;
4187+
let propertySetter = this.setterInstance;
4188+
if (propertyGetter && propertySetter && !propertyGetter.visibilityNoLessThan(propertySetter)) {
4189+
diag.errorRelated(
4190+
DiagnosticCode.Get_accessor_0_must_be_at_least_as_accessible_as_the_setter,
4191+
propertyGetter.identifierNode.range, propertySetter.identifierNode.range, propertyGetter.identifierNode.text
4192+
);
4193+
}
4194+
}
41774195
}
41784196

41794197
/** A resolved index signature. */

Diff for: src/resolver.ts

+1-21
Original file line numberDiff line numberDiff line change
@@ -3384,7 +3384,6 @@ export class Resolver extends DiagnosticEmitter {
33843384
// Resolve instance members
33853385
let prototype = instance.prototype;
33863386
let instanceMemberPrototypes = prototype.instanceMembers;
3387-
let properties = new Array<Property>();
33883387
if (instanceMemberPrototypes) {
33893388
// TODO: for (let member of instanceMemberPrototypes.values()) {
33903389
for (let _values = Map_values(instanceMemberPrototypes), i = 0, k = _values.length; i < k; ++i) {
@@ -3464,26 +3463,6 @@ export class Resolver extends DiagnosticEmitter {
34643463
}
34653464
}
34663465

3467-
// Check that property getters and setters match
3468-
for (let i = 0, k = properties.length; i < k; ++i) {
3469-
let property = properties[i];
3470-
let propertyGetter = property.getterInstance;
3471-
if (!propertyGetter) {
3472-
this.error(
3473-
DiagnosticCode.Property_0_only_has_a_setter_and_is_missing_a_getter,
3474-
property.identifierNode.range, property.name
3475-
);
3476-
} else {
3477-
let propertySetter = property.setterInstance;
3478-
if (propertySetter && !propertyGetter.visibilityEquals(propertySetter)) {
3479-
this.errorRelated(
3480-
DiagnosticCode.Getter_and_setter_accessors_do_not_agree_in_visibility,
3481-
propertyGetter.identifierNode.range, propertySetter.identifierNode.range
3482-
);
3483-
}
3484-
}
3485-
}
3486-
34873466
if (instance.kind != ElementKind.Interface) {
34883467

34893468
// Check that all required members are implemented
@@ -3707,6 +3686,7 @@ export class Resolver extends DiagnosticEmitter {
37073686
}
37083687
}
37093688
}
3689+
instance.checkVisibility(this);
37103690
return instance;
37113691
}
37123692

Diff for: tests/compiler/getter-setter-errors.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"asc_flags": [
3+
],
4+
"stderr": [
5+
"TS2808: Get accessor 'm2' must be at least as accessible as the setter.",
6+
"EOF"
7+
]
8+
}

Diff for: tests/compiler/getter-setter-errors.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class GetSetWithoutDifferenceVisibility {
2+
public get m1(): i32 {
3+
return 1;
4+
}
5+
private set m1(v: i32) {}
6+
7+
private get m2(): i32 {
8+
return 1;
9+
}
10+
public set m2(v: i32) {}
11+
}
12+
13+
new GetSetWithoutDifferenceVisibility().m1; // m1 is valid
14+
new GetSetWithoutDifferenceVisibility().m2; // m2 is invalid
15+
16+
ERROR("EOF");

0 commit comments

Comments
 (0)