mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
fix(52664): Assertion failure on completions for derived class with computed base property name (#52673)
This commit is contained in:
parent
04637662f4
commit
bbb98cf797
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
254
tests/baselines/reference/completionsClassMembers5.baseline
Normal file
254
tests/baselines/reference/completionsClassMembers5.baseline
Normal file
@ -0,0 +1,254 @@
|
||||
=== /tests/cases/fourslash/completionsClassMembers5.ts ===
|
||||
// export const SOME_CONSTANT = 'SOME_TEXT';
|
||||
// export class Base {
|
||||
// [SOME_CONSTANT]: boolean;
|
||||
// }
|
||||
// export class Derived extends Base {
|
||||
//
|
||||
// ^
|
||||
// | ----------------------------------------------------------------------
|
||||
// | abstract
|
||||
// | accessor
|
||||
// | async
|
||||
// | constructor
|
||||
// | declare
|
||||
// | get
|
||||
// | override
|
||||
// | private
|
||||
// | protected
|
||||
// | public
|
||||
// | readonly
|
||||
// | set
|
||||
// | static
|
||||
// | (property) Base[SOME_CONSTANT]: boolean
|
||||
// | ----------------------------------------------------------------------
|
||||
// }
|
||||
|
||||
[
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/completionsClassMembers5.ts",
|
||||
"position": 134,
|
||||
"name": ""
|
||||
},
|
||||
"item": {
|
||||
"flags": 0,
|
||||
"isGlobalCompletion": false,
|
||||
"isMemberCompletion": true,
|
||||
"isNewIdentifierLocation": true,
|
||||
"entries": [
|
||||
{
|
||||
"name": "abstract",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "abstract",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "accessor",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "accessor",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "async",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "async",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "constructor",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "constructor",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "declare",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "declare",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "get",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "get",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "override",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "override",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "private",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "private",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "protected",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "protected",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "public",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "public",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "readonly",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "readonly",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "set",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "static",
|
||||
"kind": "keyword",
|
||||
"kindModifiers": "",
|
||||
"sortText": "15",
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "static",
|
||||
"kind": "keyword"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "[SOME_CONSTANT]",
|
||||
"kind": "property",
|
||||
"kindModifiers": "",
|
||||
"sortText": "17",
|
||||
"insertText": "[SOME_CONSTANT]: boolean;",
|
||||
"isSnippet": true,
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "property",
|
||||
"kind": "text"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "Base",
|
||||
"kind": "className"
|
||||
},
|
||||
{
|
||||
"text": "[",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "SOME_CONSTANT",
|
||||
"kind": "propertyName"
|
||||
},
|
||||
{
|
||||
"text": "]",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "boolean",
|
||||
"kind": "keyword"
|
||||
}
|
||||
],
|
||||
"documentation": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
15
tests/cases/fourslash/completionsClassMembers5.ts
Normal file
15
tests/cases/fourslash/completionsClassMembers5.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////export const SOME_CONSTANT = 'SOME_TEXT';
|
||||
////export class Base {
|
||||
//// [SOME_CONSTANT]: boolean;
|
||||
////}
|
||||
////export class Derived extends Base {
|
||||
//// /**/
|
||||
////}
|
||||
|
||||
verify.baselineCompletions({
|
||||
includeCompletionsWithInsertText: true,
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithClassMemberSnippets: true,
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user