When adding completions for a module, don't get the type of the module if not necessary. (#16768)
* When adding completions for a module, don't get the type of the module if not necessary. * Use SymbolFlags.Module alias
This commit is contained in:
parent
6880ee33a3
commit
69d3ca774a
|
@ -3604,6 +3604,10 @@ namespace ts {
|
|||
return previous[previous.length - 1];
|
||||
}
|
||||
|
||||
export function skipAlias(symbol: Symbol, checker: TypeChecker) {
|
||||
return symbol.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
||||
}
|
||||
|
||||
/** See comment on `declareModuleMember` in `binder.ts`. */
|
||||
export function getCombinedLocalAndExportSymbolFlags(symbol: Symbol): SymbolFlags {
|
||||
return symbol.exportSymbol ? symbol.exportSymbol.flags | symbol.flags : symbol.flags;
|
||||
|
|
|
@ -222,10 +222,7 @@ namespace ts.codefix {
|
|||
}
|
||||
|
||||
function getUniqueSymbolId(symbol: Symbol) {
|
||||
if (symbol.flags & SymbolFlags.Alias) {
|
||||
return getSymbolId(checker.getAliasedSymbol(symbol));
|
||||
}
|
||||
return getSymbolId(symbol);
|
||||
return getSymbolId(skipAlias(symbol, checker));
|
||||
}
|
||||
|
||||
function checkSymbolHasMeaning(symbol: Symbol, meaning: SemanticMeaning) {
|
||||
|
|
|
@ -596,46 +596,48 @@ namespace ts.Completions {
|
|||
isNewIdentifierLocation = false;
|
||||
|
||||
// Since this is qualified name check its a type node location
|
||||
const isTypeLocation = isPartOfTypeNode(node.parent) || insideJsDocTagTypeExpression;
|
||||
const isTypeLocation = insideJsDocTagTypeExpression || isPartOfTypeNode(node.parent);
|
||||
const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration(node);
|
||||
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
if (isEntityName(node)) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(node);
|
||||
if (symbol) {
|
||||
symbol = skipAlias(symbol, typeChecker);
|
||||
|
||||
// This is an alias, follow what it aliases
|
||||
if (symbol && symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = typeChecker.getAliasedSymbol(symbol);
|
||||
}
|
||||
|
||||
if (symbol && symbol.flags & SymbolFlags.HasExports) {
|
||||
// Extract module or enum members
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName());
|
||||
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
|
||||
const isValidAccess = isRhsOfImportDeclaration ?
|
||||
// Any kind is allowed when dotting off namespace in internal import equals declaration
|
||||
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
|
||||
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
|
||||
forEach(exportedSymbols, symbol => {
|
||||
if (isValidAccess(symbol)) {
|
||||
symbols.push(symbol);
|
||||
if (symbol.flags & (SymbolFlags.Module | SymbolFlags.Enum)) {
|
||||
// Extract module or enum members
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName());
|
||||
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
|
||||
const isValidAccess = isRhsOfImportDeclaration ?
|
||||
// Any kind is allowed when dotting off namespace in internal import equals declaration
|
||||
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
|
||||
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
|
||||
for (const symbol of exportedSymbols) {
|
||||
if (isValidAccess(symbol)) {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// If the module is merged with a value, we must get the type of the class and add its propertes (for inherited static methods).
|
||||
if (!isTypeLocation && symbol.declarations.some(d => d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration && d.kind !== SyntaxKind.EnumDeclaration)) {
|
||||
addTypeProperties(typeChecker.getTypeOfSymbolAtLocation(symbol, node));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTypeLocation) {
|
||||
const type = typeChecker.getTypeAtLocation(node);
|
||||
if (type) addTypeProperties(type);
|
||||
addTypeProperties(typeChecker.getTypeAtLocation(node));
|
||||
}
|
||||
}
|
||||
|
||||
function addTypeProperties(type: Type) {
|
||||
if (type) {
|
||||
// Filter private properties
|
||||
for (const symbol of type.getApparentProperties()) {
|
||||
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName())) {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
// Filter private properties
|
||||
for (const symbol of type.getApparentProperties()) {
|
||||
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName())) {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -811,15 +813,13 @@ namespace ts.Completions {
|
|||
symbol = symbol.exportSymbol || symbol;
|
||||
|
||||
// This is an alias, follow what it aliases
|
||||
if (symbol && symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = typeChecker.getAliasedSymbol(symbol);
|
||||
}
|
||||
symbol = skipAlias(symbol, typeChecker);
|
||||
|
||||
if (symbol.flags & SymbolFlags.Type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule)) {
|
||||
if (symbol.flags & SymbolFlags.Module) {
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
// If the exported symbols contains type,
|
||||
// symbol can be referenced at locations where type is allowed
|
||||
|
|
21
tests/cases/fourslash/completionsNamespaceMergedWithClass.ts
Normal file
21
tests/cases/fourslash/completionsNamespaceMergedWithClass.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////class C {
|
||||
//// static m() { }
|
||||
////}
|
||||
////
|
||||
////class D extends C {}
|
||||
////namespace D {
|
||||
//// export type T = number;
|
||||
////}
|
||||
////
|
||||
////let x: D./*type*/;
|
||||
////D./*value*/
|
||||
|
||||
goTo.marker("type");
|
||||
verify.completionListContains("T");
|
||||
verify.not.completionListContains("m");
|
||||
|
||||
goTo.marker("value");
|
||||
verify.not.completionListContains("T");
|
||||
verify.completionListContains("m");
|
|
@ -0,0 +1,16 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////namespace N {
|
||||
//// export type T = number;
|
||||
////}
|
||||
////const N = { m() {} };
|
||||
////let x: N./*type*/;
|
||||
////N./*value*/;
|
||||
|
||||
goTo.marker("type");
|
||||
verify.completionListContains("T");
|
||||
verify.not.completionListContains("m");
|
||||
|
||||
goTo.marker("value");
|
||||
verify.not.completionListContains("T");
|
||||
verify.completionListContains("m");
|
Loading…
Reference in a new issue