From 0481d44501c4335706f8fa423049ea15e499ca89 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 30 Oct 2018 13:25:24 -0700 Subject: [PATCH] Bad callsite inferences fall back to body usage (#28235) For parameters, the infer-from-usage codefix uses a substantially different codepath that previously only looked at call site uses. When this resulted in no inferences, or bad inferences, for a single parameter, the codefix would just use any. Only if no usages of a function were found would the codefix use the body-inference code. This commit makes parameter inference fall back to body-inference code for individual parameters when there is no inference or inference to any. --- src/services/codefixes/inferFromUsage.ts | 15 ++++++++++----- .../codeFixInferFromUsageCallBodyPriority.ts | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInferFromUsageCallBodyPriority.ts diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 834228f7884..12a0aeff730 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -349,7 +349,7 @@ namespace ts.codefix { findChildOfKind>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile) : containingFunction.name; if (searchToken) { - return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program.getTypeChecker(), cancellationToken); + return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program, cancellationToken); } } } @@ -387,7 +387,8 @@ namespace ts.codefix { return getTypeFromUsageContext(usageContext, checker) || checker.getAnyType(); } - export function inferTypeForParametersFromReferences(references: ReadonlyArray, declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): ParameterInference[] | undefined { + export function inferTypeForParametersFromReferences(references: ReadonlyArray, declaration: FunctionLikeDeclaration, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined { + const checker = program.getTypeChecker(); if (references.length === 0) { return undefined; } @@ -422,10 +423,14 @@ namespace ts.codefix { types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex])); } } - if (!types.length) { - return { declaration: parameter, type: checker.getAnyType() }; + + let type = types.length && checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype)); + if ((!type || type.flags & TypeFlags.Any) && isIdentifier(parameter.name)) { + type = inferTypeForVariableFromUsage(parameter.name, program, cancellationToken); + } + if (!type) { + type = checker.getAnyType(); } - const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype)); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, diff --git a/tests/cases/fourslash/codeFixInferFromUsageCallBodyPriority.ts b/tests/cases/fourslash/codeFixInferFromUsageCallBodyPriority.ts new file mode 100644 index 00000000000..1603d35d742 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageCallBodyPriority.ts @@ -0,0 +1,18 @@ +/// +// based on acorn + +////function isIdentifierStart([|code, astral |]) { +//// if (code < 65) { return code === 36 } +//// if (code < 91) { return true } +//// if (code < 97) { return code === 95 } +//// if (code < 123) { return true } +//// if (code <= 0xffff) { return code >= 0xaa } +//// if (astral === false) { return false } +////} +//// +////function isLet(nextCh: any) { +//// return isIdentifierStart(nextCh, true) +////}; + + +verify.rangeAfterCodeFix("code: number, astral: boolean",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 0);