未验证 提交 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
self.GetDocumentIdsWithFilePath (Path.GetFullPath filePath)
|> 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
member self.TryGetProject (projId:ProjectId) =
......
......@@ -35,7 +35,7 @@ module internal SymbolHelpers =
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
|> Seq.map (fun project ->
async {
......@@ -43,8 +43,19 @@ module internal SymbolHelpers =
| Some (_parsingOptions, projectOptions) ->
for filePath in projectOptions.SourceFiles do
let! symbolUses = checker.FindBackgroundReferencesInFile(filePath, projectOptions, symbol, userOpName = userOpName)
for symbolUse in symbolUses do
do! onFound symbolUse
let documentOpt = project.Solution.TryGetDocumentFromPath(filePath, project.Id)
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
......@@ -76,7 +87,7 @@ module internal SymbolHelpers =
yield! project.GetDependentProjects() ]
|> 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 }
......
......@@ -13,6 +13,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages
open FSharp.Compiler.Range
open FSharp.Compiler.SourceCodeServices
open Microsoft.CodeAnalysis.Text
[<Export(typeof<IFSharpFindUsagesService>)>]
type internal FSharpFindUsagesService
......@@ -65,51 +66,54 @@ type internal FSharpFindUsagesService
match declaration with
| FSharpFindDeclResult.DeclFound range -> Some range
| _ -> 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 =
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
for definitionItem, _ in definitionItems do
do! context.OnDefinitionFoundAsync(definitionItem) |> Async.AwaitTask |> liftAsync
if isExternal then
do! context.OnDefinitionFoundAsync(externalDefinitionItem) |> Async.AwaitTask |> liftAsync
let onFound =
fun (symbolUse: range) ->
fun (doc: Document) (textSpan: TextSpan) (symbolUse: range) ->
async {
match declarationRange with
| Some declRange when FSharp.Compiler.Range.equals declRange symbolUse -> ()
| _ ->
if allReferences then
let! referenceDocSpans = rangeToDocumentSpans(document.Project.Solution, symbolUse)
match referenceDocSpans with
| [] -> ()
| _ ->
for referenceDocSpan in referenceDocSpans do
for definitionItem in definitionItems do
let referenceItem = FSharpSourceReferenceItem(definitionItem, referenceDocSpan)
do! context.OnReferenceFoundAsync(referenceItem) |> Async.AwaitTask }
let definitionItem =
if isExternal then
externalDefinitionItem
else
definitionItems
|> List.tryFind (fun (_, docId) -> doc.Id = docId)
|> Option.map (fun (definitionItem, _) -> definitionItem)
|> Option.defaultValue externalDefinitionItem
let referenceItem = FSharpSourceReferenceItem(definitionItem, FSharpDocumentSpan(doc, textSpan))
do! context.OnReferenceFoundAsync(referenceItem) |> Async.AwaitTask }
match symbolUse.GetDeclarationLocation document with
| Some SymbolDeclarationLocation.CurrentDocument ->
let! symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) |> liftAsync
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 ->
let projectsToCheck =
match scope with
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册