Skip to content

Commit 895be38

Browse files
committed
Handle class accesibility
1 parent 83dd753 commit 895be38

File tree

7 files changed

+44
-24
lines changed

7 files changed

+44
-24
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ namespace ts {
213213
return node ? getConstantValue(node) : undefined;
214214
},
215215
isValidPropertyAccess: (node, propertyName) => {
216-
node = getParseTreeNode(node, isPropertyAccessOrQualifiedName);
216+
node = getParseTreeNode(node, isPropertyAccessOrQualifiedNameOrImportTypeNode);
217217
return !!node && isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName));
218218
},
219219
isValidPropertyAccessForCompletions: (node, type, property) => {
@@ -8547,7 +8547,7 @@ namespace ts {
85478547
return links.resolvedType = unknownType;
85488548
}
85498549
const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false);
8550-
if (node.qualifier) {
8550+
if (!nodeIsMissing(node.qualifier)) {
85518551
const nameStack: Identifier[] = getIdentifierChain(node.qualifier);
85528552
let currentNamespace = moduleSymbol;
85538553
let current: Identifier | undefined;
@@ -16237,11 +16237,13 @@ namespace ts {
1623716237
* @param type The type of left.
1623816238
* @param prop The symbol for the right hand side of the property access.
1623916239
*/
16240-
function checkPropertyAccessibility(node: PropertyAccessExpression | QualifiedName | VariableLikeDeclaration, left: Expression | QualifiedName, type: Type, prop: Symbol): boolean {
16240+
function checkPropertyAccessibility(node: PropertyAccessExpression | QualifiedName | VariableLikeDeclaration | ImportTypeNode, left: Expression | QualifiedName | ImportTypeNode, type: Type, prop: Symbol): boolean {
1624116241
const flags = getDeclarationModifierFlagsFromSymbol(prop);
1624216242
const errorNode = node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.VariableDeclaration ?
1624316243
node.name :
16244-
(<QualifiedName>node).right;
16244+
node.kind === SyntaxKind.ImportTypeNode ?
16245+
node :
16246+
(<QualifiedName>node).right;
1624516247

1624616248
if (getCheckFlags(prop) & CheckFlags.ContainsPrivate) {
1624716249
// Synthetic property with private constituent property
@@ -16680,13 +16682,19 @@ namespace ts {
1668016682
(getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop).isReferenced = SymbolFlags.All;
1668116683
}
1668216684

16683-
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: __String): boolean {
16684-
const left = node.kind === SyntaxKind.PropertyAccessExpression ? node.expression : node.left;
16685-
return isValidPropertyAccessWithType(node, left, propertyName, getWidenedType(checkExpression(left)));
16685+
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean {
16686+
switch (node.kind) {
16687+
case SyntaxKind.PropertyAccessExpression:
16688+
return isValidPropertyAccessWithType(node, node.expression, propertyName, getWidenedType(checkExpression(node.expression)));
16689+
case SyntaxKind.QualifiedName:
16690+
return isValidPropertyAccessWithType(node, node.left, propertyName, getWidenedType(checkExpression(node.left)));
16691+
case SyntaxKind.ImportTypeNode:
16692+
return isValidPropertyAccessWithType(node, node, propertyName, getTypeFromTypeNode(node));
16693+
}
1668616694
}
1668716695

16688-
function isValidPropertyAccessForCompletions(node: PropertyAccessExpression, type: Type, property: Symbol): boolean {
16689-
return isValidPropertyAccessWithType(node, node.expression, property.escapedName, type)
16696+
function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol): boolean {
16697+
return isValidPropertyAccessWithType(node, node.kind === SyntaxKind.ImportTypeNode ? node : node.expression, property.escapedName, type)
1669016698
&& (!(property.flags & SymbolFlags.Method) || isValidMethodAccess(property, type));
1669116699
}
1669216700
function isValidMethodAccess(method: Symbol, actualThisType: Type): boolean {
@@ -16708,8 +16716,8 @@ namespace ts {
1670816716
}
1670916717

1671016718
function isValidPropertyAccessWithType(
16711-
node: PropertyAccessExpression | QualifiedName,
16712-
left: LeftHandSideExpression | QualifiedName,
16719+
node: PropertyAccessExpression | QualifiedName | ImportTypeNode,
16720+
left: LeftHandSideExpression | QualifiedName | ImportTypeNode,
1671316721
propertyName: __String,
1671416722
type: Type): boolean {
1671516723

src/compiler/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,9 +2890,9 @@ namespace ts {
28902890
/* @internal */ getMergedSymbol(symbol: Symbol): Symbol;
28912891

28922892
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined;
2893-
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
2893+
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean;
28942894
/** Exclude accesses to private properties or methods with a `this` parameter that `type` doesn't satisfy. */
2895-
/* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression, type: Type, property: Symbol): boolean;
2895+
/* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol): boolean;
28962896
/** Follow all aliases to get the original symbol. */
28972897
getAliasedSymbol(symbol: Symbol): Symbol;
28982898
/** Follow a *single* alias to get the immediately aliased symbol. */

src/compiler/utilities.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5731,6 +5731,14 @@ namespace ts {
57315731
return false;
57325732
}
57335733

5734+
/* @internal */
5735+
export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode {
5736+
const kind = node.kind;
5737+
return kind === SyntaxKind.PropertyAccessExpression
5738+
|| kind === SyntaxKind.QualifiedName
5739+
|| kind === SyntaxKind.ImportTypeNode;
5740+
}
5741+
57345742
// Expression
57355743

57365744
export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName {

src/services/completions.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,14 +1011,7 @@ namespace ts.Completions {
10111011
if (symbol.flags & (SymbolFlags.Module | SymbolFlags.Enum)) {
10121012
// Extract module or enum members
10131013
const exportedSymbols = Debug.assertEachDefined(typeChecker.getExportsOfModule(symbol), "getExportsOfModule() should all be defined");
1014-
const isValidValueAccess = (symbol: Symbol) => {
1015-
if (!isImportType) {
1016-
return typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name);
1017-
}
1018-
else {
1019-
return !!(node as ImportTypeNode).isTypeOf && !!(symbol.flags & SymbolFlags.Value);
1020-
}
1021-
};
1014+
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(isImportType ? <ImportTypeNode>node : <PropertyAccessExpression>(node.parent), symbol.name);
10221015
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
10231016
const isValidAccess = allowTypeOrValue ?
10241017
// Any kind is allowed when dotting off namespace in internal import equals declaration
@@ -1058,7 +1051,7 @@ namespace ts.Completions {
10581051
}
10591052
else {
10601053
for (const symbol of type.getApparentProperties()) {
1061-
if (typeChecker.isValidPropertyAccessForCompletions(<PropertyAccessExpression>(node.parent), type, symbol)) {
1054+
if (typeChecker.isValidPropertyAccessForCompletions(node.kind === SyntaxKind.ImportTypeNode ? <ImportTypeNode>node : <PropertyAccessExpression>(node.parent), type, symbol)) {
10621055
symbols.push(symbol);
10631056
}
10641057
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ declare namespace ts {
18211821
isArgumentsSymbol(symbol: Symbol): boolean;
18221822
isUnknownSymbol(symbol: Symbol): boolean;
18231823
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined;
1824-
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
1824+
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean;
18251825
/** Follow all aliases to get the original symbol. */
18261826
getAliasedSymbol(symbol: Symbol): Symbol;
18271827
getExportsOfModule(moduleSymbol: Symbol): Symbol[];

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ declare namespace ts {
18211821
isArgumentsSymbol(symbol: Symbol): boolean;
18221822
isUnknownSymbol(symbol: Symbol): boolean;
18231823
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined;
1824-
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
1824+
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean;
18251825
/** Follow all aliases to get the original symbol. */
18261826
getAliasedSymbol(symbol: Symbol): Symbol;
18271827
getExportsOfModule(moduleSymbol: Symbol): Symbol[];

tests/cases/fourslash/importTypeMemberCompletions.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@
66
//// export class Baz {}
77
//// export interface Bat {}
88
//// export const a: number;
9+
//// const b: string;
910
//// }
1011
////}
1112

1213
// @Filename: /top.ts
1314
////export interface Bat {}
1415
////export const a: number;
1516

17+
// @Filename: /equals.ts
18+
////class Foo {
19+
//// public static bar: string;
20+
//// private static baz: number;
21+
////}
22+
////export = Foo;
23+
1624
// @Filename: /usage1.ts
1725
////type A = typeof import("./ns")./*1*/
1826
// @Filename: /usage2.ts
@@ -29,6 +37,8 @@
2937
////type G = typeof import("./top")./*7*/
3038
// @Filename: /usage8.ts
3139
////type H = import("./top")./*8*/
40+
// @Filename: /usage9.ts
41+
////type H = typeof import("./equals")./*9*/
3242

3343
verify.completionsAt("1", ["Foo"]);
3444
verify.completionsAt("2", ["Bar"]);
@@ -38,3 +48,4 @@ verify.completionsAt("5", ["Bar"]);
3848
verify.completionsAt("6", ["Baz", "Bat"]);
3949
verify.completionsAt("7", ["a"]);
4050
verify.completionsAt("8", ["Bat"]);
51+
verify.completionsAt("9", ["prototype", "bar"]);

0 commit comments

Comments
 (0)