diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index 12adae55598..91751ba27df 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -13,6 +13,7 @@ * Fixed checking failure when `global` namespace is involved with enabled GraphBasedChecking ([PR #17553](https://github.com/dotnet/fsharp/pull/17553)) * Add missing byte chars notations, enforce limits in decimal notation in byte char & string (Issues [#15867](https://github.com/dotnet/fsharp/issues/15867), [#15868](https://github.com/dotnet/fsharp/issues/15868), [#15869](https://github.com/dotnet/fsharp/issues/15869), [PR #15898](https://github.com/dotnet/fsharp/pull/15898)) * Parentheses analysis: keep extra parentheses around unit & tuples in method definitions. ([PR #17618](https://github.com/dotnet/fsharp/pull/17618)) +* Consider `open type` used when the type is an enum and any of the enum cases is used unqualified. ([PR #17628](https://github.com/dotnet/fsharp/pull/17628)) ### Added diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 29df63b1194..26b2ea1f7a2 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -51,6 +51,11 @@ module UnusedOpens = if not entity.IsNamespace && not entity.IsFSharpModule then for fv in entity.MembersFunctionsAndValues do fv + + if entity.IsEnum then + for field in entity.FSharpFields do + if field.IsStatic && field.IsLiteral then + field |] HashSet<_>(symbols, symbolHash) diff --git a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs index e14a3ae1e52..bbaac72bb56 100644 --- a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs @@ -5603,6 +5603,14 @@ open SomeUsedModuleContainingFunction open SomeUsedModuleContainingExtensionMember open SomeUsedModuleContainingActivePattern open SomeUsedModuleContainingUnion +open type System.DayOfWeek // Used, should not appear. +open type System.DateTimeKind // Unused, should appear. + +type FSharpEnum1 = X = 1 | Y = (1 <<< 1) | Z = (1 <<< 2) +type FSharpEnum2 = H = 1 | I = (1 <<< 1) | J = (1 <<< 2) + +open type FSharpEnum1 // Used, should not appear. +open type FSharpEnum2 // Unused, should appear. type UseTheThings(i:int) = member x.Value = Dictionary() // use something from System.Collections.Generic, as a constructor @@ -5610,6 +5618,10 @@ type UseTheThings(i:int) = member x.UseSomeUsedModuleContainingActivePattern(ActivePattern g) = g member x.UseSomeUsedModuleContainingExtensionMember() = (3).Q member x.UseSomeUsedModuleContainingUnion() = A + member x.UseEnumCase = Monday // Use an enum case from System.DayOfWeek. + member x.UseEnumCaseQualified = System.DateTimeKind.Utc // Use a qualified enum case. + member x.UseFSharpEnumCase = Y // Use an enum case from FSharpEnum1. + member x.UseFSharpEnumCaseQualified = FSharpEnum2.J // Use a qualified enum case. """ let fileSource1 = SourceText.ofString fileSource1Text FileSystem.OpenFileForWriteShim(fileName1).Write(fileSource1Text) @@ -5637,7 +5649,9 @@ type UseTheThings(i:int) = (((6, 5), (6, 19)), "open FSharp.Control // unused"); (((7, 5), (7, 16)), "open FSharp.Data // unused"); (((8, 5), (8, 25)), "open System.Globalization // unused"); - (((25, 5), (25, 21)), "open SomeUnusedModule")] + (((25, 5), (25, 21)), "open SomeUnusedModule"); + (((31, 10), (31, 29)), "open type System.DateTimeKind // Unused, should appear.") + (((37, 10), (37, 21)), "open type FSharpEnum2 // Unused, should appear.")] unusedOpensData |> shouldEqual expected []