@@ -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 () =
2928member __.DisplayName = " "
3029member __.FullDisplayName = " "
3130member __.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>. FromResultnull
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>. FromResultnull
35+ member __.TryOnBeforeGlobalSymbolRenamed ( _ , _ , _ ) = false
36+ member __.TryOnAfterGlobalSymbolRenamed ( _ , _ , _ ) = false
3837static 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 ) =
4540interface IInlineRenameLocationSetwith
46- member __.Locations : IList < InlineRenameLocation > =
47- upcast [| for docin locationsByDocumentdo 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 )=
5145async {
52- if i= locationsByDocument.Lengththen
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 locationsByDocumentwith
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
6254async {
63- let! newSolution = applyChanges0 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
6462return
6563{ new IInlineRenameReplacementInfowith
6664member __.NewSolution = newSolution
6765member __.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
9896member __.LocalizedErrorMessage = null
9997member __.TriggerSpan = triggerSpan
10098member __.HasOverloads = false
101- member __.ForceRenameOverloads = true
99+ member __.ForceRenameOverloads = false
102100member __.DisplayName = symbolUse.Symbol.DisplayName
103101member __.FullDisplayName = try symbolUse.Symbol.FullNamewith _ -> symbolUse.Symbol.DisplayName
104102member __.Glyph = Glyph.MethodPublic
@@ -108,30 +106,34 @@ type internal InlineRenameInfo
108106let 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
113116member __.FindRenameLocationsAsync ( _optionSet , cancellationToken ) =
114117async {
115118let! symbolUsesByDocumentId = symbolUses
116- let! locationsByDocument =
119+ let! locations =
117120 symbolUsesByDocumentId
118121|> Seq.map( fun ( KeyValue ( documentId , symbolUses )) ->
119122async {
120123let document = document.Project.Solution.GetDocument( documentId)
121- let! cancellationToken = Async.CancellationToken
122124let! 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 symbolUsein symbolUsesdo
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
137139member __.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
149150static let userOpName = " InlineRename"