Skip to content

Commit 69214c0

Browse files
authored
fix(49001): handle missing imports in addMissingMember QF (microsoft#49009)
1 parent c1c3ebc commit 69214c0

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ namespace ts.codefix {
459459
const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host);
460460
const functionDeclaration = createSignatureDeclarationFromCallExpression(SyntaxKind.FunctionDeclaration, context, importAdder, info.call, idText(info.token), info.modifierFlags, info.parentDeclaration) as FunctionDeclaration;
461461
changes.insertNodeAtEndOfScope(info.sourceFile, info.parentDeclaration, functionDeclaration);
462+
importAdder.writeFixes(changes);
462463
}
463464

464465
function addJsxAttributes(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: JsxAttributesInfo) {
@@ -468,7 +469,7 @@ namespace ts.codefix {
468469
const jsxAttributesNode = info.parentDeclaration.attributes;
469470
const hasSpreadAttribute = some(jsxAttributesNode.properties, isJsxSpreadAttribute);
470471
const attrs = map(info.attributes, attr => {
471-
const value = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(attr));
472+
const value = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(attr), info.parentDeclaration);
472473
const name = factory.createIdentifier(attr.name);
473474
const jsxAttribute = factory.createJsxAttribute(name, factory.createJsxExpression(/*dotDotDotToken*/ undefined, value));
474475
// formattingScanner requires the Identifier to have a context for scanning attributes with "-" (data-foo).
@@ -478,6 +479,7 @@ namespace ts.codefix {
478479
const jsxAttributes = factory.createJsxAttributes(hasSpreadAttribute ? [...attrs, ...jsxAttributesNode.properties] : [...jsxAttributesNode.properties, ...attrs]);
479480
const options = { prefix: jsxAttributesNode.pos === jsxAttributesNode.end ? " " : undefined };
480481
changes.replaceNode(context.sourceFile, jsxAttributesNode, jsxAttributes, options);
482+
importAdder.writeFixes(changes);
481483
}
482484

483485
function addObjectLiteralProperties(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: ObjectLiteralInfo) {
@@ -486,7 +488,7 @@ namespace ts.codefix {
486488
const target = getEmitScriptTarget(context.program.getCompilerOptions());
487489
const checker = context.program.getTypeChecker();
488490
const props = map(info.properties, prop => {
489-
const initializer = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(prop));
491+
const initializer = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(prop), info.parentDeclaration);
490492
return factory.createPropertyAssignment(createPropertyNameNodeForIdentifierOrLiteral(prop.name, target, quotePreference === QuotePreference.Single), initializer);
491493
});
492494
const options = {
@@ -495,9 +497,10 @@ namespace ts.codefix {
495497
indentation: info.indentation
496498
};
497499
changes.replaceNode(context.sourceFile, info.parentDeclaration, factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true), options);
500+
importAdder.writeFixes(changes);
498501
}
499502

500-
function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, importAdder: ImportAdder, quotePreference: QuotePreference, type: Type): Expression {
503+
function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, importAdder: ImportAdder, quotePreference: QuotePreference, type: Type, enclosingDeclaration: Node | undefined): Expression {
501504
if (type.flags & TypeFlags.AnyOrUnknown) {
502505
return createUndefined();
503506
}
@@ -534,15 +537,15 @@ namespace ts.codefix {
534537
return factory.createNull();
535538
}
536539
if (type.flags & TypeFlags.Union) {
537-
const expression = firstDefined((type as UnionType).types, t => tryGetValueFromType(context, checker, importAdder, quotePreference, t));
540+
const expression = firstDefined((type as UnionType).types, t => tryGetValueFromType(context, checker, importAdder, quotePreference, t, enclosingDeclaration));
538541
return expression ?? createUndefined();
539542
}
540543
if (checker.isArrayLikeType(type)) {
541544
return factory.createArrayLiteralExpression();
542545
}
543546
if (isObjectLiteralType(type)) {
544547
const props = map(checker.getPropertiesOfType(type), prop => {
545-
const initializer = prop.valueDeclaration ? tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeAtLocation(prop.valueDeclaration)) : createUndefined();
548+
const initializer = prop.valueDeclaration ? tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeAtLocation(prop.valueDeclaration), enclosingDeclaration) : createUndefined();
546549
return factory.createPropertyAssignment(prop.name, initializer);
547550
});
548551
return factory.createObjectLiteralExpression(props, /*multiLine*/ true);
@@ -555,7 +558,7 @@ namespace ts.codefix {
555558
if (signature === undefined) return createUndefined();
556559

557560
const func = createSignatureDeclarationFromSignature(SyntaxKind.FunctionExpression, context, quotePreference, signature[0],
558-
createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), /*name*/ undefined, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ undefined, importAdder) as FunctionExpression | undefined;
561+
createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), /*name*/ undefined, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ enclosingDeclaration, importAdder) as FunctionExpression | undefined;
559562
return func ?? createUndefined();
560563
}
561564
if (getObjectFlags(type) & ObjectFlags.Class) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @filename: /a.ts
4+
////export type A = { x: string };
5+
6+
// @filename: /b.ts
7+
////import { A } from "./a";
8+
////export type Foo = { x: string };
9+
////export interface B {
10+
//// b(a: A): Foo;
11+
////}
12+
13+
// @filename: /c.ts
14+
////import { B } from "./b";
15+
////const b: B = {};
16+
17+
goTo.file("/c.ts");
18+
verify.codeFix({
19+
index: 0,
20+
description: ts.Diagnostics.Add_missing_properties.message,
21+
newFileContent:
22+
`import { A } from "./a";
23+
import { B, Foo } from "./b";
24+
const b: B = {
25+
b: function(a: A): Foo {
26+
throw new Error("Function not implemented.");
27+
}
28+
};`,
29+
});

0 commit comments

Comments
 (0)