@@ -16,6 +16,7 @@ open FSharp.Compiler.Range
1616open System.Runtime .Caching
1717open Microsoft.CodeAnalysis .Host .Mef
1818open Microsoft.CodeAnalysis .ExternalAccess .FSharp .Diagnostics
19+ open FSharp.Compiler .SourceCodeServices
1920
2021type private TextVersionHash = int
2122type private PerDocumentSavedData = { Hash: int ; Diagnostics: ImmutableArray < Diagnostic > }
@@ -26,7 +27,7 @@ type internal SimplifyNameDiagnosticAnalyzer [<ImportingConstructor>] () =
2627 static let userOpName = " SimplifyNameDiagnosticAnalyzer"
2728 let getProjectInfoManager ( document : Document ) = document.Project.Solution.Workspace.Services.GetService< FSharpCheckerWorkspaceService>() .FSharpProjectOptionsManager
2829 let getChecker ( document : Document ) = document.Project.Solution.Workspace.Services.GetService< FSharpCheckerWorkspaceService>() .Checker
29- let getPlidLength ( plid : string list ) = ( plid |> List.sumBy String.length ) + plid.Length
30+
3031 static let cache = new MemoryCache( " FSharp.Editor." + userOpName)
3132 // Make sure only one document is being analyzed at a time, to be nice
3233 static let guard = new SemaphoreSlim( 1 )
@@ -52,62 +53,15 @@ type internal SimplifyNameDiagnosticAnalyzer [<ImportingConstructor>] () =
5253 let! sourceText = document.GetTextAsync()
5354 let checker = getChecker document
5455 let! _ , _ , checkResults = checker.ParseAndCheckDocument( document, projectOptions, sourceText = sourceText, userOpName= userOpName)
55- let! symbolUses = checkResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync
56- let mutable result = ResizeArray()
57- let symbolUses =
58- symbolUses
59- |> Array.filter ( fun symbolUse -> not symbolUse.IsFromOpenStatement)
60- |> Array.Parallel.map ( fun symbolUse ->
61- let lineStr = sourceText.Lines.[ Line.toZ symbolUse.RangeAlternate.StartLine]. ToString()
62- // for `System.DateTime.Now` it returns ([|"System"; "DateTime"|], "Now")
63- let partialName = QuickParse.GetPartialLongNameEx( lineStr, symbolUse.RangeAlternate.EndColumn - 1 )
64- // `symbolUse.RangeAlternate.Start` does not point to the start of plid, it points to start of `name`,
65- // so we have to calculate plid's start ourselves.
66- let plidStartCol = symbolUse.RangeAlternate.EndColumn - partialName.PartialIdent.Length - ( getPlidLength partialName.QualifyingIdents)
67- symbolUse, partialName.QualifyingIdents, plidStartCol, partialName.PartialIdent)
68- |> Array.filter ( fun ( _ , plid , _ , name ) -> name <> " " && not ( List.isEmpty plid))
69- |> Array.groupBy ( fun ( symbolUse , _ , plidStartCol , _ ) -> symbolUse.RangeAlternate.StartLine, plidStartCol)
70- |> Array.map ( fun ( _ , xs ) -> xs |> Array.maxBy ( fun ( symbolUse , _ , _ , _ ) -> symbolUse.RangeAlternate.EndColumn))
71-
72- for symbolUse, plid, plidStartCol, name in symbolUses do
73- if not symbolUse.IsFromDefinition then
74- let posAtStartOfName =
75- let r = symbolUse.RangeAlternate
76- if r.StartLine = r.EndLine then Range.mkPos r.StartLine ( r.EndColumn - name.Length)
77- else r.Start
78-
79- let getNecessaryPlid ( plid : string list ) : Async < string list > =
80- let rec loop ( rest : string list ) ( current : string list ) =
81- async {
82- match rest with
83- | [] -> return current
84- | headIdent :: restPlid ->
85- let! res = checkResults.IsRelativeNameResolvableFromSymbol( posAtStartOfName, current, symbolUse.Symbol, userOpName= userOpName)
86- if res then return current
87- else return ! loop restPlid ( headIdent :: current)
88- }
89- loop ( List.rev plid) []
90-
91- do ! Async.Sleep DefaultTuning.SimplifyNameEachItemDelay |> liftAsync // be less intrusive, give other work priority most of the time
92- let! necessaryPlid = getNecessaryPlid plid |> liftAsync
93-
94- match necessaryPlid with
95- | necessaryPlid when necessaryPlid = plid -> ()
96- | necessaryPlid ->
97- let r = symbolUse.RangeAlternate
98- let necessaryPlidStartCol = r.EndColumn - name.Length - ( getPlidLength necessaryPlid)
99-
100- let unnecessaryRange =
101- Range.mkRange r.FileName ( Range.mkPos r.StartLine plidStartCol) ( Range.mkPos r.EndLine necessaryPlidStartCol)
102-
103- let relativeName = ( String.concat " ." plid) + " ." + name
104- result.Add(
105- Diagnostic.Create(
106- descriptor,
107- RoslynHelpers.RangeToLocation( unnecessaryRange, sourceText, document.FilePath),
108- properties = ( dict [ SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey, relativeName]) .ToImmutableDictionary()))
109-
110- let diagnostics = result.ToImmutableArray()
56+ let! result = SimplifyNames.getSimplifiableNames( checkResults, fun lineNumber -> sourceText.Lines.[ Line.toZ lineNumber]. ToString()) |> liftAsync
57+ let mutable diag = ResizeArray()
58+ for r in result do
59+ diag.Add(
60+ Diagnostic.Create(
61+ descriptor,
62+ RoslynHelpers.RangeToLocation( r.Range, sourceText, document.FilePath),
63+ properties = ( dict [ SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey, r.RelativeName]). ToImmutableDictionary()))
64+ let diagnostics = diag.ToImmutableArray()
11165 cache.Remove( key) |> ignore
11266 let data = { Hash = textVersionHash; Diagnostics= diagnostics }
11367 let cacheItem = CacheItem( key, data)
0 commit comments