Tune the completion list for static and private modifiers

Do not show inherited members in completion for when writing private member
Show only static inherited members when writing static member
This commit is contained in:
Sheetal Nandi 2017-05-04 17:44:34 -07:00
parent 37a2cddabc
commit fcb0f46178
2 changed files with 107 additions and 39 deletions

View File

@ -939,10 +939,31 @@ namespace ts.Completions {
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));
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)) {
const baseType = typeChecker.getTypeAtLocation(baseTypeNode);
const typeToGetPropertiesFrom = (classElementModifierFlags & ModifierFlags.Static) ?
typeChecker.getTypeOfSymbolAtLocation(baseType.symbol, classLikeDeclaration) :
baseType;
// List of property symbols of base type that are not private
symbols = filter(typeChecker.getPropertiesOfType(typeToGetPropertiesFrom),
baseProperty => baseProperty.getDeclarations() && !(getDeclarationModifierFlagsFromSymbol(baseProperty) & ModifierFlags.Private));
}
}
return true;
@ -1248,7 +1269,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;
}
@ -1287,7 +1308,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;
}
@ -1322,7 +1343,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;
}
@ -1333,6 +1354,10 @@ namespace ts.Completions {
return filter(symbols, a => !seenNames.get(a.name));
}
function isCurrentlyEditingNode(node: Node): boolean {
return node.getStart() <= position && position <= node.getEnd();
}
}
/**

View File

@ -23,12 +23,19 @@
////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*/
@ -68,38 +75,87 @@
////class L extends B {
//// public identi/*classThatStartedWritingIdentifierAfterModifier*/
////}
////class L extends B {
////class L2 extends B {
//// private identi/*classThatStartedWritingIdentifierAfterPrivateModifier*/
////}
////class M extends B {
//// static identi/*classThatStartedWritingIdentifierAfterStaticModifier*/
////}
////class M extends B {
//// private static identi/*classThatStartedWritingIdentifierAfterPrivateStaticModifier*/
////}
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"]
];
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");
// Not a class element declaration location
const nonClassElementMarkers = [
"InsideMethod"
];
for (const marker of nonClassElementMarkers) {
goTo.marker(marker);
verify.not.completionListContains("getValue");
verifyCompletionInfo(allMembersOfBase, verify.not);
verify.not.completionListIsEmpty();
}
// Only keywords allowed at this position since they dont extend the class
// Only keywords allowed at this position since they dont extend the class or are private
const onlyClassElementKeywordLocations = [
"abstractClass",
"classThatDoesNotExtendAnotherClass"
"classThatDoesNotExtendAnotherClass",
"classThatHasWrittenPrivateKeyword",
"classElementContainingPrivateStatic",
"classThatStartedWritingIdentifierAfterPrivateModifier",
"classThatStartedWritingIdentifierAfterPrivateStaticModifier"
];
for (const marker of onlyClassElementKeywordLocations) {
goTo.marker(marker);
verify.completionListContainsClassElementKeywords();
verify.completionListCount(allowedKeywordCount);
}
verifyClassElementLocations({ validMembers: [], invalidMembers: allMembersOfBase }, onlyClassElementKeywordLocations);
// Base members and class member keywords allowed
const classElementCompletionLocations = [
// Instance base members and class member keywords allowed
const classInstanceElementLocations = [
"classThatIsEmptyAndExtendingAnotherClass",
"classThatHasAlreadyImplementedAnotherClassMethod",
"classThatHasAlreadyImplementedAnotherClassMethodAfterMethod",
"classThatHasWrittenPublicKeyword",
"classElementContainingStatic",
"classThatStartedWritingIdentifier",
"propDeclarationWithoutSemicolon",
"propDeclarationWithSemicolon",
@ -115,25 +171,12 @@ const classElementCompletionLocations = [
"classThatStartedWritingIdentifierOfGetAccessor",
"classThatStartedWritingIdentifierOfSetAccessor",
"classThatStartedWritingIdentifierAfterModifier",
];
verifyClassElementLocations(instanceMemberInfo, classInstanceElementLocations);
// Static Base members and class member keywords allowed
const staticClassLocations = [
"classElementContainingStatic",
"classThatStartedWritingIdentifierAfterStaticModifier"
];
const validMembersOfBase = [
["getValue", "(method) B.getValue(): number"],
["protectedMethod", "(method) B.protectedMethod(): void"]
];
const invalidMembersOfBase = [
["privateMethod", "(method) B.privateMethod(): void"],
["staticMethod", "(method) B.staticMethod(): void"]
];
for (const marker of classElementCompletionLocations) {
goTo.marker(marker);
for (const [validMemberOfBaseSymbol, validMemberOfBaseText] of validMembersOfBase) {
verify.completionListContains(validMemberOfBaseSymbol, validMemberOfBaseText, /*documentation*/ undefined, "method");
}
for (const [invalidMemberOfBaseSymbol, invalidMemberOfBaseText] of invalidMembersOfBase) {
verify.not.completionListContains(invalidMemberOfBaseSymbol, invalidMemberOfBaseText, /*documentation*/ undefined, "method");
}
verify.completionListContainsClassElementKeywords();
verify.completionListCount(allowedKeywordCount + validMembersOfBase.length);
}
verifyClassElementLocations(staticMemberInfo, staticClassLocations);