@@ -768,7 +768,7 @@ namespace ts.Completions {
768768 completionKind === CompletionKind . MemberLike &&
769769 isClassLikeMemberCompletion ( symbol , location ) ) {
770770 let importAdder ;
771- ( { insertText, isSnippet, importAdder } = getEntryForMemberCompletion ( host , program , options , preferences , name , symbol , location , contextToken , formatContext ) ) ;
771+ ( { insertText, isSnippet, importAdder, replacementSpan } = getEntryForMemberCompletion ( host , program , options , preferences , name , symbol , location , contextToken , formatContext ) ) ;
772772 if ( importAdder ?. hasFixes ( ) ) {
773773 hasAction = true ;
774774 source = CompletionSource . ClassMemberSnippet ;
@@ -894,13 +894,14 @@ namespace ts.Completions {
894894 location : Node ,
895895 contextToken : Node | undefined ,
896896 formatContext : formatting . FormatContext | undefined ,
897- ) : { insertText : string , isSnippet ?: true , importAdder ?: codefix . ImportAdder } {
897+ ) : { insertText : string , isSnippet ?: true , importAdder ?: codefix . ImportAdder , replacementSpan ?: TextSpan } {
898898 const classLikeDeclaration = findAncestor ( location , isClassLike ) ;
899899 if ( ! classLikeDeclaration ) {
900900 return { insertText : name } ;
901901 }
902902
903903 let isSnippet : true | undefined ;
904+ let replacementSpan : TextSpan | undefined ;
904905 let insertText : string = name ;
905906
906907 const checker = program . getTypeChecker ( ) ;
@@ -932,10 +933,8 @@ namespace ts.Completions {
932933 let modifiers = ModifierFlags . None ;
933934 // Whether the suggested member should be abstract.
934935 // e.g. in `abstract class C { abstract | }`, we should offer abstract method signatures at position `|`.
935- // Note: We are relying on checking if the context token is `abstract`,
936- // since other visibility modifiers (e.g. `protected`) should come *before* `abstract`.
937- // However, that is not true for the e.g. `override` modifier, so this check has its limitations.
938- const isAbstract = contextToken && isModifierLike ( contextToken ) === SyntaxKind . AbstractKeyword ;
936+ const { modifiers : presentModifiers , span : modifiersSpan } = getPresentModifiers ( contextToken ) ;
937+ const isAbstract = ! ! ( presentModifiers & ModifierFlags . Abstract ) ;
939938 const completionNodes : Node [ ] = [ ] ;
940939 codefix . addNewNodeForMemberSymbol (
941940 symbol ,
@@ -961,26 +960,22 @@ namespace ts.Completions {
961960 requiredModifiers |= ModifierFlags . Override ;
962961 }
963962
964- let presentModifiers = ModifierFlags . None ;
965963 if ( ! completionNodes . length ) {
966- // Omit already present modifiers from the first completion node/signature.
967- if ( contextToken ) {
968- presentModifiers = getPresentModifiers ( contextToken ) ;
969- }
970964 // Keep track of added missing required modifiers and modifiers already present.
971965 // This is needed when we have overloaded signatures,
972966 // so this callback will be called for multiple nodes/signatures,
973967 // and we need to make sure the modifiers are uniform for all nodes/signatures.
974968 modifiers = node . modifierFlagsCache | requiredModifiers | presentModifiers ;
975969 }
976- node = factory . updateModifiers ( node , modifiers & ( ~ presentModifiers ) ) ;
970+ node = factory . updateModifiers ( node , modifiers ) ;
977971 completionNodes . push ( node ) ;
978972 } ,
979973 body ,
980974 codefix . PreserveOptionalFlags . Property ,
981975 isAbstract ) ;
982976
983977 if ( completionNodes . length ) {
978+ replacementSpan = modifiersSpan ;
984979 // If we have access to formatting settings, we print the nodes using the emitter,
985980 // and then format the printed text.
986981 if ( formatContext ) {
@@ -1015,11 +1010,15 @@ namespace ts.Completions {
10151010 }
10161011 }
10171012
1018- return { insertText, isSnippet, importAdder } ;
1013+ return { insertText, isSnippet, importAdder, replacementSpan } ;
10191014 }
10201015
1021- function getPresentModifiers ( contextToken : Node ) : ModifierFlags {
1016+ function getPresentModifiers ( contextToken : Node | undefined ) : { modifiers : ModifierFlags , span ?: TextSpan } {
1017+ if ( ! contextToken ) {
1018+ return { modifiers : ModifierFlags . None } ;
1019+ }
10221020 let modifiers = ModifierFlags . None ;
1021+ let span ;
10231022 let contextMod ;
10241023 /*
10251024 Cases supported:
@@ -1042,11 +1041,13 @@ namespace ts.Completions {
10421041 */
10431042 if ( contextMod = isModifierLike ( contextToken ) ) {
10441043 modifiers |= modifierToFlag ( contextMod ) ;
1044+ span = createTextSpanFromNode ( contextToken ) ;
10451045 }
10461046 if ( isPropertyDeclaration ( contextToken . parent ) ) {
10471047 modifiers |= modifiersToFlags ( contextToken . parent . modifiers ) ;
1048+ span = createTextSpanFromNode ( contextToken . parent ) ;
10481049 }
1049- return modifiers ;
1050+ return { modifiers, span } ;
10501051 }
10511052
10521053 function isModifierLike ( node : Node ) : ModifierSyntaxKind | undefined {
0 commit comments