Merge pull request #32377 from minajevs/fix29666

Fix completion lists for 'readonly' and 'const' keywords
This commit is contained in:
Sheetal Nandi 2019-07-16 10:17:52 -07:00 committed by GitHub
commit 664671cf49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 15 deletions

View file

@ -865,7 +865,7 @@ namespace FourSlash {
ts.zipWith(actual, expected, (completion, expectedCompletion, index) => {
const name = typeof expectedCompletion === "string" ? expectedCompletion : expectedCompletion.name;
if (completion.name !== name) {
this.raiseError(`${marker ? JSON.stringify(marker) : "" } Expected completion at index ${index} to be ${name}, got ${completion.name}`);
this.raiseError(`${marker ? JSON.stringify(marker) : ""} Expected completion at index ${index} to be ${name}, got ${completion.name}`);
}
this.verifyCompletionEntry(completion, expectedCompletion);
});
@ -3759,7 +3759,7 @@ namespace FourSlashInterface {
}
export class Plugins {
constructor (private state: FourSlash.TestState) {
constructor(private state: FourSlash.TestState) {
}
public configurePlugin(pluginName: string, configuration: any): void {
@ -4582,7 +4582,7 @@ namespace FourSlashInterface {
export const keywords: ReadonlyArray<ExpectedCompletionEntryObject> = keywordsWithUndefined.filter(k => k.name !== "undefined");
export const typeKeywords: ReadonlyArray<ExpectedCompletionEntryObject> =
["false", "null", "true", "void", "any", "boolean", "keyof", "never", "number", "object", "string", "symbol", "undefined", "unique", "unknown", "bigint"].map(keywordEntry);
["false", "null", "true", "void", "any", "boolean", "keyof", "never", "readonly", "number", "object", "string", "symbol", "undefined", "unique", "unknown", "bigint"].map(keywordEntry);
const globalTypeDecls: ReadonlyArray<ExpectedCompletionEntryObject> = [
interfaceEntry("Symbol"),
@ -4698,6 +4698,9 @@ namespace FourSlashInterface {
];
}
export const typeAssertionKeywords: ReadonlyArray<ExpectedCompletionEntry> =
globalTypesPlus([keywordEntry("const")]);
function getInJsKeywords(keywords: ReadonlyArray<ExpectedCompletionEntryObject>): ReadonlyArray<ExpectedCompletionEntryObject> {
return keywords.filter(keyword => {
switch (keyword.name) {

View file

@ -38,6 +38,7 @@ namespace ts.Completions {
InterfaceElementKeywords, // Keywords inside interface body
ConstructorParameterKeywords, // Keywords at constructor parameter
FunctionLikeBodyKeywords, // Keywords at function like body
TypeAssertionKeywords,
TypeKeywords,
Last = TypeKeywords
}
@ -441,7 +442,7 @@ namespace ts.Completions {
(symbol.escapedName === InternalSymbolName.ExportEquals))
// Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
? firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined)
|| codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target)
|| codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target)
: symbol.name;
}
@ -632,9 +633,9 @@ namespace ts.Completions {
// At `,`, treat this as the next argument after the comma.
? checker.getContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex + (previousToken.kind === SyntaxKind.CommaToken ? 1 : 0))
: isEqualityOperatorKind(previousToken.kind) && isBinaryExpression(parent) && isEqualityOperatorKind(parent.operatorToken.kind)
// completion at `x ===/**/` should be for the right side
? checker.getTypeAtLocation(parent.left)
: checker.getContextualType(previousToken as Expression);
// completion at `x ===/**/` should be for the right side
? checker.getTypeAtLocation(parent.left)
: checker.getContextualType(previousToken as Expression);
}
}
@ -1182,7 +1183,11 @@ namespace ts.Completions {
function filterGlobalCompletion(symbols: Symbol[]): void {
const isTypeOnly = isTypeOnlyCompletion();
const allowTypes = isTypeOnly || !isContextTokenValueLocation(contextToken) && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker);
if (isTypeOnly) keywordFilters = KeywordCompletionFilters.TypeKeywords;
if (isTypeOnly) {
keywordFilters = isTypeAssertion()
? KeywordCompletionFilters.TypeAssertionKeywords
: KeywordCompletionFilters.TypeKeywords;
}
filterMutate(symbols, symbol => {
if (!isSourceFile(location)) {
@ -1212,6 +1217,10 @@ namespace ts.Completions {
});
}
function isTypeAssertion(): boolean {
return isAssertionExpression(contextToken.parent);
}
function isTypeOnlyCompletion(): boolean {
return insideJsDocTagTypeExpression || !isContextTokenValueLocation(contextToken) && (isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken));
}
@ -1240,7 +1249,8 @@ namespace ts.Completions {
return parentKind === SyntaxKind.AsExpression;
case SyntaxKind.LessThanToken:
return parentKind === SyntaxKind.TypeReference;
return parentKind === SyntaxKind.TypeReference ||
parentKind === SyntaxKind.TypeAssertionExpression;
case SyntaxKind.ExtendsKeyword:
return parentKind === SyntaxKind.TypeParameter;
@ -1516,7 +1526,7 @@ namespace ts.Completions {
// 3. at the end of a regular expression (due to trailing flags like '/foo/g').
return (isRegularExpressionLiteral(contextToken) || isStringTextContainingNode(contextToken)) && (
rangeContainsPositionExclusive(createTextRangeFromSpan(createTextSpanFromNode(contextToken)), position) ||
position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)));
position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)));
}
/**
@ -2026,8 +2036,8 @@ namespace ts.Completions {
return baseSymbols.filter(propertySymbol =>
!existingMemberNames.has(propertySymbol.escapedName) &&
!!propertySymbol.declarations &&
!(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private));
!!propertySymbol.declarations &&
!(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private));
}
/**
@ -2139,6 +2149,8 @@ namespace ts.Completions {
return isParameterPropertyModifier(kind);
case KeywordCompletionFilters.FunctionLikeBodyKeywords:
return isFunctionLikeBodyKeyword(kind);
case KeywordCompletionFilters.TypeAssertionKeywords:
return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword;
case KeywordCompletionFilters.TypeKeywords:
return isTypeKeyword(kind);
default:

View file

@ -1224,6 +1224,7 @@ namespace ts {
SyntaxKind.NullKeyword,
SyntaxKind.NumberKeyword,
SyntaxKind.ObjectKeyword,
SyntaxKind.ReadonlyKeyword,
SyntaxKind.StringKeyword,
SyntaxKind.SymbolKeyword,
SyntaxKind.TrueKeyword,
@ -1734,8 +1735,8 @@ namespace ts {
function getSynthesizedDeepCloneWorker<T extends Node>(node: T, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T {
const visited = (renameMap || checker || callback) ?
visitEachChild(node, wrapper, nullTransformationContext) :
visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext);
visitEachChild(node, wrapper, nullTransformationContext) :
visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext);
if (visited === node) {
// This only happens for leaf nodes - internal nodes always see their children change.

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts'/>
////const a = {
//// b: 42 as /*0*/
////};
////
////1 as /*1*/
////
////const b = 42 as /*2*/
////
////var c = </*3*/>42
verify.completions({ marker: test.markers(), exact: completion.typeAssertionKeywords });

View file

@ -6,5 +6,5 @@
////function f([|readonly|] p) {}
for (const r of test.ranges()) {
verify.documentHighlightsOf(r, [r]);
verify.documentHighlightsOf(r, test.ranges());
}

View file

@ -696,6 +696,7 @@ declare namespace completion {
export const typeKeywords: ReadonlyArray<Entry>;
export const globalTypes: ReadonlyArray<Entry>;
export function globalTypesPlus(plus: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry>): ReadonlyArray<Entry>;
export const typeAssertionKeywords: ReadonlyArray<Entry>;
export const classElementKeywords: ReadonlyArray<Entry>;
export const classElementInJsKeywords: ReadonlyArray<Entry>;
export const constructorParameterKeywords: ReadonlyArray<Entry>;