mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-06 23:59:42 -05:00
Merge pull request #15614 from Microsoft/completionListForClassElementDeclarations
When writing class elements show completion with allowed keywords and inheritted properties
This commit is contained in:
@@ -685,10 +685,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);
|
||||
}
|
||||
@@ -14047,25 +14043,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;
|
||||
}
|
||||
|
||||
@@ -4235,6 +4235,29 @@ namespace ts {
|
||||
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;
|
||||
}
|
||||
|
||||
export function levenshtein(s1: string, s2: string): number {
|
||||
let previous: number[] = new Array(s2.length + 1);
|
||||
let current: number[] = new Array(s2.length + 1);
|
||||
|
||||
@@ -3417,6 +3417,18 @@ namespace FourSlashInterface {
|
||||
|
||||
export class VerifyNegatable {
|
||||
public not: VerifyNegatable;
|
||||
public allowedClassElementKeywords = [
|
||||
"public",
|
||||
"private",
|
||||
"protected",
|
||||
"static",
|
||||
"abstract",
|
||||
"readonly",
|
||||
"get",
|
||||
"set",
|
||||
"constructor",
|
||||
"async"
|
||||
];
|
||||
|
||||
constructor(protected state: FourSlash.TestState, private negative = false) {
|
||||
if (!negative) {
|
||||
@@ -3453,6 +3465,12 @@ namespace FourSlashInterface {
|
||||
this.state.verifyCompletionListIsEmpty(this.negative);
|
||||
}
|
||||
|
||||
public completionListContainsClassElementKeywords() {
|
||||
for (const keyword of this.allowedClassElementKeywords) {
|
||||
this.completionListContains(keyword, keyword, /*documentation*/ undefined, "keyword");
|
||||
}
|
||||
}
|
||||
|
||||
public completionListIsGlobal(expected: boolean) {
|
||||
this.state.verifyCompletionListIsGlobal(expected);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -411,7 +414,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) {
|
||||
@@ -510,6 +513,7 @@ namespace ts.Completions {
|
||||
let isGlobalCompletion = false;
|
||||
let isMemberCompletion: boolean;
|
||||
let isNewIdentifierLocation: boolean;
|
||||
let hasFilteredClassMemberKeywords = false;
|
||||
let symbols: Symbol[] = [];
|
||||
|
||||
if (isRightOfDot) {
|
||||
@@ -547,7 +551,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
|
||||
@@ -604,6 +608,7 @@ namespace ts.Completions {
|
||||
function tryGetGlobalSymbols(): boolean {
|
||||
let objectLikeContainer: ObjectLiteralExpression | BindingPattern;
|
||||
let namedImportsOrExports: NamedImportsOrExports;
|
||||
let classLikeContainer: ClassLikeDeclaration;
|
||||
let jsxContainer: JsxOpeningLikeElement;
|
||||
|
||||
if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) {
|
||||
@@ -616,6 +621,12 @@ namespace ts.Completions {
|
||||
return tryGetImportOrExportClauseCompletionSymbols(namedImportsOrExports);
|
||||
}
|
||||
|
||||
if (classLikeContainer = tryGetClassLikeCompletionContainer(contextToken)) {
|
||||
// cursor inside class declaration
|
||||
getGetClassLikeCompletionSymbols(classLikeContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (jsxContainer = tryGetContainingJsxElement(contextToken)) {
|
||||
let attrsType: Type;
|
||||
if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) {
|
||||
@@ -913,6 +924,62 @@ namespace ts.Completions {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates relevant symbols for completion in class declaration
|
||||
* Relevant symbols are stored in the captured 'symbols' variable.
|
||||
*/
|
||||
function getGetClassLikeCompletionSymbols(classLikeDeclaration: ClassLikeDeclaration) {
|
||||
// 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);
|
||||
const implementsTypeNodes = getClassImplementsHeritageClauseElements(classLikeDeclaration);
|
||||
if (baseTypeNode || implementsTypeNodes) {
|
||||
const classElement = contextToken.parent;
|
||||
let classElementModifierFlags = isClassElement(classElement) && getModifierFlags(classElement);
|
||||
// If this is context token is not something we are editing now, consider if this would lead to be modifier
|
||||
if (contextToken.kind === SyntaxKind.Identifier && !isCurrentlyEditingNode(contextToken)) {
|
||||
switch (contextToken.getText()) {
|
||||
case "private":
|
||||
classElementModifierFlags = classElementModifierFlags | ModifierFlags.Private;
|
||||
break;
|
||||
case "static":
|
||||
classElementModifierFlags = classElementModifierFlags | ModifierFlags.Static;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No member list for private methods
|
||||
if (!(classElementModifierFlags & ModifierFlags.Private)) {
|
||||
let baseClassTypeToGetPropertiesFrom: Type;
|
||||
if (baseTypeNode) {
|
||||
baseClassTypeToGetPropertiesFrom = typeChecker.getTypeAtLocation(baseTypeNode);
|
||||
if (classElementModifierFlags & ModifierFlags.Static) {
|
||||
// Use static class to get property symbols from
|
||||
baseClassTypeToGetPropertiesFrom = typeChecker.getTypeOfSymbolAtLocation(
|
||||
baseClassTypeToGetPropertiesFrom.symbol, classLikeDeclaration);
|
||||
}
|
||||
}
|
||||
const implementedInterfaceTypePropertySymbols = (classElementModifierFlags & ModifierFlags.Static) ?
|
||||
undefined :
|
||||
flatMap(implementsTypeNodes, typeNode => typeChecker.getPropertiesOfType(typeChecker.getTypeAtLocation(typeNode)));
|
||||
|
||||
// List of property symbols of base type that are not private and already implemented
|
||||
symbols = filterClassMembersList(
|
||||
baseClassTypeToGetPropertiesFrom ?
|
||||
typeChecker.getPropertiesOfType(baseClassTypeToGetPropertiesFrom) :
|
||||
undefined,
|
||||
implementedInterfaceTypePropertySymbols,
|
||||
classLikeDeclaration.members,
|
||||
classElementModifierFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +1020,49 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isFromClassElementDeclaration(node: Node) {
|
||||
return isClassElement(node.parent) && isClassLike(node.parent.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
default:
|
||||
if (isFromClassElementDeclaration(contextToken) &&
|
||||
(isClassMemberCompletionKeyword(contextToken.kind) ||
|
||||
isClassMemberCompletionKeywordText(contextToken.getText()))) {
|
||||
return contextToken.parent.parent as ClassLikeDeclaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
@@ -1081,7 +1191,7 @@ namespace ts.Completions {
|
||||
isFunction(containingNodeKind);
|
||||
|
||||
case SyntaxKind.StaticKeyword:
|
||||
return containingNodeKind === SyntaxKind.PropertyDeclaration;
|
||||
return containingNodeKind === SyntaxKind.PropertyDeclaration && !isClassLike(contextToken.parent.parent);
|
||||
|
||||
case SyntaxKind.DotDotDotToken:
|
||||
return containingNodeKind === SyntaxKind.Parameter ||
|
||||
@@ -1098,13 +1208,17 @@ namespace ts.Completions {
|
||||
containingNodeKind === SyntaxKind.ExportSpecifier ||
|
||||
containingNodeKind === SyntaxKind.NamespaceImport;
|
||||
|
||||
case SyntaxKind.GetKeyword:
|
||||
case SyntaxKind.SetKeyword:
|
||||
if (isFromClassElementDeclaration(contextToken)) {
|
||||
return false;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.ClassKeyword:
|
||||
case SyntaxKind.EnumKeyword:
|
||||
case SyntaxKind.InterfaceKeyword:
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
case SyntaxKind.VarKeyword:
|
||||
case SyntaxKind.GetKeyword:
|
||||
case SyntaxKind.SetKeyword:
|
||||
case SyntaxKind.ImportKeyword:
|
||||
case SyntaxKind.LetKeyword:
|
||||
case SyntaxKind.ConstKeyword:
|
||||
@@ -1113,6 +1227,13 @@ namespace ts.Completions {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the previous token is keyword correspoding to class member completion keyword
|
||||
// there will be completion available here
|
||||
if (isClassMemberCompletionKeywordText(contextToken.getText()) &&
|
||||
isFromClassElementDeclaration(contextToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Previous token may have been a keyword that was converted to an identifier.
|
||||
switch (contextToken.getText()) {
|
||||
case "abstract":
|
||||
@@ -1159,7 +1280,7 @@ namespace ts.Completions {
|
||||
|
||||
for (const element of namedImportsOrExports) {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (element.getStart() <= position && position <= element.getEnd()) {
|
||||
if (isCurrentlyEditingNode(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1198,7 +1319,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (m.getStart() <= position && position <= m.getEnd()) {
|
||||
if (isCurrentlyEditingNode(m)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1223,6 +1344,58 @@ namespace ts.Completions {
|
||||
return filter(contextualMemberSymbols, m => !existingMemberNames.get(m.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out completion suggestions for class elements.
|
||||
*
|
||||
* @returns Symbols to be suggested in an class element depending on existing memebers and symbol flags
|
||||
*/
|
||||
function filterClassMembersList(baseSymbols: Symbol[], implementingTypeSymbols: Symbol[], existingMembers: ClassElement[], currentClassElementModifierFlags: ModifierFlags): Symbol[] {
|
||||
const existingMemberNames = createMap<boolean>();
|
||||
for (const m of existingMembers) {
|
||||
// Ignore omitted expressions for missing members
|
||||
if (m.kind !== SyntaxKind.PropertyDeclaration &&
|
||||
m.kind !== SyntaxKind.MethodDeclaration &&
|
||||
m.kind !== SyntaxKind.GetAccessor &&
|
||||
m.kind !== SyntaxKind.SetAccessor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (isCurrentlyEditingNode(m)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dont filter member even if the name matches if it is declared private in the list
|
||||
if (hasModifier(m, ModifierFlags.Private)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// do not filter it out if the static presence doesnt match
|
||||
const mIsStatic = hasModifier(m, ModifierFlags.Static);
|
||||
const currentElementIsStatic = !!(currentClassElementModifierFlags & ModifierFlags.Static);
|
||||
if ((mIsStatic && !currentElementIsStatic) ||
|
||||
(!mIsStatic && currentElementIsStatic)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingName = getPropertyNameForPropertyNameNode(m.name);
|
||||
if (existingName) {
|
||||
existingMemberNames.set(existingName, true);
|
||||
}
|
||||
}
|
||||
|
||||
return concatenate(
|
||||
filter(baseSymbols, baseProperty => isValidProperty(baseProperty, ModifierFlags.Private)),
|
||||
filter(implementingTypeSymbols, implementingProperty => isValidProperty(implementingProperty, ModifierFlags.NonPublicAccessibilityModifier))
|
||||
);
|
||||
|
||||
function isValidProperty(propertySymbol: Symbol, inValidModifierFlags: ModifierFlags) {
|
||||
return !existingMemberNames.get(propertySymbol.name) &&
|
||||
propertySymbol.getDeclarations() &&
|
||||
!(getDeclarationModifierFlagsFromSymbol(propertySymbol) & inValidModifierFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out completion suggestions from 'symbols' according to existing JSX attributes.
|
||||
*
|
||||
@@ -1233,7 +1406,7 @@ namespace ts.Completions {
|
||||
const seenNames = createMap<boolean>();
|
||||
for (const attr of attributes) {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (attr.getStart() <= position && position <= attr.getEnd()) {
|
||||
if (isCurrentlyEditingNode(attr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1244,6 +1417,10 @@ namespace ts.Completions {
|
||||
|
||||
return filter(symbols, a => !seenNames.get(a.name));
|
||||
}
|
||||
|
||||
function isCurrentlyEditingNode(node: Node): boolean {
|
||||
return node.getStart() <= position && position <= node.getEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1306,6 +1483,29 @@ namespace ts.Completions {
|
||||
});
|
||||
}
|
||||
|
||||
function isClassMemberCompletionKeyword(kind: SyntaxKind) {
|
||||
switch (kind) {
|
||||
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:
|
||||
case SyntaxKind.AsyncKeyword:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function isClassMemberCompletionKeywordText(text: string) {
|
||||
return isClassMemberCompletionKeyword(stringToToken(text));
|
||||
}
|
||||
|
||||
const classMemberKeywordCompletions = filter(keywordCompletions, entry =>
|
||||
isClassMemberCompletionKeywordText(entry.name));
|
||||
|
||||
function isEqualityExpression(node: Node): node is BinaryExpression {
|
||||
return isBinaryExpression(node) && isEqualityOperatorKind(node.operatorToken.kind);
|
||||
}
|
||||
|
||||
@@ -200,27 +200,33 @@ namespace ts.SymbolDisplay {
|
||||
(location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration
|
||||
// get the signature from the declaration and write it
|
||||
const functionDeclaration = <FunctionLikeDeclaration>location.parent;
|
||||
const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures();
|
||||
if (!typeChecker.isImplementationOfOverload(functionDeclaration)) {
|
||||
signature = typeChecker.getSignatureFromDeclaration(functionDeclaration);
|
||||
}
|
||||
else {
|
||||
signature = allSignatures[0];
|
||||
}
|
||||
// Use function declaration to write the signatures only if the symbol corresponding to this declaration
|
||||
const locationIsSymbolDeclaration = findDeclaration(symbol, declaration =>
|
||||
declaration === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent : functionDeclaration));
|
||||
|
||||
if (functionDeclaration.kind === SyntaxKind.Constructor) {
|
||||
// show (constructor) Type(...) signature
|
||||
symbolKind = ScriptElementKind.constructorImplementationElement;
|
||||
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
|
||||
}
|
||||
else {
|
||||
// (function/method) symbol(..signature)
|
||||
addPrefixForAnyFunctionOrVar(functionDeclaration.kind === SyntaxKind.CallSignature &&
|
||||
!(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind);
|
||||
}
|
||||
if (locationIsSymbolDeclaration) {
|
||||
const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures();
|
||||
if (!typeChecker.isImplementationOfOverload(functionDeclaration)) {
|
||||
signature = typeChecker.getSignatureFromDeclaration(functionDeclaration);
|
||||
}
|
||||
else {
|
||||
signature = allSignatures[0];
|
||||
}
|
||||
|
||||
addSignatureDisplayParts(signature, allSignatures);
|
||||
hasAddedSymbolInfo = true;
|
||||
if (functionDeclaration.kind === SyntaxKind.Constructor) {
|
||||
// show (constructor) Type(...) signature
|
||||
symbolKind = ScriptElementKind.constructorImplementationElement;
|
||||
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
|
||||
}
|
||||
else {
|
||||
// (function/method) symbol(..signature)
|
||||
addPrefixForAnyFunctionOrVar(functionDeclaration.kind === SyntaxKind.CallSignature &&
|
||||
!(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind);
|
||||
}
|
||||
|
||||
addSignatureDisplayParts(signature, allSignatures);
|
||||
hasAddedSymbolInfo = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
256
tests/cases/fourslash/completionEntryForClassMembers.ts
Normal file
256
tests/cases/fourslash/completionEntryForClassMembers.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
|
||||
////abstract class B {
|
||||
//// private privateMethod() { }
|
||||
//// protected protectedMethod() { };
|
||||
//// static staticMethod() { }
|
||||
//// abstract getValue(): number;
|
||||
//// /*abstractClass*/
|
||||
////}
|
||||
////class C extends B {
|
||||
//// /*classThatIsEmptyAndExtendingAnotherClass*/
|
||||
////}
|
||||
////class D extends B {
|
||||
//// /*classThatHasAlreadyImplementedAnotherClassMethod*/
|
||||
//// getValue() {
|
||||
//// return 10;
|
||||
//// }
|
||||
//// /*classThatHasAlreadyImplementedAnotherClassMethodAfterMethod*/
|
||||
////}
|
||||
////class D1 extends B {
|
||||
//// /*classThatHasDifferentMethodThanBase*/
|
||||
//// getValue1() {
|
||||
//// return 10;
|
||||
//// }
|
||||
//// /*classThatHasDifferentMethodThanBaseAfterMethod*/
|
||||
////}
|
||||
////class D2 extends B {
|
||||
//// /*classThatHasAlreadyImplementedAnotherClassProtectedMethod*/
|
||||
//// protectedMethod() {
|
||||
//// }
|
||||
//// /*classThatHasDifferentMethodThanBaseAfterProtectedMethod*/
|
||||
////}
|
||||
////class D3 extends D1 {
|
||||
//// /*classThatExtendsClassExtendingAnotherClass*/
|
||||
////}
|
||||
////class D4 extends D1 {
|
||||
//// static /*classThatExtendsClassExtendingAnotherClassAndTypesStatic*/
|
||||
////}
|
||||
////class D5 extends D2 {
|
||||
//// /*classThatExtendsClassExtendingAnotherClassWithOverridingMember*/
|
||||
////}
|
||||
////class D6 extends D2 {
|
||||
//// static /*classThatExtendsClassExtendingAnotherClassWithOverridingMemberAndTypesStatic*/
|
||||
////}
|
||||
////class E {
|
||||
//// /*classThatDoesNotExtendAnotherClass*/
|
||||
////}
|
||||
////class F extends B {
|
||||
//// public /*classThatHasWrittenPublicKeyword*/
|
||||
////}
|
||||
////class F2 extends B {
|
||||
//// private /*classThatHasWrittenPrivateKeyword*/
|
||||
////}
|
||||
////class G extends B {
|
||||
//// static /*classElementContainingStatic*/
|
||||
////}
|
||||
////class G2 extends B {
|
||||
//// private static /*classElementContainingPrivateStatic*/
|
||||
////}
|
||||
////class H extends B {
|
||||
//// prop/*classThatStartedWritingIdentifier*/
|
||||
////}
|
||||
//////Class for location verification
|
||||
////class I extends B {
|
||||
//// prop0: number
|
||||
//// /*propDeclarationWithoutSemicolon*/
|
||||
//// prop: number;
|
||||
//// /*propDeclarationWithSemicolon*/
|
||||
//// prop1 = 10;
|
||||
//// /*propAssignmentWithSemicolon*/
|
||||
//// prop2 = 10
|
||||
//// /*propAssignmentWithoutSemicolon*/
|
||||
//// method(): number
|
||||
//// /*methodSignatureWithoutSemicolon*/
|
||||
//// method2(): number;
|
||||
//// /*methodSignatureWithSemicolon*/
|
||||
//// method3() {
|
||||
//// /*InsideMethod*/
|
||||
//// }
|
||||
//// /*methodImplementation*/
|
||||
//// get c()
|
||||
//// /*accessorSignatureWithoutSemicolon*/
|
||||
//// set c()
|
||||
//// {
|
||||
//// }
|
||||
//// /*accessorSignatureImplementation*/
|
||||
////}
|
||||
////class J extends B {
|
||||
//// get /*classThatHasWrittenGetKeyword*/
|
||||
////}
|
||||
////class K extends B {
|
||||
//// set /*classThatHasWrittenSetKeyword*/
|
||||
////}
|
||||
////class J extends B {
|
||||
//// get identi/*classThatStartedWritingIdentifierOfGetAccessor*/
|
||||
////}
|
||||
////class K extends B {
|
||||
//// set identi/*classThatStartedWritingIdentifierOfSetAccessor*/
|
||||
////}
|
||||
////class L extends B {
|
||||
//// public identi/*classThatStartedWritingIdentifierAfterModifier*/
|
||||
////}
|
||||
////class L2 extends B {
|
||||
//// private identi/*classThatStartedWritingIdentifierAfterPrivateModifier*/
|
||||
////}
|
||||
////class M extends B {
|
||||
//// static identi/*classThatStartedWritingIdentifierAfterStaticModifier*/
|
||||
////}
|
||||
////class M extends B {
|
||||
//// private static identi/*classThatStartedWritingIdentifierAfterPrivateStaticModifier*/
|
||||
////}
|
||||
////class N extends B {
|
||||
//// async /*classThatHasWrittenAsyncKeyword*/
|
||||
////}
|
||||
|
||||
const allowedKeywordCount = verify.allowedClassElementKeywords.length;
|
||||
type CompletionInfo = [string, string];
|
||||
type CompletionInfoVerifier = { validMembers: CompletionInfo[], invalidMembers: CompletionInfo[] };
|
||||
|
||||
function verifyClassElementLocations({ validMembers, invalidMembers }: CompletionInfoVerifier, classElementCompletionLocations: string[]) {
|
||||
for (const marker of classElementCompletionLocations) {
|
||||
goTo.marker(marker);
|
||||
verifyCompletionInfo(validMembers, verify);
|
||||
verifyCompletionInfo(invalidMembers, verify.not);
|
||||
verify.completionListContainsClassElementKeywords();
|
||||
verify.completionListCount(allowedKeywordCount + validMembers.length);
|
||||
}
|
||||
}
|
||||
|
||||
function verifyCompletionInfo(memberInfo: CompletionInfo[], verify: FourSlashInterface.verifyNegatable) {
|
||||
for (const [symbol, text] of memberInfo) {
|
||||
verify.completionListContains(symbol, text, /*documentation*/ undefined, "method");
|
||||
}
|
||||
}
|
||||
|
||||
const allMembersOfBase: CompletionInfo[] = [
|
||||
["getValue", "(method) B.getValue(): number"],
|
||||
["protectedMethod", "(method) B.protectedMethod(): void"],
|
||||
["privateMethod", "(method) B.privateMethod(): void"],
|
||||
["staticMethod", "(method) B.staticMethod(): void"]
|
||||
];
|
||||
const publicCompletionInfoOfD1: CompletionInfo[] = [
|
||||
["getValue1", "(method) D1.getValue1(): number"]
|
||||
];
|
||||
const publicCompletionInfoOfD2: CompletionInfo[] = [
|
||||
["protectedMethod", "(method) D2.protectedMethod(): void"]
|
||||
];
|
||||
function filterCompletionInfo(fn: (a: CompletionInfo) => boolean): CompletionInfoVerifier {
|
||||
const validMembers: CompletionInfo[] = [];
|
||||
const invalidMembers: CompletionInfo[] = [];
|
||||
for (const member of allMembersOfBase) {
|
||||
if (fn(member)) {
|
||||
validMembers.push(member);
|
||||
}
|
||||
else {
|
||||
invalidMembers.push(member);
|
||||
}
|
||||
}
|
||||
return { validMembers, invalidMembers };
|
||||
}
|
||||
|
||||
|
||||
const instanceMemberInfo = filterCompletionInfo(([a]: CompletionInfo) => a === "getValue" || a === "protectedMethod");
|
||||
const staticMemberInfo = filterCompletionInfo(([a]: CompletionInfo) => a === "staticMethod");
|
||||
const instanceWithoutProtectedMemberInfo = filterCompletionInfo(([a]: CompletionInfo) => a === "getValue");
|
||||
const instanceWithoutPublicMemberInfo = filterCompletionInfo(([a]: CompletionInfo) => a === "protectedMethod");
|
||||
|
||||
const instanceMemberInfoD1: CompletionInfoVerifier = {
|
||||
validMembers: instanceMemberInfo.validMembers.concat(publicCompletionInfoOfD1),
|
||||
invalidMembers: instanceMemberInfo.invalidMembers
|
||||
};
|
||||
const instanceMemberInfoD2: CompletionInfoVerifier = {
|
||||
validMembers: instanceWithoutProtectedMemberInfo.validMembers.concat(publicCompletionInfoOfD2),
|
||||
invalidMembers: instanceWithoutProtectedMemberInfo.invalidMembers
|
||||
};
|
||||
const staticMemberInfoDn: CompletionInfoVerifier = {
|
||||
validMembers: staticMemberInfo.validMembers,
|
||||
invalidMembers: staticMemberInfo.invalidMembers.concat(publicCompletionInfoOfD1, publicCompletionInfoOfD2)
|
||||
};
|
||||
|
||||
// Not a class element declaration location
|
||||
const nonClassElementMarkers = [
|
||||
"InsideMethod"
|
||||
];
|
||||
for (const marker of nonClassElementMarkers) {
|
||||
goTo.marker(marker);
|
||||
verifyCompletionInfo(allMembersOfBase, verify.not);
|
||||
verify.not.completionListIsEmpty();
|
||||
}
|
||||
|
||||
// Only keywords allowed at this position since they dont extend the class or are private
|
||||
const onlyClassElementKeywordLocations = [
|
||||
"abstractClass",
|
||||
"classThatDoesNotExtendAnotherClass",
|
||||
"classThatHasWrittenPrivateKeyword",
|
||||
"classElementContainingPrivateStatic",
|
||||
"classThatStartedWritingIdentifierAfterPrivateModifier",
|
||||
"classThatStartedWritingIdentifierAfterPrivateStaticModifier"
|
||||
];
|
||||
verifyClassElementLocations({ validMembers: [], invalidMembers: allMembersOfBase }, onlyClassElementKeywordLocations);
|
||||
|
||||
// Instance base members and class member keywords allowed
|
||||
const classInstanceElementLocations = [
|
||||
"classThatIsEmptyAndExtendingAnotherClass",
|
||||
"classThatHasDifferentMethodThanBase",
|
||||
"classThatHasDifferentMethodThanBaseAfterMethod",
|
||||
"classThatHasWrittenPublicKeyword",
|
||||
"classThatStartedWritingIdentifier",
|
||||
"propDeclarationWithoutSemicolon",
|
||||
"propDeclarationWithSemicolon",
|
||||
"propAssignmentWithSemicolon",
|
||||
"propAssignmentWithoutSemicolon",
|
||||
"methodSignatureWithoutSemicolon",
|
||||
"methodSignatureWithSemicolon",
|
||||
"methodImplementation",
|
||||
"accessorSignatureWithoutSemicolon",
|
||||
"accessorSignatureImplementation",
|
||||
"classThatHasWrittenGetKeyword",
|
||||
"classThatHasWrittenSetKeyword",
|
||||
"classThatStartedWritingIdentifierOfGetAccessor",
|
||||
"classThatStartedWritingIdentifierOfSetAccessor",
|
||||
"classThatStartedWritingIdentifierAfterModifier",
|
||||
"classThatHasWrittenAsyncKeyword"
|
||||
];
|
||||
verifyClassElementLocations(instanceMemberInfo, classInstanceElementLocations);
|
||||
|
||||
// Static Base members and class member keywords allowed
|
||||
const staticClassLocations = [
|
||||
"classElementContainingStatic",
|
||||
"classThatStartedWritingIdentifierAfterStaticModifier"
|
||||
];
|
||||
verifyClassElementLocations(staticMemberInfo, staticClassLocations);
|
||||
|
||||
const classInstanceElementWithoutPublicMethodLocations = [
|
||||
"classThatHasAlreadyImplementedAnotherClassMethod",
|
||||
"classThatHasAlreadyImplementedAnotherClassMethodAfterMethod",
|
||||
];
|
||||
verifyClassElementLocations(instanceWithoutPublicMemberInfo, classInstanceElementWithoutPublicMethodLocations);
|
||||
|
||||
const classInstanceElementWithoutProtectedMethodLocations = [
|
||||
"classThatHasAlreadyImplementedAnotherClassProtectedMethod",
|
||||
"classThatHasDifferentMethodThanBaseAfterProtectedMethod",
|
||||
];
|
||||
verifyClassElementLocations(instanceWithoutProtectedMemberInfo, classInstanceElementWithoutProtectedMethodLocations);
|
||||
|
||||
// instance memebers in D1 and base class are shown
|
||||
verifyClassElementLocations(instanceMemberInfoD1, ["classThatExtendsClassExtendingAnotherClass"]);
|
||||
|
||||
// instance memebers in D2 and base class are shown
|
||||
verifyClassElementLocations(instanceMemberInfoD2, ["classThatExtendsClassExtendingAnotherClassWithOverridingMember"]);
|
||||
|
||||
// static base members and class member keywords allowed
|
||||
verifyClassElementLocations(staticMemberInfoDn, [
|
||||
"classThatExtendsClassExtendingAnotherClassAndTypesStatic",
|
||||
"classThatExtendsClassExtendingAnotherClassWithOverridingMemberAndTypesStatic"
|
||||
]);
|
||||
456
tests/cases/fourslash/completionEntryForClassMembers2.ts
Normal file
456
tests/cases/fourslash/completionEntryForClassMembers2.ts
Normal file
@@ -0,0 +1,456 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
|
||||
////interface I {
|
||||
//// methodOfInterface(): number;
|
||||
////}
|
||||
////interface I2 {
|
||||
//// methodOfInterface2(): number;
|
||||
////}
|
||||
////interface I3 {
|
||||
//// getValue(): string;
|
||||
//// method(): string;
|
||||
////}
|
||||
////interface I4 {
|
||||
//// staticMethod(): void;
|
||||
//// method(): string;
|
||||
////}
|
||||
////class B0 {
|
||||
//// private privateMethod() { }
|
||||
//// protected protectedMethod() { }
|
||||
//// static staticMethod() { }
|
||||
//// getValue(): string | boolean { return "hello"; }
|
||||
//// private privateMethod1() { }
|
||||
//// protected protectedMethod1() { }
|
||||
//// static staticMethod1() { }
|
||||
//// getValue1(): string | boolean { return "hello"; }
|
||||
////}
|
||||
////interface I5 extends B0 {
|
||||
//// methodOfInterface5(): number;
|
||||
////}
|
||||
////interface I6 extends B0 {
|
||||
//// methodOfInterface6(): number;
|
||||
//// staticMethod(): void;
|
||||
////}
|
||||
////interface I7 extends I {
|
||||
//// methodOfInterface7(): number;
|
||||
////}
|
||||
////class B {
|
||||
//// private privateMethod() { }
|
||||
//// protected protectedMethod() { }
|
||||
//// static staticMethod() { }
|
||||
//// getValue(): string | boolean { return "hello"; }
|
||||
////}
|
||||
////class C0 implements I, I2 {
|
||||
//// /*implementsIAndI2*/
|
||||
////}
|
||||
////class C00 implements I, I2 {
|
||||
//// static /*implementsIAndI2AndWritingStatic*/
|
||||
////}
|
||||
////class C001 implements I, I2 {
|
||||
//// methodOfInterface/*implementsIAndI2AndWritingMethodNameOfI*/
|
||||
////}
|
||||
////class C extends B implements I, I2 {
|
||||
//// /*extendsBAndImplementsIAndI2*/
|
||||
////}
|
||||
////class C1 extends B implements I, I2 {
|
||||
//// static /*extendsBAndImplementsIAndI2AndWritingStatic*/
|
||||
////}
|
||||
////class D extends B implements I, I2 {
|
||||
//// /*extendsBAndImplementsIAndI2WithMethodFromB*/
|
||||
//// protected protectedMethod() {
|
||||
//// return "protected";
|
||||
//// }
|
||||
////}
|
||||
////class E extends B implements I, I2 {
|
||||
//// /*extendsBAndImplementsIAndI2WithMethodFromI*/
|
||||
//// methodOfInterface() {
|
||||
//// return 1;
|
||||
//// }
|
||||
////}
|
||||
////class F extends B implements I, I2 {
|
||||
//// /*extendsBAndImplementsIAndI2WithMethodFromBAndI*/
|
||||
//// protected protectedMethod() {
|
||||
//// return "protected"
|
||||
//// }
|
||||
//// methodOfInterface() {
|
||||
//// return 1;
|
||||
//// }
|
||||
////}
|
||||
////class F2 extends B implements I, I2 {
|
||||
//// protected protectedMethod() {
|
||||
//// return "protected"
|
||||
//// }
|
||||
//// methodOfInterface() {
|
||||
//// return 1;
|
||||
//// }
|
||||
//// static /*extendsBAndImplementsIAndI2WithMethodFromBAndIAndTypesStatic*/
|
||||
////}
|
||||
////class G extends B implements I3 {
|
||||
//// /*extendsBAndImplementsI3WithSameNameMembers*/
|
||||
////}
|
||||
////class H extends B implements I3 {
|
||||
//// /*extendsBAndImplementsI3WithSameNameMembersAndHasImplementedTheMember*/
|
||||
//// getValue() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
////}
|
||||
////class J extends B0 implements I4 {
|
||||
//// /*extendsB0ThatExtendsAndImplementsI4WithStaticMethod*/
|
||||
////}
|
||||
////class L extends B0 implements I4 {
|
||||
//// /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedAnotherMethod*/
|
||||
//// staticMethod2() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
////}
|
||||
////class K extends B0 implements I4 {
|
||||
//// /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethod*/
|
||||
//// staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
////}
|
||||
////class M extends B0 implements I4 {
|
||||
//// /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsStatic*/
|
||||
//// static staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
////}
|
||||
////class N extends B0 implements I4 {
|
||||
//// /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsBoth*/
|
||||
//// staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
//// static staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
////}
|
||||
////class J1 extends B0 implements I4 {
|
||||
//// static /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodWritingStatic*/
|
||||
////}
|
||||
////class L1 extends B0 implements I4 {
|
||||
//// staticMethod2() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
//// static /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedAnotherMethodWritingStatic*/
|
||||
////}
|
||||
////class K1 extends B0 implements I4 {
|
||||
//// staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
//// static /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodWritingStatic*/
|
||||
////}
|
||||
////class M1 extends B0 implements I4 {
|
||||
//// static staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
//// static /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsStaticWritingStatic*/
|
||||
////}
|
||||
////class N1 extends B0 implements I4 {
|
||||
//// staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
//// static staticMethod() {
|
||||
//// return "hello";
|
||||
//// }
|
||||
//// static /*extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsBothWritingStatic*/
|
||||
////}
|
||||
////class O implements I7 {
|
||||
//// /*implementsI7whichExtendsI*/
|
||||
////}
|
||||
////class P implements I7, I {
|
||||
//// /*implementsI7whichExtendsIAndAlsoImplementsI*/
|
||||
////}
|
||||
////class Q implements I, I7 {
|
||||
//// /*implementsIAndAlsoImplementsI7whichExtendsI*/
|
||||
////}
|
||||
////class R implements I5 {
|
||||
//// /*implementsI5ThatExtendsB0*/
|
||||
////}
|
||||
////class S implements I6 {
|
||||
//// /*implementsI6ThatExtendsB0AndHasStaticMethodOfB0*/
|
||||
////}
|
||||
////class T extends B0 implements I5 {
|
||||
//// /*extendsB0AndImplementsI5ThatExtendsB0*/
|
||||
////}
|
||||
////class U extends B0 implements I6 {
|
||||
//// /*extendsB0AndImplementsI6ThatExtendsB0AndHasStaticMethodOfB0*/
|
||||
////}
|
||||
////class R1 implements I5 {
|
||||
//// static /*implementsI5ThatExtendsB0TypesStatic*/
|
||||
////}
|
||||
////class S1 implements I6 {
|
||||
//// static /*implementsI6ThatExtendsB0AndHasStaticMethodOfB0TypesStatic*/
|
||||
////}
|
||||
////class T1 extends B0 implements I5 {
|
||||
//// static /*extendsB0AndImplementsI5ThatExtendsB0TypesStatic*/
|
||||
////}
|
||||
////class U1 extends B0 implements I6 {
|
||||
//// static /*extendsB0AndImplementsI6ThatExtendsB0AndHasStaticMethodOfB0TypesStatic*/
|
||||
////}
|
||||
|
||||
const allowedKeywordCount = verify.allowedClassElementKeywords.length;
|
||||
type CompletionInfo = [string, string];
|
||||
type CompletionInfoVerifier = { validMembers: CompletionInfo[], invalidMembers: CompletionInfo[] };
|
||||
|
||||
function verifyClassElementLocations({ validMembers, invalidMembers }: CompletionInfoVerifier, classElementCompletionLocations: string[]) {
|
||||
for (const marker of classElementCompletionLocations) {
|
||||
goTo.marker(marker);
|
||||
verifyCompletionInfo(validMembers, verify);
|
||||
verifyCompletionInfo(invalidMembers, verify.not);
|
||||
verify.completionListContainsClassElementKeywords();
|
||||
verify.completionListCount(allowedKeywordCount + validMembers.length);
|
||||
}
|
||||
}
|
||||
|
||||
function verifyCompletionInfo(memberInfo: CompletionInfo[], verify: FourSlashInterface.verifyNegatable) {
|
||||
for (const [symbol, text] of memberInfo) {
|
||||
verify.completionListContains(symbol, text, /*documentation*/ undefined, "method");
|
||||
}
|
||||
}
|
||||
|
||||
const validInstanceMembersOfBaseClassB: CompletionInfo[] = [
|
||||
["getValue", "(method) B.getValue(): string | boolean"],
|
||||
["protectedMethod", "(method) B.protectedMethod(): void"],
|
||||
];
|
||||
const validStaticMembersOfBaseClassB: CompletionInfo[] = [
|
||||
["staticMethod", "(method) B.staticMethod(): void"]
|
||||
];
|
||||
const privateMembersOfBaseClassB: CompletionInfo[] = [
|
||||
["privateMethod", "(method) B.privateMethod(): void"],
|
||||
];
|
||||
const protectedPropertiesOfBaseClassB0: CompletionInfo[] = [
|
||||
["protectedMethod", "(method) B0.protectedMethod(): void"],
|
||||
["protectedMethod1", "(method) B0.protectedMethod1(): void"],
|
||||
];
|
||||
const publicPropertiesOfBaseClassB0: CompletionInfo[] = [
|
||||
["getValue", "(method) B0.getValue(): string | boolean"],
|
||||
["getValue1", "(method) B0.getValue1(): string | boolean"],
|
||||
];
|
||||
const validInstanceMembersOfBaseClassB0: CompletionInfo[] = protectedPropertiesOfBaseClassB0.concat(publicPropertiesOfBaseClassB0);
|
||||
const validStaticMembersOfBaseClassB0: CompletionInfo[] = [
|
||||
["staticMethod", "(method) B0.staticMethod(): void"],
|
||||
["staticMethod1", "(method) B0.staticMethod1(): void"]
|
||||
];
|
||||
const privateMembersOfBaseClassB0: CompletionInfo[] = [
|
||||
["privateMethod", "(method) B0.privateMethod(): void"],
|
||||
["privateMethod1", "(method) B0.privateMethod1(): void"],
|
||||
];
|
||||
const membersOfI: CompletionInfo[] = [
|
||||
["methodOfInterface", "(method) I.methodOfInterface(): number"],
|
||||
];
|
||||
const membersOfI2: CompletionInfo[] = [
|
||||
["methodOfInterface2", "(method) I2.methodOfInterface2(): number"],
|
||||
];
|
||||
const membersOfI3: CompletionInfo[] = [
|
||||
["getValue", "(method) I3.getValue(): string"],
|
||||
["method", "(method) I3.method(): string"],
|
||||
];
|
||||
const membersOfI4: CompletionInfo[] = [
|
||||
["staticMethod", "(method) I4.staticMethod(): void"],
|
||||
["method", "(method) I4.method(): string"],
|
||||
];
|
||||
const membersOfI5: CompletionInfo[] = publicPropertiesOfBaseClassB0.concat([
|
||||
["methodOfInterface5", "(method) I5.methodOfInterface5(): number"]
|
||||
]);
|
||||
const membersOfI6: CompletionInfo[] = publicPropertiesOfBaseClassB0.concat([
|
||||
["staticMethod", "(method) I6.staticMethod(): void"],
|
||||
["methodOfInterface6", "(method) I6.methodOfInterface6(): number"]
|
||||
]);
|
||||
const membersOfI7: CompletionInfo[] = membersOfI.concat([
|
||||
["methodOfInterface7", "(method) I7.methodOfInterface7(): number"]
|
||||
]);
|
||||
|
||||
function getCompletionInfoVerifier(
|
||||
validMembers: CompletionInfo[],
|
||||
invalidMembers: CompletionInfo[],
|
||||
arrayToDistribute: CompletionInfo[],
|
||||
isValidDistributionCriteria: (v: CompletionInfo) => boolean): CompletionInfoVerifier {
|
||||
if (arrayToDistribute) {
|
||||
validMembers = validMembers.concat(arrayToDistribute.filter(isValidDistributionCriteria));
|
||||
invalidMembers = invalidMembers.concat(arrayToDistribute.filter(v => !isValidDistributionCriteria(v)));
|
||||
}
|
||||
return {
|
||||
validMembers,
|
||||
invalidMembers
|
||||
}
|
||||
}
|
||||
|
||||
const noMembers: CompletionInfo[] = [];
|
||||
const membersOfIAndI2 = membersOfI.concat(membersOfI2);
|
||||
const invalidMembersOfBAtInstanceLocation = privateMembersOfBaseClassB.concat(validStaticMembersOfBaseClassB);
|
||||
|
||||
// members of I and I2
|
||||
verifyClassElementLocations({ validMembers: membersOfIAndI2, invalidMembers: noMembers }, [
|
||||
"implementsIAndI2",
|
||||
"implementsIAndI2AndWritingMethodNameOfI"
|
||||
]);
|
||||
|
||||
// Static location so no members of I and I2
|
||||
verifyClassElementLocations({ validMembers: noMembers, invalidMembers: membersOfIAndI2 },
|
||||
["implementsIAndI2AndWritingStatic"]);
|
||||
|
||||
const allInstanceBAndIAndI2 = membersOfIAndI2.concat(validInstanceMembersOfBaseClassB);
|
||||
// members of instance B, I and I2
|
||||
verifyClassElementLocations({
|
||||
validMembers: allInstanceBAndIAndI2,
|
||||
invalidMembers: invalidMembersOfBAtInstanceLocation
|
||||
}, ["extendsBAndImplementsIAndI2"]);
|
||||
|
||||
// static location so only static members of B and no members of instance B, I and I2
|
||||
verifyClassElementLocations({
|
||||
validMembers: validStaticMembersOfBaseClassB,
|
||||
invalidMembers: privateMembersOfBaseClassB.concat(allInstanceBAndIAndI2)
|
||||
}, [
|
||||
"extendsBAndImplementsIAndI2AndWritingStatic",
|
||||
"extendsBAndImplementsIAndI2WithMethodFromBAndIAndTypesStatic"
|
||||
]);
|
||||
|
||||
// instance members of B without protectedMethod, I and I2
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ membersOfIAndI2,
|
||||
/*invalidMembers*/ invalidMembersOfBAtInstanceLocation,
|
||||
/*arrayToDistribute*/ validInstanceMembersOfBaseClassB,
|
||||
value => value[0] !== "protectedMethod"),
|
||||
["extendsBAndImplementsIAndI2WithMethodFromB"]);
|
||||
|
||||
// instance members of B, members of T without methodOfInterface and I2
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ membersOfI2.concat(validInstanceMembersOfBaseClassB),
|
||||
/*invalidMembers*/ invalidMembersOfBAtInstanceLocation,
|
||||
/*arrayToDistribute*/ membersOfI,
|
||||
value => value[0] !== "methodOfInterface"),
|
||||
["extendsBAndImplementsIAndI2WithMethodFromI"]);
|
||||
|
||||
// instance members of B without protectedMethod, members of T without methodOfInterface and I2
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ membersOfI2,
|
||||
/*invalidMembers*/ invalidMembersOfBAtInstanceLocation,
|
||||
/*arrayToDistribute*/ membersOfI.concat(validInstanceMembersOfBaseClassB),
|
||||
value => value[0] !== "methodOfInterface" && value[0] !== "protectedMethod"),
|
||||
["extendsBAndImplementsIAndI2WithMethodFromBAndI"]);
|
||||
|
||||
// members of B and members of I3 that are not same as name of method in B
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ validInstanceMembersOfBaseClassB,
|
||||
/*invalidMembers*/ invalidMembersOfBAtInstanceLocation,
|
||||
/*arrayToDistribute*/ membersOfI3,
|
||||
value => value[0] !== "getValue"),
|
||||
["extendsBAndImplementsI3WithSameNameMembers"]);
|
||||
|
||||
// members of B (without getValue since its implemented) and members of I3 that are not same as name of method in B
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ noMembers,
|
||||
/*invalidMembers*/ invalidMembersOfBAtInstanceLocation,
|
||||
/*arrayToDistribute*/ membersOfI3.concat(validInstanceMembersOfBaseClassB),
|
||||
value => value[0] !== "getValue"),
|
||||
["extendsBAndImplementsI3WithSameNameMembersAndHasImplementedTheMember"]);
|
||||
|
||||
const invalidMembersOfB0AtInstanceSide = privateMembersOfBaseClassB0.concat(validStaticMembersOfBaseClassB0);
|
||||
const invalidMembersOfB0AtStaticSide = privateMembersOfBaseClassB0.concat(validInstanceMembersOfBaseClassB0);
|
||||
// members of B0 and members of I4
|
||||
verifyClassElementLocations({
|
||||
validMembers: validInstanceMembersOfBaseClassB0.concat(membersOfI4),
|
||||
invalidMembers: invalidMembersOfB0AtInstanceSide
|
||||
}, [
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethod",
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedAnotherMethod",
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsStatic"
|
||||
]);
|
||||
|
||||
// members of B0 and members of I4 that are not staticMethod
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ validInstanceMembersOfBaseClassB0,
|
||||
/*invalidMembers*/ invalidMembersOfB0AtInstanceSide,
|
||||
/*arrayToDistribute*/ membersOfI4,
|
||||
value => value[0] !== "staticMethod"
|
||||
), [
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethod",
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsBoth"
|
||||
]);
|
||||
|
||||
// static members of B0
|
||||
verifyClassElementLocations({
|
||||
validMembers: validStaticMembersOfBaseClassB0,
|
||||
invalidMembers: invalidMembersOfB0AtStaticSide.concat(membersOfI4)
|
||||
}, [
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodWritingStatic",
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedAnotherMethodWritingStatic",
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodWritingStatic"
|
||||
]);
|
||||
|
||||
// static members of B0 without staticMethod
|
||||
verifyClassElementLocations(
|
||||
getCompletionInfoVerifier(
|
||||
/*validMembers*/ noMembers,
|
||||
/*invalidMembers*/ invalidMembersOfB0AtStaticSide.concat(membersOfI4),
|
||||
/*arrayToDistribute*/ validStaticMembersOfBaseClassB0,
|
||||
value => value[0] !== "staticMethod"
|
||||
), [
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsStaticWritingStatic",
|
||||
"extendsB0ThatExtendsAndImplementsI4WithStaticMethodAndImplementedThatMethodAsBothWritingStatic"
|
||||
]);
|
||||
|
||||
// members of I7 extends I
|
||||
verifyClassElementLocations({ validMembers: membersOfI7, invalidMembers: noMembers }, [
|
||||
"implementsI7whichExtendsI",
|
||||
"implementsI7whichExtendsIAndAlsoImplementsI",
|
||||
"implementsIAndAlsoImplementsI7whichExtendsI"
|
||||
]);
|
||||
|
||||
const invalidMembersOfB0AtInstanceSideFromInterfaceExtendingB0 = invalidMembersOfB0AtInstanceSide
|
||||
.concat(protectedPropertiesOfBaseClassB0);
|
||||
// members of I5 extends B0
|
||||
verifyClassElementLocations({
|
||||
validMembers: membersOfI5,
|
||||
invalidMembers: invalidMembersOfB0AtInstanceSideFromInterfaceExtendingB0
|
||||
}, [
|
||||
"implementsI5ThatExtendsB0",
|
||||
]);
|
||||
|
||||
// members of I6 extends B0
|
||||
verifyClassElementLocations({
|
||||
validMembers: membersOfI6,
|
||||
invalidMembers: invalidMembersOfB0AtInstanceSideFromInterfaceExtendingB0
|
||||
}, [
|
||||
"implementsI6ThatExtendsB0AndHasStaticMethodOfB0",
|
||||
]);
|
||||
|
||||
// members of B0 and I5 that extends B0
|
||||
verifyClassElementLocations({
|
||||
validMembers: membersOfI5.concat(protectedPropertiesOfBaseClassB0),
|
||||
invalidMembers: invalidMembersOfB0AtInstanceSide
|
||||
}, [
|
||||
"extendsB0AndImplementsI5ThatExtendsB0"
|
||||
]);
|
||||
|
||||
// members of B0 and I6 that extends B0
|
||||
verifyClassElementLocations({
|
||||
validMembers: membersOfI6.concat(protectedPropertiesOfBaseClassB0),
|
||||
invalidMembers: invalidMembersOfB0AtInstanceSide
|
||||
}, [
|
||||
"extendsB0AndImplementsI6ThatExtendsB0AndHasStaticMethodOfB0"
|
||||
]);
|
||||
|
||||
// nothing on static side as these do not extend any other class
|
||||
verifyClassElementLocations({
|
||||
validMembers: [],
|
||||
invalidMembers: membersOfI5.concat(membersOfI6, invalidMembersOfB0AtStaticSide)
|
||||
}, [
|
||||
"implementsI5ThatExtendsB0TypesStatic",
|
||||
"implementsI6ThatExtendsB0AndHasStaticMethodOfB0TypesStatic"
|
||||
]);
|
||||
|
||||
// statics of base B but nothing from instance side
|
||||
verifyClassElementLocations({
|
||||
validMembers: validStaticMembersOfBaseClassB0,
|
||||
invalidMembers: membersOfI5.concat(membersOfI6, invalidMembersOfB0AtStaticSide)
|
||||
}, [
|
||||
"extendsB0AndImplementsI5ThatExtendsB0TypesStatic",
|
||||
"extendsB0AndImplementsI6ThatExtendsB0AndHasStaticMethodOfB0TypesStatic"
|
||||
]);
|
||||
@@ -10,4 +10,4 @@
|
||||
//// public static a/*property2*/
|
||||
////}
|
||||
|
||||
goTo.eachMarker(() => verify.completionListIsEmpty());
|
||||
goTo.eachMarker(() => verify.completionListContainsClassElementKeywords());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
///<reference path="fourslash.ts" />
|
||||
|
||||
//// var x = class myClass {
|
||||
//// getClassName (){
|
||||
@@ -11,4 +11,4 @@ goTo.marker("0");
|
||||
verify.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
|
||||
goTo.marker("1");
|
||||
verify.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
verify.not.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
@@ -1,4 +1,4 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
///<reference path="fourslash.ts" />
|
||||
|
||||
//// class myClass { /*0*/ }
|
||||
//// /*1*/
|
||||
@@ -16,7 +16,7 @@
|
||||
//// }
|
||||
|
||||
goTo.marker("0");
|
||||
verify.completionListContains("myClass", "class myClass", /*documentation*/ undefined, "class");
|
||||
verify.not.completionListContains("myClass", "class myClass", /*documentation*/ undefined, "class");
|
||||
verify.not.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
|
||||
goTo.marker("1");
|
||||
@@ -28,7 +28,7 @@ verify.completionListContains("myClass", "(local class) myClass", /*documentatio
|
||||
verify.not.completionListContains("myClass", "class myClass", /*documentation*/ undefined, "class");
|
||||
|
||||
goTo.marker("3");
|
||||
verify.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
verify.not.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
verify.not.completionListContains("myClass", "class myClass", /*documentation*/ undefined, "class");
|
||||
|
||||
goTo.marker("4");
|
||||
@@ -36,5 +36,5 @@ verify.completionListContains("myClass", "class myClass", /*documentation*/ unde
|
||||
verify.not.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
|
||||
goTo.marker("5");
|
||||
verify.completionListContains("myClass", "class myClass", /*documentation*/ undefined, "class");
|
||||
verify.not.completionListContains("myClass", "class myClass", /*documentation*/ undefined, "class");
|
||||
verify.not.completionListContains("myClass", "(local class) myClass", /*documentation*/ undefined, "local class");
|
||||
|
||||
@@ -53,7 +53,7 @@ verify.completionListIsGlobal(false);
|
||||
goTo.marker("9");
|
||||
verify.completionListIsGlobal(false);
|
||||
goTo.marker("10");
|
||||
verify.completionListIsGlobal(true);
|
||||
verify.completionListIsGlobal(false);
|
||||
goTo.marker("11");
|
||||
verify.completionListIsGlobal(true);
|
||||
goTo.marker("12");
|
||||
|
||||
@@ -225,27 +225,28 @@
|
||||
////
|
||||
////var shwvar = 1;
|
||||
|
||||
function goToMarkAndGeneralVerify(marker: string)
|
||||
function goToMarkAndGeneralVerify(marker: string, isClassScope?: boolean)
|
||||
{
|
||||
goTo.marker(marker);
|
||||
|
||||
verify.completionListContains('mod1var', 'var mod1var: number');
|
||||
verify.completionListContains('mod1fn', 'function mod1fn(): void');
|
||||
verify.completionListContains('mod1cls', 'class mod1cls');
|
||||
verify.completionListContains('mod1int', 'interface mod1int');
|
||||
verify.completionListContains('mod1mod', 'namespace mod1mod');
|
||||
verify.completionListContains('mod1evar', 'var mod1.mod1evar: number');
|
||||
verify.completionListContains('mod1efn', 'function mod1.mod1efn(): void');
|
||||
verify.completionListContains('mod1ecls', 'class mod1.mod1ecls');
|
||||
verify.completionListContains('mod1eint', 'interface mod1.mod1eint');
|
||||
verify.completionListContains('mod1emod', 'namespace mod1.mod1emod');
|
||||
verify.completionListContains('mod1eexvar', 'var mod1.mod1eexvar: number');
|
||||
verify.completionListContains('mod2', 'namespace mod2');
|
||||
verify.completionListContains('mod3', 'namespace mod3');
|
||||
verify.completionListContains('shwvar', 'var shwvar: number');
|
||||
verify.completionListContains('shwfn', 'function shwfn(): void');
|
||||
verify.completionListContains('shwcls', 'class shwcls');
|
||||
verify.completionListContains('shwint', 'interface shwint');
|
||||
const verifyModule = isClassScope ? verify.not : verify;
|
||||
verifyModule.completionListContains('mod1var', 'var mod1var: number');
|
||||
verifyModule.completionListContains('mod1fn', 'function mod1fn(): void');
|
||||
verifyModule.completionListContains('mod1cls', 'class mod1cls');
|
||||
verifyModule.completionListContains('mod1int', 'interface mod1int');
|
||||
verifyModule.completionListContains('mod1mod', 'namespace mod1mod');
|
||||
verifyModule.completionListContains('mod1evar', 'var mod1.mod1evar: number');
|
||||
verifyModule.completionListContains('mod1efn', 'function mod1.mod1efn(): void');
|
||||
verifyModule.completionListContains('mod1ecls', 'class mod1.mod1ecls');
|
||||
verifyModule.completionListContains('mod1eint', 'interface mod1.mod1eint');
|
||||
verifyModule.completionListContains('mod1emod', 'namespace mod1.mod1emod');
|
||||
verifyModule.completionListContains('mod1eexvar', 'var mod1.mod1eexvar: number');
|
||||
verifyModule.completionListContains('mod2', 'namespace mod2');
|
||||
verifyModule.completionListContains('mod3', 'namespace mod3');
|
||||
verifyModule.completionListContains('shwvar', 'var shwvar: number');
|
||||
verifyModule.completionListContains('shwfn', 'function shwfn(): void');
|
||||
verifyModule.completionListContains('shwcls', 'class shwcls');
|
||||
verifyModule.completionListContains('shwint', 'interface shwint');
|
||||
|
||||
verify.not.completionListContains('mod2var');
|
||||
verify.not.completionListContains('mod2fn');
|
||||
@@ -280,7 +281,7 @@ verify.completionListContains('bar', '(local var) bar: number');
|
||||
verify.completionListContains('foob', '(local function) foob(): void');
|
||||
|
||||
// from class in mod1
|
||||
goToMarkAndGeneralVerify('class');
|
||||
goToMarkAndGeneralVerify('class', /*isClassScope*/ true);
|
||||
//verify.not.completionListContains('ceFunc');
|
||||
//verify.not.completionListContains('ceVar');
|
||||
|
||||
@@ -306,7 +307,7 @@ verify.completionListContains('bar', '(local var) bar: number');
|
||||
verify.completionListContains('foob', '(local function) foob(): void');
|
||||
|
||||
// from exported class in mod1
|
||||
goToMarkAndGeneralVerify('exportedClass');
|
||||
goToMarkAndGeneralVerify('exportedClass', /*isClassScope*/ true);
|
||||
//verify.not.completionListContains('ceFunc');
|
||||
//verify.not.completionListContains('ceVar');
|
||||
|
||||
|
||||
@@ -231,6 +231,39 @@
|
||||
//// x: /*objectLiteral*/
|
||||
////}
|
||||
|
||||
goTo.marker('extendedClass');
|
||||
|
||||
verify.not.completionListContains('mod1');
|
||||
verify.not.completionListContains('mod2');
|
||||
verify.not.completionListContains('mod3');
|
||||
verify.not.completionListContains('shwvar', 'var shwvar: number');
|
||||
verify.not.completionListContains('shwfn', 'function shwfn(): void');
|
||||
verify.not.completionListContains('shwcls', 'class shwcls');
|
||||
verify.not.completionListContains('shwint', 'interface shwint');
|
||||
|
||||
verify.not.completionListContains('mod2var');
|
||||
verify.not.completionListContains('mod2fn');
|
||||
verify.not.completionListContains('mod2cls');
|
||||
verify.not.completionListContains('mod2int');
|
||||
verify.not.completionListContains('mod2mod');
|
||||
verify.not.completionListContains('mod2evar');
|
||||
verify.not.completionListContains('mod2efn');
|
||||
verify.not.completionListContains('mod2ecls');
|
||||
verify.not.completionListContains('mod2eint');
|
||||
verify.not.completionListContains('mod2emod');
|
||||
verify.not.completionListContains('sfvar');
|
||||
verify.not.completionListContains('sffn');
|
||||
verify.not.completionListContains('scvar');
|
||||
verify.not.completionListContains('scfn');
|
||||
verify.completionListContains('scpfn');
|
||||
verify.completionListContains('scpvar');
|
||||
verify.not.completionListContains('scsvar');
|
||||
verify.not.completionListContains('scsfn');
|
||||
verify.not.completionListContains('sivar');
|
||||
verify.not.completionListContains('sifn');
|
||||
verify.not.completionListContains('mod1exvar');
|
||||
verify.not.completionListContains('mod2eexvar');
|
||||
|
||||
function goToMarkerAndVerify(marker: string)
|
||||
{
|
||||
goTo.marker(marker);
|
||||
@@ -267,8 +300,6 @@ function goToMarkerAndVerify(marker: string)
|
||||
verify.not.completionListContains('mod2eexvar');
|
||||
}
|
||||
|
||||
goToMarkerAndVerify('extendedClass');
|
||||
|
||||
goToMarkerAndVerify('objectLiteral');
|
||||
|
||||
goTo.marker('localVar');
|
||||
|
||||
@@ -133,11 +133,13 @@ declare namespace FourSlashInterface {
|
||||
class verifyNegatable {
|
||||
private negative;
|
||||
not: verifyNegatable;
|
||||
allowedClassElementKeywords: string[];
|
||||
constructor(negative?: boolean);
|
||||
completionListCount(expectedCount: number): void;
|
||||
completionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number): void;
|
||||
completionListItemsCountIsGreaterThan(count: number): void;
|
||||
completionListIsEmpty(): void;
|
||||
completionListContainsClassElementKeywords(): void;
|
||||
completionListAllowsNewIdentifier(): void;
|
||||
signatureHelpPresent(): void;
|
||||
errorExistsBetweenMarkers(startMarker: string, endMarker: string): void;
|
||||
|
||||
@@ -26,7 +26,7 @@ const methods = ranges.get("method");
|
||||
const [m0, m1, m2] = methods;
|
||||
verify.referenceGroups(m0, [{ definition: "(method) Base<T>.method<U>(a?: T, b?: U): this", ranges: methods }]);
|
||||
verify.referenceGroups(m1, [
|
||||
{ definition: "(method) Base<T>.method(): void", ranges: [m0] },
|
||||
{ definition: "(method) Base<T>.method<U>(a?: T, b?: U): this", ranges: [m0] },
|
||||
{ definition: "(method) MyClass.method(): void", ranges: [m1, m2] }
|
||||
]);
|
||||
verify.referenceGroups(m2, [
|
||||
|
||||
Reference in New Issue
Block a user