@@ -57,7 +57,9 @@ namespace ts.Completions {
57
57
*/
58
58
export enum CompletionSource {
59
59
/** Completions that require `this.` insertion text */
60
- ThisProperty = "ThisProperty/"
60
+ ThisProperty = "ThisProperty/" ,
61
+ /** Auto-import that comes attached to a class member snippet */
62
+ ClassMemberSnippet = "ClassMemberSnippet/" ,
61
63
}
62
64
63
65
const enum SymbolOriginInfoKind {
@@ -641,6 +643,7 @@ namespace ts.Completions {
641
643
let replacementSpan = getReplacementSpanForContextToken ( replacementToken ) ;
642
644
let data : CompletionEntryData | undefined ;
643
645
let isSnippet : true | undefined ;
646
+ let source = getSourceFromOrigin ( origin ) ;
644
647
let sourceDisplay ;
645
648
let hasAction ;
646
649
@@ -702,7 +705,12 @@ namespace ts.Completions {
702
705
preferences . includeCompletionsWithInsertText &&
703
706
completionKind === CompletionKind . MemberLike &&
704
707
isClassLikeMemberCompletion ( symbol , location ) ) {
705
- ( { insertText, isSnippet } = getEntryForMemberCompletion ( host , program , options , preferences , name , symbol , location , contextToken ) ) ;
708
+ let importAdder ;
709
+ ( { insertText, isSnippet, importAdder } = getEntryForMemberCompletion ( host , program , options , preferences , name , symbol , location , contextToken ) ) ;
710
+ if ( importAdder ?. hasFixes ( ) ) {
711
+ hasAction = true ;
712
+ source = CompletionSource . ClassMemberSnippet ;
713
+ }
706
714
}
707
715
708
716
const kind = SymbolDisplay . getSymbolKind ( typeChecker , symbol , location ) ;
@@ -758,7 +766,7 @@ namespace ts.Completions {
758
766
kind,
759
767
kindModifiers : SymbolDisplay . getSymbolModifiers ( typeChecker , symbol ) ,
760
768
sortText,
761
- source : getSourceFromOrigin ( origin ) ,
769
+ source,
762
770
hasAction : hasAction ? true : undefined ,
763
771
isRecommended : isRecommendedCompletionMatch ( symbol , recommendedCompletion , typeChecker ) || undefined ,
764
772
insertText,
@@ -828,7 +836,7 @@ namespace ts.Completions {
828
836
symbol : Symbol ,
829
837
location : Node ,
830
838
contextToken : Node | undefined ,
831
- ) : { insertText : string , isSnippet ?: true } {
839
+ ) : { insertText : string , isSnippet ?: true , importAdder ?: codefix . ImportAdder } {
832
840
const classLikeDeclaration = findAncestor ( location , isClassLike ) ;
833
841
if ( ! classLikeDeclaration ) {
834
842
return { insertText : name } ;
@@ -921,7 +929,7 @@ namespace ts.Completions {
921
929
insertText = printer . printSnippetList ( ListFormat . MultiLine , factory . createNodeArray ( completionNodes ) , sourceFile ) ;
922
930
}
923
931
924
- return { insertText, isSnippet } ;
932
+ return { insertText, isSnippet, importAdder } ;
925
933
}
926
934
927
935
function getPresentModifiers ( contextToken : Node ) : ModifierFlags {
@@ -1297,6 +1305,7 @@ namespace ts.Completions {
1297
1305
location : Node ;
1298
1306
origin : SymbolOriginInfo | SymbolOriginInfoExport | SymbolOriginInfoResolvedExport | undefined ;
1299
1307
previousToken : Node | undefined ;
1308
+ contextToken : Node | undefined ;
1300
1309
readonly isJsxInitializer : IsJsxInitializer ;
1301
1310
readonly isTypeOnlyLocation : boolean ;
1302
1311
}
@@ -1312,11 +1321,13 @@ namespace ts.Completions {
1312
1321
if ( entryId . data ) {
1313
1322
const autoImport = getAutoImportSymbolFromCompletionEntryData ( entryId . name , entryId . data , program , host ) ;
1314
1323
if ( autoImport ) {
1324
+ const { contextToken, previousToken } = getRelevantTokens ( position , sourceFile ) ;
1315
1325
return {
1316
1326
type : "symbol" ,
1317
1327
symbol : autoImport . symbol ,
1318
1328
location : getTouchingPropertyName ( sourceFile , position ) ,
1319
- previousToken : findPrecedingToken ( position , sourceFile , /*startNode*/ undefined ) ! ,
1329
+ previousToken,
1330
+ contextToken,
1320
1331
isJsxInitializer : false ,
1321
1332
isTypeOnlyLocation : false ,
1322
1333
origin : autoImport . origin ,
@@ -1333,7 +1344,7 @@ namespace ts.Completions {
1333
1344
return { type : "request" , request : completionData } ;
1334
1345
}
1335
1346
1336
- const { symbols, literals, location, completionKind, symbolToOriginInfoMap, previousToken, isJsxInitializer, isTypeOnlyLocation } = completionData ;
1347
+ const { symbols, literals, location, completionKind, symbolToOriginInfoMap, contextToken , previousToken, isJsxInitializer, isTypeOnlyLocation } = completionData ;
1337
1348
1338
1349
const literal = find ( literals , l => completionNameForLiteral ( sourceFile , preferences , l ) === entryId . name ) ;
1339
1350
if ( literal !== undefined ) return { type : "literal" , literal } ;
@@ -1345,8 +1356,8 @@ namespace ts.Completions {
1345
1356
return firstDefined ( symbols , ( symbol , index ) : SymbolCompletion | undefined => {
1346
1357
const origin = symbolToOriginInfoMap [ index ] ;
1347
1358
const info = getCompletionEntryDisplayNameForSymbol ( symbol , getEmitScriptTarget ( compilerOptions ) , origin , completionKind , completionData . isJsxIdentifierExpected ) ;
1348
- return info && info . name === entryId . name && getSourceFromOrigin ( origin ) === entryId . source
1349
- ? { type : "symbol" as const , symbol, location, origin, previousToken, isJsxInitializer, isTypeOnlyLocation }
1359
+ return info && info . name === entryId . name && ( entryId . source === CompletionSource . ClassMemberSnippet && symbol . flags & SymbolFlags . ClassMember || getSourceFromOrigin ( origin ) === entryId . source )
1360
+ ? { type : "symbol" as const , symbol, location, origin, contextToken , previousToken, isJsxInitializer, isTypeOnlyLocation }
1350
1361
: undefined ;
1351
1362
} ) || { type : "none" } ;
1352
1363
}
@@ -1370,7 +1381,7 @@ namespace ts.Completions {
1370
1381
) : CompletionEntryDetails | undefined {
1371
1382
const typeChecker = program . getTypeChecker ( ) ;
1372
1383
const compilerOptions = program . getCompilerOptions ( ) ;
1373
- const { name } = entryId ;
1384
+ const { name, source , data } = entryId ;
1374
1385
1375
1386
const contextToken = findPrecedingToken ( position , sourceFile ) ;
1376
1387
if ( isInString ( sourceFile , position , contextToken ) ) {
@@ -1396,8 +1407,8 @@ namespace ts.Completions {
1396
1407
}
1397
1408
}
1398
1409
case "symbol" : {
1399
- const { symbol, location, origin, previousToken } = symbolCompletion ;
1400
- const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay ( origin , symbol , program , host , compilerOptions , sourceFile , position , previousToken , formatContext , preferences , entryId . data ) ;
1410
+ const { symbol, location, contextToken , origin, previousToken } = symbolCompletion ;
1411
+ const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay ( name , location , contextToken , origin , symbol , program , host , compilerOptions , sourceFile , position , previousToken , formatContext , preferences , data , source ) ;
1401
1412
return createCompletionDetailsForSymbol ( symbol , typeChecker , sourceFile , location , cancellationToken , codeActions , sourceDisplay ) ; // TODO: GH#18217
1402
1413
}
1403
1414
case "literal" : {
@@ -1433,6 +1444,9 @@ namespace ts.Completions {
1433
1444
readonly sourceDisplay : SymbolDisplayPart [ ] | undefined ;
1434
1445
}
1435
1446
function getCompletionEntryCodeActionsAndSourceDisplay (
1447
+ name : string ,
1448
+ location : Node ,
1449
+ contextToken : Node | undefined ,
1436
1450
origin : SymbolOriginInfo | SymbolOriginInfoExport | SymbolOriginInfoResolvedExport | undefined ,
1437
1451
symbol : Symbol ,
1438
1452
program : Program ,
@@ -1444,6 +1458,7 @@ namespace ts.Completions {
1444
1458
formatContext : formatting . FormatContext ,
1445
1459
preferences : UserPreferences ,
1446
1460
data : CompletionEntryData | undefined ,
1461
+ source : string | undefined ,
1447
1462
) : CodeActionsAndSourceDisplay {
1448
1463
if ( data ?. moduleSpecifier ) {
1449
1464
const { contextToken, previousToken } = getRelevantTokens ( position , sourceFile ) ;
@@ -1453,6 +1468,30 @@ namespace ts.Completions {
1453
1468
}
1454
1469
}
1455
1470
1471
+ if ( source === CompletionSource . ClassMemberSnippet ) {
1472
+ const { importAdder } = getEntryForMemberCompletion (
1473
+ host ,
1474
+ program ,
1475
+ compilerOptions ,
1476
+ preferences ,
1477
+ name ,
1478
+ symbol ,
1479
+ location ,
1480
+ contextToken ) ;
1481
+ if ( importAdder ) {
1482
+ const changes = textChanges . ChangeTracker . with (
1483
+ { host, formatContext, preferences } ,
1484
+ importAdder . writeFixes ) ;
1485
+ return {
1486
+ sourceDisplay : undefined ,
1487
+ codeActions : [ {
1488
+ changes,
1489
+ description : diagnosticToString ( [ Diagnostics . Includes_imports_of_types_referenced_by_0 , name ] ) ,
1490
+ } ] ,
1491
+ } ;
1492
+ }
1493
+ }
1494
+
1456
1495
if ( ! origin || ! ( originIsExport ( origin ) || originIsResolvedExport ( origin ) ) ) {
1457
1496
return { codeActions : undefined , sourceDisplay : undefined } ;
1458
1497
}
0 commit comments