Skip to content
This repository was archived by the owner on Dec 23, 2024. It is now read-only.

Commit d58c9ea

Browse files
vasily-kirichenkoKevinRansom
authored andcommitted
[WIP] Fix inlline rename at end of file (dotnet#3766)
* do not filter symbol uses by range length in getSymbolUsesInSolution because it causes loosing symbol occurrences in Inline Rename * make impl closer to the XAML one * remove obsolete import
1 parent c0bdbc4 commit d58c9ea

File tree

1 file changed

+44
-43
lines changed

1 file changed

+44
-43
lines changed

InlineRename/InlineRenameService.fs

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor
44

55
open System
66
open System.Composition
7-
open System.Collections.Generic
87
open System.Linq
98
open System.Threading
109
open System.Threading.Tasks
@@ -29,44 +28,43 @@ type internal FailureInlineRenameInfo private () =
2928
member __.DisplayName = ""
3029
member __.FullDisplayName = ""
3130
member __.Glyph = Glyph.MethodPublic
32-
member __.GetFinalSymbolName _replacementText = ""
33-
member __.GetReferenceEditSpan(_location, _cancellationToken) = Unchecked.defaultof<_>
34-
member __.GetConflictEditSpan(_location, _replacementText, _cancellationToken) = Nullable()
35-
member __.FindRenameLocationsAsync(_optionSet, _cancellationToken) = Task<IInlineRenameLocationSet>.FromResult null
36-
member __.TryOnBeforeGlobalSymbolRenamed(_workspace, _changedDocumentIDs, _replacementText) = false
37-
member __.TryOnAfterGlobalSymbolRenamed(_workspace, _changedDocumentIDs, _replacementText) = false
31+
member __.GetFinalSymbolName _ = ""
32+
member __.GetReferenceEditSpan(_, _) = Unchecked.defaultof<_>
33+
member __.GetConflictEditSpan(_, _, _) = Nullable()
34+
member __.FindRenameLocationsAsync(_, _) = Task<IInlineRenameLocationSet>.FromResult null
35+
member __.TryOnBeforeGlobalSymbolRenamed(_, _, _) = false
36+
member __.TryOnAfterGlobalSymbolRenamed(_, _, _) = false
3837
static member Instance = FailureInlineRenameInfo() :> IInlineRenameInfo
3938

40-
type internal DocumentLocations =
41-
{ Document: Document
42-
Locations: InlineRenameLocation [] }
43-
44-
type internal InlineRenameLocationSet(locationsByDocument: DocumentLocations [], originalSolution: Solution, symbolKind: LexerSymbolKind, symbol: FSharpSymbol) =
39+
type internal InlineRenameLocationSet(locations: InlineRenameLocation [], originalSolution: Solution, symbolKind: LexerSymbolKind, symbol: FSharpSymbol) =
4540
interface IInlineRenameLocationSet with
46-
member __.Locations : IList<InlineRenameLocation> =
47-
upcast [| for doc in locationsByDocument do yield! doc.Locations |].ToList()
41+
member __.Locations = upcast locations.ToList()
4842

49-
member this.GetReplacementsAsync(replacementText, _optionSet, cancellationToken) : Task<IInlineRenameReplacementInfo> =
50-
let rec applyChanges i (solution: Solution) =
43+
member __.GetReplacementsAsync(replacementText, _optionSet, cancellationToken) : Task<IInlineRenameReplacementInfo> =
44+
let rec applyChanges (solution: Solution) (locationsByDocument: (Document * InlineRenameLocation list) list) =
5145
async {
52-
if i = locationsByDocument.Length then
53-
return solution
54-
else
55-
let doc = locationsByDocument.[i]
56-
let! oldSourceText = doc.Document.GetTextAsync(cancellationToken) |> Async.AwaitTask
57-
let changes = doc.Locations |> Seq.map (fun loc -> TextChange(loc.TextSpan, replacementText))
58-
let newSource = oldSourceText.WithChanges(changes)
59-
return! applyChanges (i + 1) (solution.WithDocumentText(doc.Document.Id, newSource))
46+
match locationsByDocument with
47+
| [] -> return solution
48+
| (document, locations) :: rest ->
49+
let! oldSource = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
50+
let newSource = oldSource.WithChanges(locations |> List.map (fun l -> TextChange(l.TextSpan, replacementText)))
51+
return! applyChanges (solution.WithDocumentText(document.Id, newSource)) rest
6052
}
6153

6254
async {
63-
let! newSolution = applyChanges 0 originalSolution
55+
let! newSolution = applyChanges originalSolution (locations |> Array.toList |> List.groupBy (fun x -> x.Document))
56+
// > debug
57+
let newDoc = newSolution.GetDocument(locations.[0].Document.Id)
58+
let! newSource = newDoc.GetTextAsync(cancellationToken) |> Async.AwaitTask
59+
let newText = newSource.ToString()
60+
let _ = newText
61+
// < debug
6462
return
6563
{ new IInlineRenameReplacementInfo with
6664
member __.NewSolution = newSolution
6765
member __.ReplacementTextValid = Tokenizer.isValidNameForSymbol(symbolKind, symbol, replacementText)
68-
member __.DocumentIds = locationsByDocument |> Seq.map (fun doc -> doc.Document.Id)
69-
member __.GetReplacements(documentId) = Seq.empty }
66+
member __.DocumentIds = locations |> Seq.map (fun doc -> doc.Document.Id) |> Seq.distinct
67+
member __.GetReplacements _ = Seq.empty }
7068
}
7169
|> RoslynHelpers.StartAsyncAsTask(cancellationToken)
7270

@@ -98,7 +96,7 @@ type internal InlineRenameInfo
9896
member __.LocalizedErrorMessage = null
9997
member __.TriggerSpan = triggerSpan
10098
member __.HasOverloads = false
101-
member __.ForceRenameOverloads = true
99+
member __.ForceRenameOverloads = false
102100
member __.DisplayName = symbolUse.Symbol.DisplayName
103101
member __.FullDisplayName = try symbolUse.Symbol.FullName with _ -> symbolUse.Symbol.DisplayName
104102
member __.Glyph = Glyph.MethodPublic
@@ -108,30 +106,34 @@ type internal InlineRenameInfo
108106
let text = getDocumentText location.Document cancellationToken
109107
Tokenizer.fixupSpan(text, location.TextSpan)
110108

111-
member __.GetConflictEditSpan(location, _replacementText, _cancellationToken) = Nullable(location.TextSpan)
109+
member __.GetConflictEditSpan(location, replacementText, cancellationToken) =
110+
let text = getDocumentText location.Document cancellationToken
111+
let spanText = text.ToString(location.TextSpan)
112+
let position = spanText.LastIndexOf(replacementText, StringComparison.Ordinal)
113+
if position < 0 then Nullable()
114+
else Nullable(TextSpan(location.TextSpan.Start + position, replacementText.Length))
112115

113116
member __.FindRenameLocationsAsync(_optionSet, cancellationToken) =
114117
async {
115118
let! symbolUsesByDocumentId = symbolUses
116-
let! locationsByDocument =
119+
let! locations =
117120
symbolUsesByDocumentId
118121
|> Seq.map (fun (KeyValue(documentId, symbolUses)) ->
119122
async {
120123
let document = document.Project.Solution.GetDocument(documentId)
121-
let! cancellationToken = Async.CancellationToken
122124
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
123-
let locations =
124-
symbolUses
125-
|> Array.choose (fun symbolUse ->
126-
RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate)
127-
|> Option.map (fun span ->
128-
let textSpan = Tokenizer.fixupSpan(sourceText, span)
129-
InlineRenameLocation(document, textSpan)))
130-
131-
return { Document = document; Locations = locations }
125+
return
126+
[| for symbolUse in symbolUses do
127+
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) with
128+
| Some span ->
129+
let textSpan = Tokenizer.fixupSpan(sourceText, span)
130+
yield InlineRenameLocation(document, textSpan)
131+
| None -> () |]
132132
})
133133
|> Async.Parallel
134-
return InlineRenameLocationSet(locationsByDocument, document.Project.Solution, lexerSymbol.Kind, symbolUse.Symbol) :> IInlineRenameLocationSet
134+
|> Async.map Array.concat
135+
136+
return InlineRenameLocationSet(locations, document.Project.Solution, lexerSymbol.Kind, symbolUse.Symbol) :> IInlineRenameLocationSet
135137
} |> RoslynHelpers.StartAsyncAsTask(cancellationToken)
136138

137139
member __.TryOnBeforeGlobalSymbolRenamed(_workspace, _changedDocumentIDs, _replacementText) = true
@@ -142,8 +144,7 @@ type internal InlineRenameService
142144
[<ImportingConstructor>]
143145
(
144146
projectInfoManager: FSharpProjectOptionsManager,
145-
checkerProvider: FSharpCheckerProvider,
146-
[<ImportMany>] _refactorNotifyServices: seq<IRefactorNotifyService>
147+
checkerProvider: FSharpCheckerProvider
147148
) =
148149

149150
static let userOpName = "InlineRename"

0 commit comments

Comments
 (0)