未验证 提交 8eefa635 编写于 作者: W Will Smith 提交者: GitHub

[VS] Fixed duplication of entries for find all refs. Minor perf improvements. (#9100)

* Fixed duplication of entries for find all refs. Stopped constant fetching of source text per found item.

* Minor fixes
上级 a13d61d7
...@@ -47,6 +47,14 @@ type Solution with ...@@ -47,6 +47,14 @@ type Solution with
self.GetDocumentIdsWithFilePath (Path.GetFullPath filePath) self.GetDocumentIdsWithFilePath (Path.GetFullPath filePath)
|> Seq.tryHead |> Option.map (fun docId -> self.GetDocument docId) |> Seq.tryHead |> Option.map (fun docId -> self.GetDocument docId)
/// Try to find the documentId corresponding to the provided filepath and ProjectId within this solution
member self.TryGetDocumentFromPath(filePath, projId: ProjectId) =
// It's crucial to normalize file path here (specificaly, remove relative parts),
// otherwise Roslyn does not find documents.
self.GetDocumentIdsWithFilePath (Path.GetFullPath filePath)
|> Seq.filter (fun x -> x.ProjectId = projId)
|> Seq.tryHead |> Option.map (fun docId -> self.GetDocument docId)
/// Try to get a project inside the solution using the project's id /// Try to get a project inside the solution using the project's id
member self.TryGetProject (projId:ProjectId) = member self.TryGetProject (projId:ProjectId) =
......
...@@ -35,7 +35,7 @@ module internal SymbolHelpers = ...@@ -35,7 +35,7 @@ module internal SymbolHelpers =
return symbolUses return symbolUses
} }
let getSymbolUsesInProjects (symbol: FSharpSymbol, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, projects: Project list, onFound: range -> Async<unit>, userOpName) = let getSymbolUsesInProjects (symbol: FSharpSymbol, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, projects: Project list, onFound: Document -> TextSpan -> range -> Async<unit>, userOpName) =
projects projects
|> Seq.map (fun project -> |> Seq.map (fun project ->
async { async {
...@@ -43,8 +43,19 @@ module internal SymbolHelpers = ...@@ -43,8 +43,19 @@ module internal SymbolHelpers =
| Some (_parsingOptions, projectOptions) -> | Some (_parsingOptions, projectOptions) ->
for filePath in projectOptions.SourceFiles do for filePath in projectOptions.SourceFiles do
let! symbolUses = checker.FindBackgroundReferencesInFile(filePath, projectOptions, symbol, userOpName = userOpName) let! symbolUses = checker.FindBackgroundReferencesInFile(filePath, projectOptions, symbol, userOpName = userOpName)
for symbolUse in symbolUses do let documentOpt = project.Solution.TryGetDocumentFromPath(filePath, project.Id)
do! onFound symbolUse match documentOpt with
| Some document ->
let! ct = Async.CancellationToken
let! sourceText = document.GetTextAsync ct |> Async.AwaitTask
for symbolUse in symbolUses do
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse) with
| Some textSpan ->
do! onFound document textSpan symbolUse
| _ ->
()
| _ ->
()
| _ -> () | _ -> ()
}) })
|> Async.Sequential |> Async.Sequential
...@@ -76,7 +87,7 @@ module internal SymbolHelpers = ...@@ -76,7 +87,7 @@ module internal SymbolHelpers =
yield! project.GetDependentProjects() ] yield! project.GetDependentProjects() ]
|> List.distinctBy (fun x -> x.Id) |> List.distinctBy (fun x -> x.Id)
let! _ = getSymbolUsesInProjects (symbol, projectInfoManager, checker, projects, (fun symbolUse -> async { symbolUses.Add symbolUse }), userOpName) let! _ = getSymbolUsesInProjects (symbol, projectInfoManager, checker, projects, (fun _ _ symbolUse -> async { symbolUses.Add symbolUse }), userOpName)
return toDict symbolUses } return toDict symbolUses }
......
...@@ -13,6 +13,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages ...@@ -13,6 +13,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages
open FSharp.Compiler.Range open FSharp.Compiler.Range
open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.SourceCodeServices
open Microsoft.CodeAnalysis.Text
[<Export(typeof<IFSharpFindUsagesService>)>] [<Export(typeof<IFSharpFindUsagesService>)>]
type internal FSharpFindUsagesService type internal FSharpFindUsagesService
...@@ -65,51 +66,54 @@ type internal FSharpFindUsagesService ...@@ -65,51 +66,54 @@ type internal FSharpFindUsagesService
match declaration with match declaration with
| FSharpFindDeclResult.DeclFound range -> Some range | FSharpFindDeclResult.DeclFound range -> Some range
| _ -> None | _ -> None
let! declarationSpans = async {
match declarationRange with
| Some range -> return! rangeToDocumentSpans(document.Project.Solution, range)
| None -> return! async.Return [] } |> liftAsync
let isExternal = declarationSpans |> List.isEmpty
let displayParts = ImmutableArray.Create(TaggedText(TextTags.Text, symbol.Ident.idText))
let originationParts = ImmutableArray.Create(TaggedText(TextTags.Assembly, symbolUse.Symbol.Assembly.SimpleName))
let externalDefinitionItem = FSharpDefinitionItem.CreateNonNavigableItem(tags, displayParts, originationParts)
let definitionItems =
declarationSpans
|> List.map (fun span -> FSharpDefinitionItem.Create(tags, displayParts, span), span.Document.Id)
let! definitionItems = for definitionItem, _ in definitionItems do
async {
let! declarationSpans =
match declarationRange with
| Some range -> rangeToDocumentSpans(document.Project.Solution, range)
| None -> async.Return []
return
match declarationSpans with
| [] ->
[ FSharpDefinitionItem.CreateNonNavigableItem(
tags,
ImmutableArray.Create(TaggedText(TextTags.Text, symbol.Ident.idText)),
ImmutableArray.Create(TaggedText(TextTags.Assembly, symbolUse.Symbol.Assembly.SimpleName))) ]
| _ ->
declarationSpans
|> List.map (fun span ->
FSharpDefinitionItem.Create(tags, ImmutableArray.Create(TaggedText(TextTags.Text, symbol.Ident.idText)), span))
} |> liftAsync
for definitionItem in definitionItems do
do! context.OnDefinitionFoundAsync(definitionItem) |> Async.AwaitTask |> liftAsync do! context.OnDefinitionFoundAsync(definitionItem) |> Async.AwaitTask |> liftAsync
if isExternal then
do! context.OnDefinitionFoundAsync(externalDefinitionItem) |> Async.AwaitTask |> liftAsync
let onFound = let onFound =
fun (symbolUse: range) -> fun (doc: Document) (textSpan: TextSpan) (symbolUse: range) ->
async { async {
match declarationRange with match declarationRange with
| Some declRange when FSharp.Compiler.Range.equals declRange symbolUse -> () | Some declRange when FSharp.Compiler.Range.equals declRange symbolUse -> ()
| _ -> | _ ->
if allReferences then if allReferences then
let! referenceDocSpans = rangeToDocumentSpans(document.Project.Solution, symbolUse) let definitionItem =
match referenceDocSpans with if isExternal then
| [] -> () externalDefinitionItem
| _ -> else
for referenceDocSpan in referenceDocSpans do definitionItems
for definitionItem in definitionItems do |> List.tryFind (fun (_, docId) -> doc.Id = docId)
let referenceItem = FSharpSourceReferenceItem(definitionItem, referenceDocSpan) |> Option.map (fun (definitionItem, _) -> definitionItem)
do! context.OnReferenceFoundAsync(referenceItem) |> Async.AwaitTask } |> Option.defaultValue externalDefinitionItem
let referenceItem = FSharpSourceReferenceItem(definitionItem, FSharpDocumentSpan(doc, textSpan))
do! context.OnReferenceFoundAsync(referenceItem) |> Async.AwaitTask }
match symbolUse.GetDeclarationLocation document with match symbolUse.GetDeclarationLocation document with
| Some SymbolDeclarationLocation.CurrentDocument -> | Some SymbolDeclarationLocation.CurrentDocument ->
let! symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) |> liftAsync let! symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) |> liftAsync
for symbolUse in symbolUses do for symbolUse in symbolUses do
do! onFound symbolUse.RangeAlternate |> liftAsync match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) with
| Some textSpan ->
do! onFound document textSpan symbolUse.RangeAlternate |> liftAsync
| _ ->
()
| scope -> | scope ->
let projectsToCheck = let projectsToCheck =
match scope with match scope with
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册