mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
fix(52664): Assertion failure on completions for derived class with computed base property name (#52673)
This commit is contained in:
@@ -42817,17 +42817,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
* Checks a member declaration node to see if has a missing or invalid `override` modifier.
|
||||
* @param node Class-like node where the member is declared.
|
||||
* @param member Member declaration node.
|
||||
* @param memberSymbol Member symbol.
|
||||
* Note: `member` can be a synthetic node without a parent.
|
||||
*/
|
||||
function getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement): MemberOverrideStatus {
|
||||
function getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement, memberSymbol: Symbol): MemberOverrideStatus {
|
||||
if (!member.name) {
|
||||
return MemberOverrideStatus.Ok;
|
||||
}
|
||||
|
||||
const symbol = getSymbolOfDeclaration(node);
|
||||
const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType;
|
||||
const classSymbol = getSymbolOfDeclaration(node);
|
||||
const type = getDeclaredTypeOfSymbol(classSymbol) as InterfaceType;
|
||||
const typeWithThis = getTypeWithThisArgument(type);
|
||||
const staticType = getTypeOfSymbol(symbol) as ObjectType;
|
||||
const staticType = getTypeOfSymbol(classSymbol) as ObjectType;
|
||||
|
||||
const baseTypeNode = getEffectiveBaseTypeNode(node);
|
||||
const baseTypes = baseTypeNode && getBaseTypes(type);
|
||||
@@ -42838,8 +42839,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
? hasOverrideModifier(member)
|
||||
: hasSyntacticModifier(member, ModifierFlags.Override);
|
||||
|
||||
const memberName = unescapeLeadingUnderscores(getTextOfPropertyName(member.name));
|
||||
|
||||
return checkMemberForOverrideModifier(
|
||||
node,
|
||||
staticType,
|
||||
@@ -42851,7 +42850,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
hasAbstractModifier(member),
|
||||
isStatic(member),
|
||||
/* memberIsParameterProperty */ false,
|
||||
memberName,
|
||||
symbolName(memberSymbol),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5238,7 +5238,7 @@ export interface TypeChecker {
|
||||
/** @internal */ isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean;
|
||||
/** @internal */ isPropertyAccessible(node: Node, isSuper: boolean, isWrite: boolean, containingType: Type, property: Symbol): boolean;
|
||||
/** @internal */ getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyAliasDeclaration | undefined;
|
||||
/** @internal */ getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement): MemberOverrideStatus;
|
||||
/** @internal */ getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement, memberSymbol: Symbol): MemberOverrideStatus;
|
||||
/** @internal */ isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node): boolean;
|
||||
}
|
||||
|
||||
|
||||
+37
-18
@@ -62,6 +62,7 @@ import {
|
||||
first,
|
||||
firstDefined,
|
||||
flatMap,
|
||||
forEach,
|
||||
formatting,
|
||||
FunctionLikeDeclaration,
|
||||
getAllSuperTypeNodes,
|
||||
@@ -427,15 +428,16 @@ export enum CompletionSource {
|
||||
|
||||
/** @internal */
|
||||
export const enum SymbolOriginInfoKind {
|
||||
ThisType = 1 << 0,
|
||||
SymbolMember = 1 << 1,
|
||||
Export = 1 << 2,
|
||||
Promise = 1 << 3,
|
||||
Nullable = 1 << 4,
|
||||
ResolvedExport = 1 << 5,
|
||||
TypeOnlyAlias = 1 << 6,
|
||||
ObjectLiteralMethod = 1 << 7,
|
||||
Ignore = 1 << 8,
|
||||
ThisType = 1 << 0,
|
||||
SymbolMember = 1 << 1,
|
||||
Export = 1 << 2,
|
||||
Promise = 1 << 3,
|
||||
Nullable = 1 << 4,
|
||||
ResolvedExport = 1 << 5,
|
||||
TypeOnlyAlias = 1 << 6,
|
||||
ObjectLiteralMethod = 1 << 7,
|
||||
Ignore = 1 << 8,
|
||||
ComputedPropertyName = 1 << 9,
|
||||
|
||||
SymbolMemberNoExport = SymbolMember,
|
||||
SymbolMemberExport = SymbolMember | Export,
|
||||
@@ -475,6 +477,10 @@ interface SymbolOriginInfoObjectLiteralMethod extends SymbolOriginInfo {
|
||||
isSnippet?: true,
|
||||
}
|
||||
|
||||
interface SymbolOriginInfoComputedPropertyName extends SymbolOriginInfo {
|
||||
symbolName: string;
|
||||
}
|
||||
|
||||
function originIsThisType(origin: SymbolOriginInfo): boolean {
|
||||
return !!(origin.kind & SymbolOriginInfoKind.ThisType);
|
||||
}
|
||||
@@ -491,8 +497,8 @@ function originIsResolvedExport(origin: SymbolOriginInfo | undefined): origin is
|
||||
return !!(origin && origin.kind === SymbolOriginInfoKind.ResolvedExport);
|
||||
}
|
||||
|
||||
function originIncludesSymbolName(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoExport | SymbolOriginInfoResolvedExport {
|
||||
return originIsExport(origin) || originIsResolvedExport(origin);
|
||||
function originIncludesSymbolName(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoExport | SymbolOriginInfoResolvedExport | SymbolOriginInfoComputedPropertyName {
|
||||
return originIsExport(origin) || originIsResolvedExport(origin) || originIsComputedPropertyName(origin);
|
||||
}
|
||||
|
||||
function originIsPackageJsonImport(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoExport {
|
||||
@@ -519,6 +525,10 @@ function originIsIgnore(origin: SymbolOriginInfo | undefined): boolean {
|
||||
return !!(origin && origin.kind & SymbolOriginInfoKind.Ignore);
|
||||
}
|
||||
|
||||
function originIsComputedPropertyName(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoComputedPropertyName {
|
||||
return !!(origin && origin.kind & SymbolOriginInfoKind.ComputedPropertyName);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface UniqueNameSet {
|
||||
add(name: string): void;
|
||||
@@ -1552,10 +1562,9 @@ function getEntryForMemberCompletion(
|
||||
requiredModifiers |= ModifierFlags.Abstract;
|
||||
}
|
||||
if (isClassElement(node)
|
||||
&& checker.getMemberOverrideModifierStatus(classLikeDeclaration, node) === MemberOverrideStatus.NeedsOverride) {
|
||||
&& checker.getMemberOverrideModifierStatus(classLikeDeclaration, node, symbol) === MemberOverrideStatus.NeedsOverride) {
|
||||
requiredModifiers |= ModifierFlags.Override;
|
||||
}
|
||||
|
||||
if (!completionNodes.length) {
|
||||
// Keep track of added missing required modifiers and modifiers already present.
|
||||
// This is needed when we have overloaded signatures,
|
||||
@@ -2322,7 +2331,8 @@ export function getCompletionEntryDetails(
|
||||
case "symbol": {
|
||||
const { symbol, location, contextToken, origin, previousToken } = symbolCompletion;
|
||||
const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(name, location, contextToken, origin, symbol, program, host, compilerOptions, sourceFile, position, previousToken, formatContext, preferences, data, source, cancellationToken);
|
||||
return createCompletionDetailsForSymbol(symbol, typeChecker, sourceFile, location, cancellationToken, codeActions, sourceDisplay); // TODO: GH#18217
|
||||
const symbolName = originIsComputedPropertyName(origin) ? origin.symbolName : symbol.name;
|
||||
return createCompletionDetailsForSymbol(symbol, symbolName, typeChecker, sourceFile, location, cancellationToken, codeActions, sourceDisplay); // TODO: GH#18217
|
||||
}
|
||||
case "literal": {
|
||||
const { literal } = symbolCompletion;
|
||||
@@ -2374,12 +2384,12 @@ function createSimpleDetails(name: string, kind: ScriptElementKind, kind2: Symbo
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createCompletionDetailsForSymbol(symbol: Symbol, checker: TypeChecker, sourceFile: SourceFile, location: Node, cancellationToken: CancellationToken, codeActions?: CodeAction[], sourceDisplay?: SymbolDisplayPart[]): CompletionEntryDetails {
|
||||
export function createCompletionDetailsForSymbol(symbol: Symbol, name: string, checker: TypeChecker, sourceFile: SourceFile, location: Node, cancellationToken: CancellationToken, codeActions?: CodeAction[], sourceDisplay?: SymbolDisplayPart[]): CompletionEntryDetails {
|
||||
const { displayParts, documentation, symbolKind, tags } =
|
||||
checker.runWithCancellationToken(cancellationToken, checker =>
|
||||
SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, sourceFile, location, location, SemanticMeaning.All)
|
||||
);
|
||||
return createCompletionDetails(symbol.name, SymbolDisplay.getSymbolModifiers(checker, symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay);
|
||||
return createCompletionDetails(name, SymbolDisplay.getSymbolModifiers(checker, symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -3963,8 +3973,17 @@ function getCompletionData(
|
||||
type && typeChecker.getPropertiesOfType(type);
|
||||
});
|
||||
symbols = concatenate(symbols, filterClassMembersList(baseSymbols, decl.members, classElementModifierFlags));
|
||||
forEach(symbols, (symbol, index) => {
|
||||
const declaration = symbol?.valueDeclaration;
|
||||
if (declaration && isClassElement(declaration) && declaration.name && isComputedPropertyName(declaration.name)) {
|
||||
const origin: SymbolOriginInfoComputedPropertyName = {
|
||||
kind: SymbolOriginInfoKind.ComputedPropertyName,
|
||||
symbolName: typeChecker.symbolToString(symbol),
|
||||
};
|
||||
symbolToOriginInfoMap[index] = origin;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return GlobalsSearch.Success;
|
||||
}
|
||||
|
||||
@@ -4545,7 +4564,7 @@ function getCompletionEntryDisplayNameForSymbol(
|
||||
}
|
||||
switch (kind) {
|
||||
case CompletionKind.MemberLike:
|
||||
return undefined;
|
||||
return originIsComputedPropertyName(origin) ? { name: origin.symbolName, needsConvertPropertyAccess: false } : undefined;
|
||||
case CompletionKind.ObjectPropertyDeclaration:
|
||||
// TODO: GH#18169
|
||||
return { name: JSON.stringify(name), needsConvertPropertyAccess: false };
|
||||
|
||||
@@ -287,7 +287,7 @@ function stringLiteralCompletionDetails(name: string, location: Node, completion
|
||||
}
|
||||
case StringLiteralCompletionKind.Properties: {
|
||||
const match = find(completion.symbols, s => s.name === name);
|
||||
return match && createCompletionDetailsForSymbol(match, checker, sourceFile, location, cancellationToken);
|
||||
return match && createCompletionDetailsForSymbol(match, match.name, checker, sourceFile, location, cancellationToken);
|
||||
}
|
||||
case StringLiteralCompletionKind.Types:
|
||||
return find(completion.types, t => t.value === name) ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.string, [textPart(name)]) : undefined;
|
||||
|
||||
Reference in New Issue
Block a user