@@ -4,7 +4,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor
44
55open System
66open System.Composition
7- open System.Collections .Generic
87open System.Linq
98open System.Threading
109open 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