Merge pull request #13364 from Microsoft/string_literal_completions_fix

String literal completions: Use call signature only if we are *immediately* in a call expression
This commit is contained in:
Andy 2017-01-09 10:11:13 -08:00 committed by GitHub
commit df8cb9d2c3
5 changed files with 37 additions and 27 deletions

View File

@ -15,7 +15,7 @@ namespace ts {
}
/** Array that is only intended to be pushed to, never read. */
interface Push<T> {
export interface Push<T> {
push(value: T): void;
}
@ -357,7 +357,7 @@ namespace ts {
* Then it computes the set of parent folders for 'directory' that should have the same module resolution result
* and for every parent folder in set it adds entry: parent -> module resolution. .
* Lets say we first directory name: /a/b/c/d/e and resolution result is: /a/b/bar.ts.
* Set of parent folders that should have the same result will be:
* Set of parent folders that should have the same result will be:
* [
* /a/b/c/d, /a/b/c, /a/b
* ]
@ -391,7 +391,7 @@ namespace ts {
}
}
}
function getCommonPrefix(directory: Path, resolution: string) {
if (resolution === undefined) {
return undefined;
@ -1022,7 +1022,7 @@ namespace ts {
/**
* Represents result of search. Normally when searching among several alternatives we treat value `undefined` as indicator
* that search fails and we should try another option.
* that search fails and we should try another option.
* However this does not allow us to represent final result that should be used instead of further searching (i.e. a final result that was found in cache).
* SearchResult is used to deal with this issue, its values represents following outcomes:
* - undefined - not found, continue searching
@ -1030,7 +1030,7 @@ namespace ts {
* - { value: <some-value> } - found - stop searching
*/
type SearchResult<T> = { value: T | undefined } | undefined;
/**
* Wraps value to SearchResult.
* @returns undefined if value is undefined or { value } otherwise

View File

@ -1,8 +1,6 @@
/// <reference path='../compiler/utilities.ts' />
/* @internal */
namespace ts.Completions {
export function getCompletionsAtPosition(host: LanguageServiceHost, typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number): CompletionInfo {
export function getCompletionsAtPosition(host: LanguageServiceHost, typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number): CompletionInfo | undefined {
if (isInReferenceComment(sourceFile, position)) {
return getTripleSlashReferenceCompletion(sourceFile, position);
}
@ -134,7 +132,7 @@ namespace ts.Completions {
return uniqueNames;
}
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number) {
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number): CompletionInfo | undefined {
const node = findPrecedingToken(position, sourceFile);
if (!node || node.kind !== SyntaxKind.StringLiteral) {
return undefined;
@ -174,7 +172,7 @@ namespace ts.Completions {
return getStringLiteralCompletionEntriesFromModuleNames(<StringLiteral>node);
}
else {
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
// i.e. declare function f(a: 'A');
@ -188,7 +186,7 @@ namespace ts.Completions {
}
}
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) {
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement): CompletionInfo | undefined {
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
const entries: CompletionEntry[] = [];
if (type) {
@ -199,7 +197,7 @@ namespace ts.Completions {
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo): CompletionInfo | undefined {
const candidates: Signature[] = [];
const entries: CompletionEntry[] = [];
@ -219,7 +217,7 @@ namespace ts.Completions {
return undefined;
}
function getStringLiteralCompletionEntriesFromElementAccess(node: ElementAccessExpression) {
function getStringLiteralCompletionEntriesFromElementAccess(node: ElementAccessExpression): CompletionInfo | undefined {
const type = typeChecker.getTypeAtLocation(node.expression);
const entries: CompletionEntry[] = [];
if (type) {
@ -231,7 +229,7 @@ namespace ts.Completions {
return undefined;
}
function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral) {
function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral): CompletionInfo | undefined {
const type = typeChecker.getContextualType(node);
if (type) {
const entries: CompletionEntry[] = [];
@ -243,7 +241,7 @@ namespace ts.Completions {
return undefined;
}
function addStringLiteralCompletionsFromType(type: Type, result: CompletionEntry[]): void {
function addStringLiteralCompletionsFromType(type: Type, result: Push<CompletionEntry>): void {
if (type && type.flags & TypeFlags.TypeParameter) {
type = typeChecker.getApparentType(type);
}
@ -251,18 +249,18 @@ namespace ts.Completions {
return;
}
if (type.flags & TypeFlags.Union) {
forEach((<UnionType>type).types, t => addStringLiteralCompletionsFromType(t, result));
}
else {
if (type.flags & TypeFlags.StringLiteral) {
result.push({
name: (<LiteralType>type).text,
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.variableElement,
sortText: "0"
});
for (const t of (<UnionType>type).types) {
addStringLiteralCompletionsFromType(t, result);
}
}
else if (type.flags & TypeFlags.StringLiteral) {
result.push({
name: (<LiteralType>type).text,
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.variableElement,
sortText: "0"
});
}
}
function getStringLiteralCompletionEntriesFromModuleNames(node: StringLiteral): CompletionInfo {

View File

@ -260,7 +260,7 @@ namespace ts.SignatureHelp {
* Returns relevant information for the argument list and the current argument if we are
* in the argument of an invocation; returns undefined otherwise.
*/
function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo {
export function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo {
if (node.parent.kind === SyntaxKind.CallExpression || node.parent.kind === SyntaxKind.NewExpression) {
const callExpression = <CallExpression>node.parent;
// There are 3 cases to handle:

View File

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts'/>
////interface Foo {
//// x: "abc" | "def";
////}
////function bar(f: Foo) { };
////bar({x: "/**/"});
goTo.marker();
verify.completionListContains("abc");
verify.completionListContains("def");
verify.completionListCount(2);

View File

@ -129,7 +129,7 @@ function dir(dirPath: string, spec?: string, options?: any) {
function deleteFolderRecursive(dirPath: string) {
if (fs.existsSync(dirPath)) {
fs.readdirSync(dirPath).forEach((file) => {
const curPath = path.join(path, file);
const curPath = path.join(dirPath, file);
if (fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
}