mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Completion list for a class extending another class should contain members from base class
Handles #7158
This commit is contained in:
@@ -679,10 +679,6 @@ namespace ts {
|
||||
return type.flags & TypeFlags.Object ? (<ObjectType>type).objectFlags : 0;
|
||||
}
|
||||
|
||||
function getCheckFlags(symbol: Symbol): CheckFlags {
|
||||
return symbol.flags & SymbolFlags.Transient ? (<TransientSymbol>symbol).checkFlags : 0;
|
||||
}
|
||||
|
||||
function isGlobalSourceFile(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(<SourceFile>node);
|
||||
}
|
||||
@@ -13928,25 +13924,6 @@ namespace ts {
|
||||
return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.PropertyDeclaration;
|
||||
}
|
||||
|
||||
function getDeclarationModifierFlagsFromSymbol(s: Symbol): ModifierFlags {
|
||||
if (s.valueDeclaration) {
|
||||
const flags = getCombinedModifierFlags(s.valueDeclaration);
|
||||
return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier;
|
||||
}
|
||||
if (getCheckFlags(s) & CheckFlags.Synthetic) {
|
||||
const checkFlags = (<TransientSymbol>s).checkFlags;
|
||||
const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private :
|
||||
checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public :
|
||||
ModifierFlags.Protected;
|
||||
const staticModifier = checkFlags & CheckFlags.ContainsStatic ? ModifierFlags.Static : 0;
|
||||
return accessModifier | staticModifier;
|
||||
}
|
||||
if (s.flags & SymbolFlags.Prototype) {
|
||||
return ModifierFlags.Public | ModifierFlags.Static;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getDeclarationNodeFlagsFromSymbol(s: Symbol): NodeFlags {
|
||||
return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : 0;
|
||||
}
|
||||
|
||||
@@ -4200,6 +4200,29 @@ namespace ts {
|
||||
// Firefox has Object.prototype.watch
|
||||
return options.watch && options.hasOwnProperty("watch");
|
||||
}
|
||||
|
||||
export function getCheckFlags(symbol: Symbol): CheckFlags {
|
||||
return symbol.flags & SymbolFlags.Transient ? (<TransientSymbol>symbol).checkFlags : 0;
|
||||
}
|
||||
|
||||
export function getDeclarationModifierFlagsFromSymbol(s: Symbol): ModifierFlags {
|
||||
if (s.valueDeclaration) {
|
||||
const flags = getCombinedModifierFlags(s.valueDeclaration);
|
||||
return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier;
|
||||
}
|
||||
if (getCheckFlags(s) & CheckFlags.Synthetic) {
|
||||
const checkFlags = (<TransientSymbol>s).checkFlags;
|
||||
const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private :
|
||||
checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public :
|
||||
ModifierFlags.Protected;
|
||||
const staticModifier = checkFlags & CheckFlags.ContainsStatic ? ModifierFlags.Static : 0;
|
||||
return accessModifier | staticModifier;
|
||||
}
|
||||
if (s.flags & SymbolFlags.Prototype) {
|
||||
return ModifierFlags.Public | ModifierFlags.Static;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag } = completionData;
|
||||
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords } = completionData;
|
||||
|
||||
if (requestJsDocTagName) {
|
||||
// If the current position is a jsDoc tag name, only tag names should be provided for completion
|
||||
@@ -52,7 +52,7 @@ namespace ts.Completions {
|
||||
sortText: "0",
|
||||
});
|
||||
}
|
||||
else {
|
||||
else if (!hasFilteredClassMemberKeywords) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -60,8 +60,11 @@ namespace ts.Completions {
|
||||
getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log);
|
||||
}
|
||||
|
||||
if (hasFilteredClassMemberKeywords) {
|
||||
addRange(entries, classMemberKeywordCompletions);
|
||||
}
|
||||
// Add keywords if this is not a member completion list
|
||||
if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
|
||||
else if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
|
||||
addRange(entries, keywordCompletions);
|
||||
}
|
||||
|
||||
@@ -406,7 +409,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
if (requestJsDocTagName || requestJsDocTag) {
|
||||
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag };
|
||||
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords: false };
|
||||
}
|
||||
|
||||
if (!insideJsDocTagExpression) {
|
||||
@@ -505,6 +508,7 @@ namespace ts.Completions {
|
||||
let isGlobalCompletion = false;
|
||||
let isMemberCompletion: boolean;
|
||||
let isNewIdentifierLocation: boolean;
|
||||
let hasFilteredClassMemberKeywords = false;
|
||||
let symbols: Symbol[] = [];
|
||||
|
||||
if (isRightOfDot) {
|
||||
@@ -542,7 +546,7 @@ namespace ts.Completions {
|
||||
|
||||
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
|
||||
|
||||
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag };
|
||||
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords };
|
||||
|
||||
function getTypeScriptMemberSymbols(): void {
|
||||
// Right of dot member completion list
|
||||
@@ -599,6 +603,7 @@ namespace ts.Completions {
|
||||
function tryGetGlobalSymbols(): boolean {
|
||||
let objectLikeContainer: ObjectLiteralExpression | BindingPattern;
|
||||
let namedImportsOrExports: NamedImportsOrExports;
|
||||
let classLikeContainer: ClassLikeDeclaration;
|
||||
let jsxContainer: JsxOpeningLikeElement;
|
||||
|
||||
if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) {
|
||||
@@ -611,6 +616,11 @@ namespace ts.Completions {
|
||||
return tryGetImportOrExportClauseCompletionSymbols(namedImportsOrExports);
|
||||
}
|
||||
|
||||
if (classLikeContainer = tryGetClassLikeCompletionContainer(contextToken)) {
|
||||
// cursor inside class declaration
|
||||
return tryGetClassLikeCompletionSymbols(classLikeContainer);
|
||||
}
|
||||
|
||||
if (jsxContainer = tryGetContainingJsxElement(contextToken)) {
|
||||
let attrsType: Type;
|
||||
if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) {
|
||||
@@ -913,6 +923,31 @@ namespace ts.Completions {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates relevant symbols for completion in class declaration
|
||||
* Relevant symbols are stored in the captured 'symbols' variable.
|
||||
*
|
||||
* @returns true if 'symbols' was successfully populated; false otherwise.
|
||||
*/
|
||||
function tryGetClassLikeCompletionSymbols(classLikeDeclaration: ClassLikeDeclaration): boolean {
|
||||
// We're looking up possible property names from parent type.
|
||||
isMemberCompletion = true;
|
||||
// Declaring new property/method/accessor
|
||||
isNewIdentifierLocation = true;
|
||||
// Has keywords for class elements
|
||||
hasFilteredClassMemberKeywords = true;
|
||||
|
||||
const baseTypeNode = getClassExtendsHeritageClauseElement(classLikeDeclaration);
|
||||
if (baseTypeNode) {
|
||||
const baseType = typeChecker.getTypeAtLocation(baseTypeNode);
|
||||
// List of property symbols of base type that are not private
|
||||
symbols = filter(typeChecker.getPropertiesOfType(baseType),
|
||||
baseProperty => !(getDeclarationModifierFlagsFromSymbol(baseProperty) & ModifierFlags.Private));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the immediate owning object literal or binding pattern of a context token,
|
||||
* on the condition that one exists and that the context implies completion should be given.
|
||||
@@ -953,6 +988,38 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the immediate owning class declaration of a context token,
|
||||
* on the condition that one exists and that the context implies completion should be given.
|
||||
*/
|
||||
function tryGetClassLikeCompletionContainer(contextToken: Node): ClassLikeDeclaration {
|
||||
if (contextToken) {
|
||||
switch (contextToken.kind) {
|
||||
case SyntaxKind.OpenBraceToken: // class c { |
|
||||
if (isClassLike(contextToken.parent)) {
|
||||
return contextToken.parent;
|
||||
}
|
||||
break;
|
||||
|
||||
// class c {getValue(): number; | }
|
||||
case SyntaxKind.CommaToken:
|
||||
case SyntaxKind.SemicolonToken:
|
||||
// class c { method() { } | }
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
if (isClassLike(location)) {
|
||||
return location;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// class c { method() { } | method2() { } }
|
||||
if (location && location.kind === SyntaxKind.SyntaxList && isClassLike(location.parent)) {
|
||||
return location.parent;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetContainingJsxElement(contextToken: Node): JsxOpeningLikeElement {
|
||||
if (contextToken) {
|
||||
const parent = contextToken.parent;
|
||||
@@ -1306,6 +1373,21 @@ namespace ts.Completions {
|
||||
});
|
||||
}
|
||||
|
||||
const classMemberKeywordCompletions = filter(keywordCompletions, entry => {
|
||||
switch (stringToToken(entry.name)) {
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
case SyntaxKind.StaticKeyword:
|
||||
case SyntaxKind.ConstructorKeyword:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
case SyntaxKind.GetKeyword:
|
||||
case SyntaxKind.SetKeyword:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
function isEqualityExpression(node: Node): node is BinaryExpression {
|
||||
return isBinaryExpression(node) && isEqualityOperatorKind(node.operatorToken.kind);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user