diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 269f6baa5..7acb9146f 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -24,7 +24,7 @@
"rollForward": false
},
"fsharp-analyzers": {
- "version": "0.35.0",
+ "version": "0.37.2",
"commands": [
"fsharp-analyzers"
],
diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets
index 712cd7713..cb218acb6 100644
--- a/.paket/Paket.Restore.targets
+++ b/.paket/Paket.Restore.targets
@@ -241,8 +241,9 @@
$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[6])
$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[7])
$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[8])
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[9])
-
+
%(PaketReferencesFileLinesInfo.PackageVersion)
All
runtime
@@ -251,10 +252,8 @@
%(PaketReferencesFileLinesInfo.Aliases)
true
true
-
-
-
+
%(PaketReferencesFileLinesInfo.PackageVersion)
@@ -319,7 +318,17 @@
-
+
+
+
+
+ <_DefinedConditionProperties Include="@(_ConditionProperties)" Condition="$(%(Identity)) == 'true'"/>
+
+
+ <_ConditionsParameter>
+ <_ConditionsParameter Condition="@(_DefinedConditionProperties) != ''">--conditions @(_DefinedConditionProperties)
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c234ad8d2..a240c6212 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
## [Unreleased]
+### Changed
+
+- Update FSharp.Analyzers.SDK to `0.37.2`, which bumps FSharp.Core to `10.1.201` and FSharp.Compiler.Service to `43.12.201`, and adapt to the corresponding FCS syntax-tree API changes.
+
### Fixed
- [Disable inline values by default to restore pipeline hints](https://github.com/ionide/FsAutoComplete/pull/1456) - `InlineValueProvider` is no longer advertised by default, restoring pipeline hints during normal editing (closes [#1214](https://github.com/ionide/FsAutoComplete/issues/1214))
diff --git a/paket.dependencies b/paket.dependencies
index ccbffe48d..fbf43e345 100644
--- a/paket.dependencies
+++ b/paket.dependencies
@@ -24,7 +24,7 @@ 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
-nuget FSharp.Analyzers.SDK 0.35.0
+nuget FSharp.Analyzers.SDK 0.37.2
nuget ICSharpCode.Decompiler
nuget Mono.Cecil >= 0.11.4
nuget FSharpLint.Core
diff --git a/paket.lock b/paket.lock
index d7704d4f3..47bbcfd87 100644
--- a/paket.lock
+++ b/paket.lock
@@ -52,13 +52,13 @@ NUGET
FParsec (1.1.1) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0))
FSharp.Core (>= 4.3.4)
FSharp.Analyzers.Build (0.3)
- FSharp.Analyzers.SDK (0.35)
- FSharp.Compiler.Service (43.10.101) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
- FSharp.Core (10.0.101) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
+ FSharp.Analyzers.SDK (0.37.2)
+ FSharp.Compiler.Service (>= 43.12.201) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
+ FSharp.Core (10.1.201) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
McMaster.NETCore.Plugins (>= 2.0) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
Microsoft.Extensions.Logging.Abstractions (>= 6.0) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
- FSharp.Compiler.Service (43.10.101)
- FSharp.Core (10.0.101)
+ FSharp.Compiler.Service (43.12.201)
+ FSharp.Core (10.1.201)
System.Buffers (>= 4.6)
System.Collections.Immutable (>= 9.0)
System.Diagnostics.DiagnosticSource (>= 9.0)
@@ -72,7 +72,7 @@ NUGET
Fsharp.Control.Reactive (5.0.5) - restriction: || (== net10.0) (== net8.0) (== net9.0) (&& (== netstandard2.0) (>= net8.0)) (&& (== netstandard2.1) (>= net8.0))
FSharp.Core (>= 4.7.2)
System.Reactive (>= 5.0 < 6.0)
- FSharp.Core (10.0.101)
+ FSharp.Core (10.1.201)
FSharp.Data.Adaptive (1.2.18)
FSharp.Core (>= 4.7)
System.Reflection.Emit.Lightweight (>= 4.6)
diff --git a/src/FsAutoComplete.Core/FCSPatches.fs b/src/FsAutoComplete.Core/FCSPatches.fs
index d964a637a..af5ad675f 100644
--- a/src/FsAutoComplete.Core/FCSPatches.fs
+++ b/src/FsAutoComplete.Core/FCSPatches.fs
@@ -135,7 +135,7 @@ module SyntaxTreeOps =
| SynExpr.Match(expr = e; clauses = cl) -> walkExpr e || walkMatchClauses cl
- | SynExpr.LetOrUse(bindings = bs; body = e) -> walkBinds bs || walkExpr e
+ | SynExpr.LetOrUse letOrUse -> walkBinds letOrUse.Bindings || walkExpr letOrUse.Body
| SynExpr.TryWith(tryExpr = e; withCases = cl) -> walkExpr e || walkMatchClauses cl
@@ -243,7 +243,15 @@ type LanguageVersionShim(versionText: string) =
static let LanguageVersionTy =
lazy (Type.GetType("FSharp.Compiler.Features+LanguageVersion, FSharp.Compiler.Service"))
- static let ctor = lazy (LanguageVersionTy.Value.GetConstructor([| typeof |]))
+ // FCS 43.12 changed the LanguageVersion constructor from `(string)` to
+ // `(string, disabledFeaturesArray: _ option)`, so we can't look it up by an exact
+ // signature. Find the constructor whose first parameter is the version string instead.
+ static let ctor =
+ lazy
+ (LanguageVersionTy.Value.GetConstructors()
+ |> Array.find (fun c ->
+ let ps = c.GetParameters()
+ ps.Length >= 1 && ps.[0].ParameterType = typeof))
static let isPreviewEnabled =
lazy (ReflectionDelegates.createGetter LanguageVersionTy.Value "IsPreviewEnabled")
@@ -251,7 +259,16 @@ type LanguageVersionShim(versionText: string) =
static let supportsFeature =
lazy (ReflectionDelegates.createFuncArity1 LanguageVersionTy.Value LanguageFeatureShim.Type "SupportsFeature")
- let realLanguageVersion = ctor.Value.Invoke([| versionText |])
+ // Pass the version text as the first argument and null (= None / default) for any
+ // additional optional parameters the constructor may have gained.
+ let realLanguageVersion =
+ let c = ctor.Value
+
+ let args =
+ c.GetParameters()
+ |> Array.mapi (fun i _ -> if i = 0 then box versionText else null)
+
+ c.Invoke(args)
member x.IsPreviewEnabled = isPreviewEnabled.Value realLanguageVersion
diff --git a/src/FsAutoComplete.Core/InlayHints.fs b/src/FsAutoComplete.Core/InlayHints.fs
index 82171eae1..f2fe33f1d 100644
--- a/src/FsAutoComplete.Core/InlayHints.fs
+++ b/src/FsAutoComplete.Core/InlayHints.fs
@@ -593,7 +593,7 @@ let tryGetExplicitTypeInfo (text: IFSACSourceText, ast: ParsedInput) (pos: Posit
member visitor.VisitPat(path, defaultTraverse, pat) =
let invalidPositionForTypeAnnotation (path: SyntaxNode list) =
match path with
- | SyntaxNode.SynExpr(SynExpr.LetOrUse(isUse = true)) :: _ ->
+ | SyntaxNode.SynExpr(SynExpr.LetOrUse letOrUse) :: _ when letOrUse.IsUse ->
// use! value =
true
| _ -> false
diff --git a/src/FsAutoComplete.Core/TestAdapter.fs b/src/FsAutoComplete.Core/TestAdapter.fs
index 1967ec4ec..2bb056733 100644
--- a/src/FsAutoComplete.Core/TestAdapter.fs
+++ b/src/FsAutoComplete.Core/TestAdapter.fs
@@ -218,9 +218,9 @@ let getExpectoTests (ast: ParsedInput) : TestAdapterEntry list =
visitExpr parent cond
visitExpr parent trueBranch
falseBranchOpt |> Option.iter (visitExpr parent)
- | SynExpr.LetOrUse(bindings = bindings; body = body) ->
- visitBindings parent bindings
- visitExpr parent body
+ | SynExpr.LetOrUse letOrUse ->
+ visitBindings parent letOrUse.Bindings
+ visitExpr parent letOrUse.Body
| SynExpr.Record(_, _, fields, _) ->
fields
|> List.choose (fun (SynExprRecordField(expr = expr)) -> expr)
@@ -237,7 +237,7 @@ let getExpectoTests (ast: ParsedInput) : TestAdapterEntry list =
let rec visitDeclarations prefix decls =
for declaration in decls do
match declaration with
- | SynModuleDecl.Let(_, bindings, _) -> visitBindings prefix bindings
+ | SynModuleDecl.Let(bindings = bindings) -> visitBindings prefix bindings
| SynModuleDecl.NestedModule(decls = decls) -> visitDeclarations prefix decls
| _ -> ()
@@ -289,7 +289,7 @@ let getNUnitTest (ast: ParsedInput) : TestAdapterEntry list =
let rec visitMember (parent: TestAdapterEntry) =
function
| SynMemberDefn.Member(b, _) -> visitBinding parent b
- | SynMemberDefn.LetBindings(bindings, _, _, _) ->
+ | SynMemberDefn.LetBindings(bindings = bindings) ->
for b in bindings do
visitBinding parent b
| SynMemberDefn.NestedType(typeDef, _, _) -> visitTypeDef parent typeDef
@@ -366,7 +366,7 @@ let getNUnitTest (ast: ParsedInput) : TestAdapterEntry list =
for declaration in decls do
match declaration with
- | SynModuleDecl.Let(_, bindings, _) ->
+ | SynModuleDecl.Let(bindings = bindings) ->
for b in bindings do
visitBinding parent b
| SynModuleDecl.NestedModule(moduleInfo = ci; decls = decls) ->
@@ -463,7 +463,7 @@ let getXUnitTest ast : TestAdapterEntry list =
let rec visitMember (parent: TestAdapterEntry) =
function
| SynMemberDefn.Member(b, _) -> visitBinding parent b
- | SynMemberDefn.LetBindings(bindings, _, _, _) ->
+ | SynMemberDefn.LetBindings(bindings = bindings) ->
for b in bindings do
visitBinding parent b
| SynMemberDefn.NestedType(typeDef, _, _) -> visitTypeDef parent typeDef
@@ -540,7 +540,7 @@ let getXUnitTest ast : TestAdapterEntry list =
for declaration in decls do
match declaration with
- | SynModuleDecl.Let(_, bindings, _) ->
+ | SynModuleDecl.Let(bindings = bindings) ->
for b in bindings do
visitBinding parent b
| SynModuleDecl.NestedModule(moduleInfo = ci; decls = decls) ->
diff --git a/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs b/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs
index 15466f138..dc432d5f4 100644
--- a/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs
+++ b/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs
@@ -85,7 +85,7 @@ let private tryFindPatternMatchExprInParsedInput (pos: Position) (parsedInput: P
getIfPosInRange decl.Range (fun () ->
match decl with
| SynModuleDecl.Exception(SynExceptionDefn(members = synMembers), _) -> List.tryPick walkSynMemberDefn synMembers
- | SynModuleDecl.Let(_isRecursive, bindings, _range) -> List.tryPick walkBinding bindings
+ | SynModuleDecl.Let(bindings = bindings) -> List.tryPick walkBinding bindings
| SynModuleDecl.ModuleAbbrev(_lhs, _rhs, _range) -> None
| SynModuleDecl.NamespaceFragment(fragment) -> walkSynModuleOrNamespace fragment
| SynModuleDecl.NestedModule(decls = modules) -> List.tryPick walkSynModuleDecl modules
@@ -119,7 +119,7 @@ let private tryFindPatternMatchExprInParsedInput (pos: Position) (parsedInput: P
| SynMemberDefn.Member(binding, _range) -> walkBinding binding
| SynMemberDefn.NestedType(typeDef, _access, _range) -> walkSynTypeDefn typeDef
| SynMemberDefn.ValField(_field, _range) -> None
- | SynMemberDefn.LetBindings(bindings, _isStatic, _isRec, _range) -> List.tryPick walkBinding bindings
+ | SynMemberDefn.LetBindings(bindings = bindings) -> List.tryPick walkBinding bindings
| SynMemberDefn.GetSetMember(_get, _set, _range, _) -> None
| SynMemberDefn.Open _
| SynMemberDefn.ImplicitInherit _
@@ -230,9 +230,9 @@ let private tryFindPatternMatchExprInParsedInput (pos: Position) (parsedInput: P
| SynExpr.TypeApp(synExpr, _, _synTypeList, _commas, _, _, _range) -> walkExpr synExpr
- | SynExpr.LetOrUse(body = synExpr; bindings = synBindingList) ->
- walkExpr synExpr
- |> Option.orElseWith (fun _ -> List.tryPick walkBinding synBindingList)
+ | SynExpr.LetOrUse letOrUse ->
+ walkExpr letOrUse.Body
+ |> Option.orElseWith (fun _ -> List.tryPick walkBinding letOrUse.Bindings)
| SynExpr.TryWith(tryExpr = synExpr) -> walkExpr synExpr
diff --git a/src/FsAutoComplete.Core/UntypedAstUtils.fs b/src/FsAutoComplete.Core/UntypedAstUtils.fs
index c0097ce02..2cef8924d 100644
--- a/src/FsAutoComplete.Core/UntypedAstUtils.fs
+++ b/src/FsAutoComplete.Core/UntypedAstUtils.fs
@@ -310,9 +310,9 @@ module Syntax =
| SynExpr.TypeApp(e, _, tys, _, _, _, _) ->
List.iter walkType tys
walkExpr e
- | SynExpr.LetOrUse(bindings = bindings; body = e; range = _) ->
- List.iter walkBinding bindings
- walkExpr e
+ | SynExpr.LetOrUse letOrUse ->
+ List.iter walkBinding letOrUse.Bindings
+ walkExpr letOrUse.Body
| SynExpr.TryWith(tryExpr = e; withCases = clauses; range = _) ->
List.iter walkClause clauses
walkExpr e
@@ -445,7 +445,7 @@ module Syntax =
| SynMemberDefn.ImplicitInherit(inheritType = t; inheritArgs = e) ->
walkType t
walkExpr e
- | SynMemberDefn.LetBindings(bindings, _, _, _) -> List.iter walkBinding bindings
+ | SynMemberDefn.LetBindings(bindings = bindings) -> List.iter walkBinding bindings
| SynMemberDefn.Interface(t, _, members, _) ->
walkType t
members |> Option.iter (List.iter walkMember)
@@ -531,7 +531,7 @@ module Syntax =
| SynModuleDecl.NestedModule(info, _, modules, _, _, _) ->
walkComponentInfo info
List.iter walkSynModuleDecl modules
- | SynModuleDecl.Let(_, bindings, _) -> List.iter walkBinding bindings
+ | SynModuleDecl.Let(bindings = bindings) -> List.iter walkBinding bindings
| SynModuleDecl.Expr(expr, _) -> walkExpr expr
| SynModuleDecl.Types(types, _) -> List.iter walkTypeDefn types
| SynModuleDecl.Attributes(attributes = AllAttrs attrs; range = _) -> List.iter walkAttribute attrs
diff --git a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs
index 9871ed621..6800afb11 100644
--- a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs
+++ b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs
@@ -261,7 +261,7 @@ type AdaptiveState
if enableAnalyzers then
let mutable assemblyLoadStats =
{ AnalyzerAssemblies = 0
- Analyzers = 0
+ AnalyzerNames = []
FailedAssemblies = 0 }
let excludeInclude =
@@ -287,7 +287,7 @@ type AdaptiveState
assemblyLoadStats <-
{ AnalyzerAssemblies = assemblyLoadStats.AnalyzerAssemblies + stats.AnalyzerAssemblies
- Analyzers = assemblyLoadStats.Analyzers + stats.Analyzers
+ AnalyzerNames = assemblyLoadStats.AnalyzerNames @ stats.AnalyzerNames
FailedAssemblies = assemblyLoadStats.FailedAssemblies + stats.FailedAssemblies }
@@ -298,7 +298,7 @@ type AdaptiveState
assemblyLoadStats <-
{ AnalyzerAssemblies = assemblyLoadStats.AnalyzerAssemblies + stats.AnalyzerAssemblies
- Analyzers = assemblyLoadStats.Analyzers + stats.Analyzers
+ AnalyzerNames = assemblyLoadStats.AnalyzerNames @ stats.AnalyzerNames
FailedAssemblies = assemblyLoadStats.FailedAssemblies + stats.FailedAssemblies }
)
diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
index 1f03e238b..36c61fd52 100644
--- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
+++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
@@ -3684,7 +3684,6 @@ let tests textFactory state =
AddExplicitTypeAnnotationTests.tests state
AdjustConstantTests.tests state
ToInterpolatedStringTests.tests state
- ToInterpolatedStringTests.unavailableTests state
addMissingEqualsToTypeDefinitionTests state
addMissingFunKeywordTests state
addMissingInstanceMemberTests state
diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/ToInterpolatedStringTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/ToInterpolatedStringTests.fs
index 5e70b6fd4..2d393f5a1 100644
--- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/ToInterpolatedStringTests.fs
+++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/ToInterpolatedStringTests.fs
@@ -7,12 +7,14 @@ open Utils.CursorbasedTests
open FsAutoComplete.CodeFix
open FsAutoComplete.FCSPatches
-let langVersion60Config =
+// NOTE: language versions <= 7.0 are "out of support" in FCS 43.12+ and cause the
+// project to fail to load, so we pin to 8.0 (LTS), which still supports string interpolation.
+let langVersion80Config =
{ defaultConfigDto with
- FSIExtraSharedParameters = Some [| "--langversion:6.0" |] }
+ FSIExtraSharedParameters = Some [| "--langversion:8.0" |] }
let tests state =
- serverTestList (nameof ToInterpolatedString) state langVersion60Config None (fun server ->
+ serverTestList (nameof ToInterpolatedString) state langVersion80Config None (fun server ->
[ let selectCodeFix = CodeFix.withTitle ToInterpolatedString.title
testCaseAsync "simple integer string format"
@@ -341,6 +343,17 @@ let tests state =
Expect.equal true (languageVersion.SupportsFeature LanguageFeatureShim) ""
}
+ // String interpolation was introduced in F# 5.0, so an older language version must report
+ // it as unsupported. This replaces the former `unavailableTests` server test: every language
+ // version still supported by FCS now includes the feature, so the negative case can only be
+ // exercised at the unit level (constructing the shim does not require the version to compile).
+ testCaseAsync "Reflecting into LanguageVersion - feature unsupported in older version"
+ <| async {
+ let feature = LanguageFeatureShim("StringInterpolation")
+ let languageVersion = LanguageVersionShim("4.7")
+ Expect.equal false (languageVersion.SupportsFeature feature) ""
+ }
+
testCaseAsync "Multiline applications are not supported"
<| CodeFix.checkNotApplicable
server
@@ -353,22 +366,3 @@ let tests state =
selectCodeFix
])
-
-let langVersion47Config =
- { defaultConfigDto with
- FSIExtraSharedParameters = Some [| "--langversion:4.7" |] }
-
-let unavailableTests state =
- serverTestList $"unavailable {(nameof ToInterpolatedString)}" state langVersion47Config None (fun server ->
- [ let selectCodeFix = CodeFix.withTitle ToInterpolatedString.title
-
- testCaseAsync "codefix not available for langversion"
- <| CodeFix.checkNotApplicable
- server
- """
- let a = sprintf$0 "Hey %i" 3
- """
- Diagnostics.acceptAll
- selectCodeFix
-
- ])