From 4b0abc7bb79caa1f3c08d4cd5a2ec8fae8ea9d12 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Wed, 15 May 2024 15:51:07 -0500 Subject: [PATCH] update Analyzers and ProjInfo, and re-enable analyzers integration (#1296) --- .config/dotnet-tools.json | 17 ++- paket.dependencies | 12 +- paket.lock | 41 ++--- src/FsAutoComplete.Core/Commands.fs | 110 +++++++------- src/FsAutoComplete.Core/paket.references | 2 +- .../LspServers/AdaptiveServerState.fs | 141 +++++++++--------- src/FsAutoComplete/paket.references | 2 +- .../ExtensionsTests.fs | 6 +- test/OptionAnalyzer/Analyzer.fs | 68 ++++----- test/OptionAnalyzer/paket.references | 2 +- 10 files changed, 206 insertions(+), 195 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 2dc509c37..31be4cfa6 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -6,31 +6,36 @@ "version": "8.0.3", "commands": [ "paket" - ] + ], + "rollForward": false }, "dotnet-reportgenerator-globaltool": { "version": "5.0.2", "commands": [ "reportgenerator" - ] + ], + "rollForward": false }, "fantomas": { "version": "6.3.1", "commands": [ "fantomas" - ] + ], + "rollForward": false }, "fsharp-analyzers": { - "version": "0.25.0", + "version": "0.26.0", "commands": [ "fsharp-analyzers" - ] + ], + "rollForward": false }, "telplin": { "version": "0.9.6", "commands": [ "telplin" - ] + ], + "rollForward": false } } } \ No newline at end of file diff --git a/paket.dependencies b/paket.dependencies index 3a97b0465..40fc752da 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -14,19 +14,19 @@ lowest_matching: true nuget BenchmarkDotNet 0.13.5 nuget Fantomas.Client >= 0.9 nuget FSharp.Compiler.Service >= 43.8.300 -nuget Ionide.Analyzers 0.10.0 +nuget Ionide.Analyzers 0.11.0 nuget FSharp.Analyzers.Build 0.3.0 -nuget Ionide.ProjInfo >= 0.64.0 -nuget Ionide.ProjInfo.FCS >= 0.64.0 -nuget Ionide.ProjInfo.ProjectSystem >= 0.64.0 -nuget Ionide.ProjInfo.Sln >= 0.64.0 +nuget Ionide.ProjInfo >= 0.65.0 +nuget Ionide.ProjInfo.FCS >= 0.65.0 +nuget Ionide.ProjInfo.ProjectSystem >= 0.65.0 +nuget Ionide.ProjInfo.Sln >= 0.65.0 nuget Microsoft.Build >= 17.2 copy_local:false nuget Microsoft.Build.Framework >= 17.4 copy_local:false nuget Microsoft.Build.Utilities.Core >= 17.4 copy_local:false nuget Microsoft.Build.Tasks.Core >= 17.4 copy_local: false nuget Nuget.Frameworks >= 6.3 copy_local: false nuget Microsoft.CodeAnalysis 4.5.0 -# nuget FSharp.Analyzers.SDK # disabled because it conflicts with the floating FCS dependency +nuget FSharp.Analyzers.SDK 0.26.0 nuget ICSharpCode.Decompiler nuget Mono.Cecil >= 0.11.4 nuget FSharpLint.Core diff --git a/paket.lock b/paket.lock index d10bbd773..e32373207 100644 --- a/paket.lock +++ b/paket.lock @@ -56,6 +56,11 @@ NUGET FParsec (1.1.1) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) FSharp.Core (>= 4.3.4) FSharp.Analyzers.Build (0.3) + FSharp.Analyzers.SDK (0.26) + FSharp.Compiler.Service (43.8.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + FSharp.Core (8.0.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + McMaster.NETCore.Plugins (>= 1.4) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Microsoft.Extensions.Logging.Abstractions (>= 6.0) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) FSharp.Compiler.Service (43.8.300) FSharp.Core (8.0.300) System.Buffers (>= 4.5.1) @@ -127,32 +132,35 @@ NUGET Microsoft.Win32.Registry (>= 5.0) System.Collections.Immutable (>= 5.0) System.Reflection.Metadata (>= 5.0) - Ionide.Analyzers (0.10) + Ionide.Analyzers (0.11) Ionide.KeepAChangelog.Tasks (0.1.8) - copy_local: true Ionide.LanguageServerProtocol (0.4.23) FSharp.Core (>= 6.0) Newtonsoft.Json (>= 13.0.1) StreamJsonRpc (>= 2.16.36) - Ionide.ProjInfo (0.64) - FSharp.Core (>= 7.0.400) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo.Sln (>= 0.64) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo (0.65) + FSharp.Core (>= 8.0.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.Sln (>= 0.65) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Microsoft.Build (>= 17.2) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) SemanticVersioning (>= 2.0.2) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo.FCS (0.64) - FSharp.Compiler.Service (>= 43.7.400) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - FSharp.Core (>= 7.0.400) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo (>= 0.64) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo.ProjectSystem (0.64) - FSharp.Compiler.Service (>= 43.7.400) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.FCS (0.65) + FSharp.Compiler.Service (>= 43.8.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + FSharp.Core (>= 8.0.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo (>= 0.65) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.ProjectSystem (0.65) + FSharp.Compiler.Service (>= 43.8.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) FSharp.Control.Reactive (>= 5.0.5) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - FSharp.Core (>= 7.0.400) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo (>= 0.64) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo.FCS (>= 0.64) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo.Sln (>= 0.64) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + FSharp.Core (>= 8.0.300) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo (>= 0.65) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.FCS (>= 0.65) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.Sln (>= 0.65) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) - Ionide.ProjInfo.Sln (0.64) + Ionide.ProjInfo.Sln (0.65) LinkDotNet.StringBuilder (1.18) + McMaster.NETCore.Plugins (1.4) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= netcoreapp2.1)) (&& (== netstandard2.1) (>= netcoreapp2.1)) + Microsoft.Extensions.DependencyModel (>= 5.0) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= netcoreapp2.1)) (&& (== netstandard2.1) (>= netcoreapp2.1)) MessagePack (2.5.108) MessagePack.Annotations (>= 2.5.108) Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net7.0) (< net6.0)) (&& (== net8.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) @@ -270,6 +278,7 @@ NUGET Microsoft.Extensions.DependencyInjection.Abstractions (6.0) Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (&& (== net8.0) (>= net461)) (&& (== net8.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (&& (== net8.0) (>= net461)) (&& (== net8.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) + Microsoft.Extensions.DependencyModel (5.0) - restriction: || (== net6.0) (== net7.0) (== net8.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Microsoft.Extensions.Logging (6.0) Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (&& (== net8.0) (>= net461)) (&& (== net8.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) Microsoft.Extensions.DependencyInjection (>= 6.0) @@ -278,8 +287,6 @@ NUGET Microsoft.Extensions.Options (>= 6.0) System.Diagnostics.DiagnosticSource (>= 6.0) Microsoft.Extensions.Logging.Abstractions (6.0.2) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (&& (== net8.0) (>= net461)) (&& (== net8.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (&& (== net8.0) (>= net461)) (&& (== net8.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) Microsoft.Extensions.Logging.Configuration (6.0) Microsoft.Extensions.Configuration (>= 6.0) Microsoft.Extensions.Configuration.Abstractions (>= 6.0) diff --git a/src/FsAutoComplete.Core/Commands.fs b/src/FsAutoComplete.Core/Commands.fs index 4e13e3a3e..2c7ecf15a 100644 --- a/src/FsAutoComplete.Core/Commands.fs +++ b/src/FsAutoComplete.Core/Commands.fs @@ -14,7 +14,7 @@ open FSharp.Compiler.Text open Ionide.ProjInfo open Ionide.ProjInfo.ProjectSystem open FsToolkit.ErrorHandling -// open FSharp.Analyzers +open FSharp.Analyzers open FSharp.UMX open FSharp.Compiler.Tokenization open SymbolLocation @@ -75,7 +75,7 @@ module AsyncResult = type NotificationEvent = | ParseError of errors: FSharpDiagnostic[] * file: string * version: int | Workspace of ProjectSystem.ProjectResponse - // | AnalyzerMessage of messages: FSharp.Analyzers.SDK.Message[] * file: string * version: int + | AnalyzerMessage of messages: FSharp.Analyzers.SDK.Message[] * file: string * version: int | UnusedOpens of file: string * opens: Range[] * version: int // | Lint of file: string * warningsWithCodes: Lint.EnrichedLintWarning list | UnusedDeclarations of file: string * decls: range[] * version: int @@ -1137,59 +1137,59 @@ module Commands = -// let analyzerHandler -// ( -// client: SDK.Client, -// file: string, -// content: ISourceText, -// pt, -// tast, -// checkFileResults: FSharpCheckFileResults -// ) = -// let ctx: SDK.EditorContext = -// { FileName = UMX.untag file -// SourceText = content -// ParseFileResults = pt -// CheckFileResults = Some checkFileResults -// TypedTree = Some tast -// CheckProjectResults = None } - -// let extractResultsFromAnalyzer (r: SDK.AnalysisResult) = -// match r.Output with -// | Ok results -> -// Loggers.analyzers.info ( -// Log.setMessage "Analyzer {analyzer} returned {count} diagnostics for file {file}" -// >> Log.addContextDestructured "analyzer" r.AnalyzerName -// >> Log.addContextDestructured "count" results.Length -// >> Log.addContextDestructured "file" (UMX.untag file) -// ) - -// results -// | Error e -> -// Loggers.analyzers.error ( -// Log.setMessage "Analyzer {analyzer} errored while processing {file}: {message}" -// >> Log.addContextDestructured "analyzer" r.AnalyzerName -// >> Log.addContextDestructured "file" (UMX.untag file) -// >> Log.addContextDestructured "message" e.Message -// >> Log.addExn e -// ) - -// [] - -// async { -// try -// let! r = client.RunAnalyzersSafely ctx -// return r |> List.collect extractResultsFromAnalyzer |> List.toArray -// with ex -> -// Loggers.analyzers.error ( -// Log.setMessage "Error while processing analyzers for {file}: {message}" -// >> Log.addContextDestructured "message" ex.Message -// >> Log.addExn ex -// >> Log.addContextDestructured "file" file -// ) - -// return [||] -// } + let analyzerHandler + ( + client: SDK.Client, + file: string, + content: ISourceText, + pt, + tast, + checkFileResults: FSharpCheckFileResults + ) = + let ctx: SDK.EditorContext = + { FileName = UMX.untag file + SourceText = content + ParseFileResults = pt + CheckFileResults = Some checkFileResults + TypedTree = Some tast + CheckProjectResults = None } + + let extractResultsFromAnalyzer (r: SDK.AnalysisResult) = + match r.Output with + | Ok results -> + Loggers.analyzers.info ( + Log.setMessage "Analyzer {analyzer} returned {count} diagnostics for file {file}" + >> Log.addContextDestructured "analyzer" r.AnalyzerName + >> Log.addContextDestructured "count" results.Length + >> Log.addContextDestructured "file" (UMX.untag file) + ) + + results + | Error e -> + Loggers.analyzers.error ( + Log.setMessage "Analyzer {analyzer} errored while processing {file}: {message}" + >> Log.addContextDestructured "analyzer" r.AnalyzerName + >> Log.addContextDestructured "file" (UMX.untag file) + >> Log.addContextDestructured "message" e.Message + >> Log.addExn e + ) + + [] + + async { + try + let! r = client.RunAnalyzersSafely ctx + return r |> List.collect extractResultsFromAnalyzer |> List.toArray + with ex -> + Loggers.analyzers.error ( + Log.setMessage "Error while processing analyzers for {file}: {message}" + >> Log.addContextDestructured "message" ex.Message + >> Log.addExn ex + >> Log.addContextDestructured "file" file + ) + + return [||] + } type Commands() = diff --git a/src/FsAutoComplete.Core/paket.references b/src/FsAutoComplete.Core/paket.references index 6c7925f98..7e54bf3cb 100644 --- a/src/FsAutoComplete.Core/paket.references +++ b/src/FsAutoComplete.Core/paket.references @@ -1,4 +1,4 @@ -#FSharp.Analyzers.SDK +FSharp.Analyzers.SDK ICSharpCode.Decompiler Microsoft.SourceLink.GitHub FSharp.UMX diff --git a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs index 3d5c7f6fe..f4e2fdf44 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs @@ -220,10 +220,10 @@ type AdaptiveState [| yield! fsiCompilerToolLocations |> Array.map toCompilerToolArgument yield! fsiExtraParameters |] - // let analyzersClient = - // FSharp.Analyzers.SDK.Client( - // Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance - // ) + let analyzersClient = + FSharp.Analyzers.SDK.Client( + Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance + ) /// Loads F# Analyzers from the configured directories /// The FSharpConfig @@ -233,17 +233,17 @@ type AdaptiveState if config.EnableAnalyzers then Loggers.analyzers.info (Log.setMessageI $"Using analyzer roots of {config.AnalyzersPath:roots}") - // let excludeInclude = - // match config.ExcludeAnalyzers, config.IncludeAnalyzers with - // | e, [||] -> FSharp.Analyzers.SDK.ExcludeInclude.ExcludeFilter(fun (s: string) -> Array.contains s e) - // | [||], i -> FSharp.Analyzers.SDK.ExcludeInclude.IncludeFilter(fun (s: string) -> Array.contains s i) - // | _e, i -> - // Loggers.analyzers.warn ( - // Log.setMessage - // "--exclude-analyzers and --include-analyzers are mutually exclusive, ignoring --exclude-analyzers" - // ) + let excludeInclude = + match config.ExcludeAnalyzers, config.IncludeAnalyzers with + | e, [||] -> FSharp.Analyzers.SDK.ExcludeInclude.ExcludeFilter(fun (s: string) -> Array.contains s e) + | [||], i -> FSharp.Analyzers.SDK.ExcludeInclude.IncludeFilter(fun (s: string) -> Array.contains s i) + | _e, i -> + Loggers.analyzers.warn ( + Log.setMessage + "--exclude-analyzers and --include-analyzers are mutually exclusive, ignoring --exclude-analyzers" + ) - // FSharp.Analyzers.SDK.ExcludeInclude.IncludeFilter(fun (s: string) -> Array.contains s i) + FSharp.Analyzers.SDK.ExcludeInclude.IncludeFilter(fun (s: string) -> Array.contains s i) config.AnalyzersPath |> Array.iter (fun analyzerPath -> @@ -261,13 +261,12 @@ type AdaptiveState System.IO.Path.Combine(workspacePath, analyzerPath) Loggers.analyzers.info (Log.setMessageI $"Loading analyzers from {dir:dir}") - // let assemblyLoadStats = analyzersClient.LoadAnalyzers(dir, excludeInclude) + let assemblyLoadStats = analyzersClient.LoadAnalyzers(dir, excludeInclude) - // Loggers.analyzers.info ( - // Log.setMessageI - // $"From {analyzerPath:name}: {assemblyLoadStats.AnalyzerAssemblies:dllNo} dlls including {assemblyLoadStats.Analyzers:analyzersNo} analyzers" - // ) - ) + Loggers.analyzers.info ( + Log.setMessageI + $"From {analyzerPath:name}: {assemblyLoadStats.AnalyzerAssemblies:dllNo} dlls including {assemblyLoadStats.Analyzers:analyzersNo} analyzers" + )) else Loggers.analyzers.info (Log.setMessage "Analyzers disabled") @@ -521,22 +520,22 @@ type AdaptiveState ) match parseAndCheck.GetCheckResults.ImplementationFile with - | Some _tast -> + | Some tast -> // Since analyzers are not async, we need to switch to a new thread to not block threadpool do! Async.SwitchToNewThread() - // let! res = - // Commands.analyzerHandler ( - // analyzersClient, - // file, - // volatileFile.Source, - // parseAndCheck.GetParseResults, - // tast, - // parseAndCheck.GetCheckResults - // ) + let! res = + Commands.analyzerHandler ( + analyzersClient, + file, + volatileFile.Source, + parseAndCheck.GetParseResults, + tast, + parseAndCheck.GetCheckResults + ) - let! _ct = Async.CancellationToken - // notifications.Trigger(NotificationEvent.AnalyzerMessage(res, file, volatileFile.Version), ct) + let! ct = Async.CancellationToken + notifications.Trigger(NotificationEvent.AnalyzerMessage(res, file, volatileFile.Version), ct) Loggers.analyzers.info (Log.setMessageI $"end analysis of {file:file}") @@ -713,46 +712,46 @@ type AdaptiveState let ntf: PlainNotification = { Content = msg } do! lspClient.NotifyCancelledRequest ntf - // | NotificationEvent.AnalyzerMessage(messages, file, version) -> - // let uri = Path.LocalPathToUri file + | NotificationEvent.AnalyzerMessage(messages, file, version) -> + let uri = Path.LocalPathToUri file - // match messages with - // | [||] -> diagnosticCollections.SetFor(uri, "F# Analyzers", version, [||]) - // | messages -> - // let diags = - // messages - // |> Array.map (fun m -> - // let range = fcsRangeToLsp m.Range - - // let severity = DiagnosticSeverity.Hint - // // match m.Severity with - // // | FSharp.Analyzers.SDK.Severity.Hint -> DiagnosticSeverity.Hint - // // | FSharp.Analyzers.SDK.Severity.Info -> DiagnosticSeverity.Information - // // | FSharp.Analyzers.SDK.Severity.Warning -> DiagnosticSeverity.Warning - // // | FSharp.Analyzers.SDK.Severity.Error -> DiagnosticSeverity.Error - - // let fixes = - // match m.Fixes with - // | [] -> None - // | fixes -> - // fixes - // |> List.map (fun fix -> - // { Range = fcsRangeToLsp fix.FromRange - // NewText = fix.ToText }) - // |> Ionide.LanguageServerProtocol.Server.serialize - // |> Some - - // { Range = range - // Code = Option.ofObj m.Code - // Severity = Some severity - // Source = Some $"F# Analyzers (%s{m.Type})" - // Message = m.Message - // RelatedInformation = None - // Tags = None - // CodeDescription = None - // Data = fixes }) - - // diagnosticCollections.SetFor(uri, "F# Analyzers", version, diags) + match messages with + | [||] -> diagnosticCollections.SetFor(uri, "F# Analyzers", version, [||]) + | messages -> + let diags = + messages + |> Array.map (fun m -> + let range = fcsRangeToLsp m.Range + + let severity = + match m.Severity with + | FSharp.Analyzers.SDK.Severity.Hint -> DiagnosticSeverity.Hint + | FSharp.Analyzers.SDK.Severity.Info -> DiagnosticSeverity.Information + | FSharp.Analyzers.SDK.Severity.Warning -> DiagnosticSeverity.Warning + | FSharp.Analyzers.SDK.Severity.Error -> DiagnosticSeverity.Error + + let fixes = + match m.Fixes with + | [] -> None + | fixes -> + fixes + |> List.map (fun fix -> + { Range = fcsRangeToLsp fix.FromRange + NewText = fix.ToText }) + |> Ionide.LanguageServerProtocol.Server.serialize + |> Some + + { Range = range + Code = Option.ofObj m.Code + Severity = Some severity + Source = Some $"F# Analyzers (%s{m.Type})" + Message = m.Message + RelatedInformation = None + Tags = None + CodeDescription = None + Data = fixes }) + + diagnosticCollections.SetFor(uri, "F# Analyzers", version, diags) | NotificationEvent.TestDetected(file, tests) -> let rec map (r: TestAdapter.TestAdapterEntry) diff --git a/src/FsAutoComplete/paket.references b/src/FsAutoComplete/paket.references index f8bdc0908..87af7001a 100644 --- a/src/FsAutoComplete/paket.references +++ b/src/FsAutoComplete/paket.references @@ -1,7 +1,7 @@ CliWrap Destructurama.FSharp Fantomas.Client -#FSharp.Analyzers.SDK +FSharp.Analyzers.SDK FSharp.UMX FsToolkit.ErrorHandling.TaskResult IcedTasks diff --git a/test/FsAutoComplete.Tests.Lsp/ExtensionsTests.fs b/test/FsAutoComplete.Tests.Lsp/ExtensionsTests.fs index 07808ea4c..191ed0e1d 100644 --- a/test/FsAutoComplete.Tests.Lsp/ExtensionsTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/ExtensionsTests.fs @@ -333,7 +333,7 @@ let analyzerTests state = testList "analyzer integration" - [ ptestList + [ testList "tests" [ testCaseAsync "can run analyzer on file" @@ -410,8 +410,8 @@ let signatureTests state = |> Async.Sequential |> Async.map (fun _ -> ())) - testSequenced <| - testList + testSequenced + <| testList "signature evaluation" [ testList "tests" diff --git a/test/OptionAnalyzer/Analyzer.fs b/test/OptionAnalyzer/Analyzer.fs index 5a9a23155..9d46e58b1 100644 --- a/test/OptionAnalyzer/Analyzer.fs +++ b/test/OptionAnalyzer/Analyzer.fs @@ -1,7 +1,7 @@ module OptionAnalyzer open System -// open FSharp.Analyzers.SDK +open FSharp.Analyzers.SDK open FSharp.Compiler.Symbols open FSharp.Compiler.Text open FsAutoComplete.Logging @@ -117,36 +117,36 @@ let info message items = let inline (==>) x y = x, box y -// [] -// let optionValueAnalyzer: Analyzer = -// fun ctx -> -// async { -// info "analyzing {file} for uses of Option.Value" [ "file" ==> ctx.FileName ] -// let state = ResizeArray() - -// let handler (range: Range) (m: FSharpMemberOrFunctionOrValue) = -// let rangeString = -// sprintf "(%d,%d)-(%d,%d)" range.Start.Line range.Start.Column range.End.Line range.End.Column - -// let name = String.Join(".", m.DeclaringEntity.Value.FullName, m.DisplayName) -// info "checking value at {range} with name {name}" [ "range" ==> rangeString; "name" ==> name ] - -// if name = "Microsoft.FSharp.Core.FSharpOption`1.Value" then -// info "matched at range {range}" [ "range" ==> rangeString ] -// state.Add range - -// match ctx.TypedTree with -// | Some tt -> tt.Declarations |> List.iter (visitDeclaration handler) -// | None -> () - -// return -// state -// |> Seq.map (fun r -> -// { Type = "Option.Value analyzer" -// Message = "Option.Value shouldn't be used" -// Code = "OV001" -// Severity = Severity.Warning -// Range = r -// Fixes = [] }) -// |> Seq.toList -// } +[] +let optionValueAnalyzer: Analyzer = + fun ctx -> + async { + info "analyzing {file} for uses of Option.Value" [ "file" ==> ctx.FileName ] + let state = ResizeArray() + + let handler (range: Range) (m: FSharpMemberOrFunctionOrValue) = + let rangeString = + sprintf "(%d,%d)-(%d,%d)" range.Start.Line range.Start.Column range.End.Line range.End.Column + + let name = String.Join(".", m.DeclaringEntity.Value.FullName, m.DisplayName) + info "checking value at {range} with name {name}" [ "range" ==> rangeString; "name" ==> name ] + + if name = "Microsoft.FSharp.Core.FSharpOption`1.Value" then + info "matched at range {range}" [ "range" ==> rangeString ] + state.Add range + + match ctx.TypedTree with + | Some tt -> tt.Declarations |> List.iter (visitDeclaration handler) + | None -> () + + return + state + |> Seq.map (fun r -> + { Type = "Option.Value analyzer" + Message = "Option.Value shouldn't be used" + Code = "OV001" + Severity = Severity.Warning + Range = r + Fixes = [] }) + |> Seq.toList + } diff --git a/test/OptionAnalyzer/paket.references b/test/OptionAnalyzer/paket.references index 703966340..32815ed0e 100644 --- a/test/OptionAnalyzer/paket.references +++ b/test/OptionAnalyzer/paket.references @@ -1,2 +1,2 @@ -#FSharp.Analyzers.Sdk +FSharp.Analyzers.Sdk FSharp.Compiler.Service