未验证 提交 0c2f90f8 编写于 作者: P Phillip Carter 提交者: GitHub

Use MEF instead of GetService calls in diagnostic analyzers (#10531)

上级 d21e15e3
......@@ -10,29 +10,25 @@ open System.Threading
open System.Threading.Tasks
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Diagnostics
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
open FSharp.Compiler
open FSharp.Compiler.SourceCodeServices
[<RequireQualifiedAccess>]
type internal DiagnosticsType =
| Syntax
| Semantic
[<Export(typeof<IFSharpDocumentDiagnosticAnalyzer>)>]
type internal FSharpDocumentDiagnosticAnalyzer [<ImportingConstructor>] () =
type internal FSharpDocumentDiagnosticAnalyzer
[<ImportingConstructor>]
(
checkerProvider: FSharpCheckerProvider,
projectInfoManager: FSharpProjectOptionsManager
) =
static let userOpName = "DocumentDiagnosticAnalyzer"
let getChecker(document: Document) =
document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().Checker
let getProjectInfoManager(document: Document) =
document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().FSharpProjectOptionsManager
static let errorInfoEqualityComparer =
{ new IEqualityComparer<FSharpErrorInfo> with
......@@ -110,27 +106,25 @@ type internal FSharpDocumentDiagnosticAnalyzer [<ImportingConstructor>] () =
interface IFSharpDocumentDiagnosticAnalyzer with
member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
let projectInfoManager = getProjectInfoManager document
asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
return!
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax)
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax)
|> liftAsync
}
|> Async.map (Option.defaultValue ImmutableArray<Diagnostic>.Empty)
|> RoslynHelpers.StartAsyncAsTask cancellationToken
member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
let projectInfoManager = getProjectInfoManager document
asyncMaybe {
let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
if document.Project.Name <> FSharpConstants.FSharpMiscellaneousFilesName || isScriptFile document.FilePath then
return!
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic)
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic)
|> liftAsync
else
return ImmutableArray<Diagnostic>.Empty
......
......@@ -17,12 +17,14 @@ open FSharp.Compiler.SourceCodeServices
type private PerDocumentSavedData = { Hash: int; Diagnostics: ImmutableArray<Diagnostic> }
[<Export(typeof<IFSharpSimplifyNameDiagnosticAnalyzer>)>]
type internal SimplifyNameDiagnosticAnalyzer [<ImportingConstructor>] () =
type internal SimplifyNameDiagnosticAnalyzer
[<ImportingConstructor>]
(
checkerProvider: FSharpCheckerProvider,
projectInfoManager: FSharpProjectOptionsManager
) =
static let userOpName = "SimplifyNameDiagnosticAnalyzer"
let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().FSharpProjectOptionsManager
let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().Checker
static let cache = new MemoryCache("FSharp.Editor." + userOpName)
// Make sure only one document is being analyzed at a time, to be nice
static let guard = new SemaphoreSlim(1)
......@@ -36,7 +38,7 @@ type internal SimplifyNameDiagnosticAnalyzer [<ImportingConstructor>] () =
do! Option.guard document.FSharpOptions.CodeFixes.SimplifyName
do Trace.TraceInformation("{0:n3} (start) SimplifyName", DateTime.Now.TimeOfDay.TotalSeconds)
do! Async.Sleep DefaultTuning.SimplifyNameInitialDelay |> liftAsync
let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
let textVersionHash = textVersion.GetHashCode()
let! _ = guard.WaitAsync(cancellationToken) |> Async.AwaitTask |> liftAsync
......@@ -46,7 +48,7 @@ type internal SimplifyNameDiagnosticAnalyzer [<ImportingConstructor>] () =
| :? PerDocumentSavedData as data when data.Hash = textVersionHash -> return data.Diagnostics
| _ ->
let! sourceText = document.GetTextAsync()
let checker = getChecker document
let checker = checkerProvider.Checker
let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName=userOpName)
let! result = SimplifyNames.getSimplifiableNames(checkResults, fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString()) |> liftAsync
let mutable diag = ResizeArray()
......
......@@ -4,24 +4,22 @@ namespace rec Microsoft.VisualStudio.FSharp.Editor
open System
open System.Composition
open System.Collections.Generic
open System.Collections.Immutable
open System.Diagnostics
open System.Threading.Tasks
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Diagnostics
open Microsoft.CodeAnalysis.Host.Mef
open FSharp.Compiler.SourceCodeServices
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
[<Export(typeof<IFSharpUnusedDeclarationsDiagnosticAnalyzer>)>]
type internal UnusedDeclarationsAnalyzer [<ImportingConstructor>] () =
type internal UnusedDeclarationsAnalyzer
[<ImportingConstructor>]
(
checkerProvider: FSharpCheckerProvider,
projectInfoManager: FSharpProjectOptionsManager
) =
static let userOpName = "UnusedDeclarationsAnalyzer"
let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().FSharpProjectOptionsManager
let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().Checker
interface IFSharpUnusedDeclarationsDiagnosticAnalyzer with
......@@ -31,10 +29,10 @@ type internal UnusedDeclarationsAnalyzer [<ImportingConstructor>] () =
do Trace.TraceInformation("{0:n3} (start) UnusedDeclarationsAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds)
do! Async.Sleep DefaultTuning.UnusedDeclarationsAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time
match! getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) with
match! projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) with
| (_parsingOptions, projectOptions) ->
let! sourceText = document.GetTextAsync()
let checker = getChecker document
let checker = checkerProvider.Checker
let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName)
let! unusedRanges = UnusedDeclarations.getUnusedDeclarations( checkResults, (isScriptFile document.FilePath)) |> liftAsync
return
......
......@@ -16,10 +16,12 @@ open FSharp.Compiler.SourceCodeServices
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
[<Export(typeof<IFSharpUnusedOpensDiagnosticAnalyzer>)>]
type internal UnusedOpensDiagnosticAnalyzer [<ImportingConstructor>] () =
let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().FSharpProjectOptionsManager
let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().Checker
type internal UnusedOpensDiagnosticAnalyzer
[<ImportingConstructor>]
(
checkerProvider: FSharpCheckerProvider,
projectInfoManager: FSharpProjectOptionsManager
) =
static let userOpName = "UnusedOpensAnalyzer"
......@@ -28,13 +30,7 @@ type internal UnusedOpensDiagnosticAnalyzer [<ImportingConstructor>] () =
do! Option.guard document.FSharpOptions.CodeFixes.UnusedOpens
let! sourceText = document.GetTextAsync()
let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, userOpName = userOpName)
#if DEBUG
let sw = Stopwatch.StartNew()
#endif
let! unusedOpens = UnusedOpens.getUnusedOpens(checkResults, fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString()) |> liftAsync
#if DEBUG
Logging.Logging.logInfof "*** Got %d unused opens in %O" unusedOpens.Length sw.Elapsed
#endif
return unusedOpens
}
......@@ -44,9 +40,9 @@ type internal UnusedOpensDiagnosticAnalyzer [<ImportingConstructor>] () =
asyncMaybe {
do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds)
do! Async.Sleep DefaultTuning.UnusedOpensAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time
let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
let! sourceText = document.GetTextAsync()
let checker = getChecker document
let checker = checkerProvider.Checker
let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker)
return
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册