diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index d5c2087765..d2d59c319a 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -3,6 +3,7 @@ * Fix DU case names matching IWSAM member names no longer cause duplicate property entries. (Issue [#14321](https://github.com/dotnet/fsharp/issues/14321), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) * Fix DefaultAugmentation(false) duplicate entry in method table. (Issue [#16565](https://github.com/dotnet/fsharp/issues/16565), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) * Fix abstract event accessors now have SpecialName flag. (Issue [#5834](https://github.com/dotnet/fsharp/issues/5834), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) +* Fix warning 20 ("expression is implicitly ignored") pointing at the wrong range when the last expression in a sequential block (e.g. inside `for`, `while` loops) is non-unit. The squiggle now correctly highlights only the offending expression. ([Issue #5735](https://github.com/dotnet/fsharp/issues/5735), [PR #19504](https://github.com/dotnet/fsharp/pull/19504)) * Fix CLIEvent properties to be correctly recognized as events: `IsEvent` returns `true` and `XmlDocSig` uses `E:` prefix instead of `P:`. ([Issue #10273](https://github.com/dotnet/fsharp/issues/10273), [PR #18584](https://github.com/dotnet/fsharp/pull/18584)) * Fix extra sequence point at the end of match expressions. ([Issue #12052](https://github.com/dotnet/fsharp/issues/12052), [PR #19278](https://github.com/dotnet/fsharp/pull/19278)) * Fix wrong sequence point range for `return`/`yield`/`return!`/`yield!` inside computation expressions. ([Issue #19248](https://github.com/dotnet/fsharp/issues/19248), [PR #19278](https://github.com/dotnet/fsharp/pull/19278)) @@ -17,6 +18,7 @@ * Fix `YieldFromFinal`/`ReturnFromFinal` being incorrectly called in non-tail positions (`for`, `use`, `use!`, `try/with` handler). ([Issue #19402](https://github.com/dotnet/fsharp/issues/19402), [PR #19403](https://github.com/dotnet/fsharp/pull/19403)) * Fixed how the source ranges of warn directives are reported (as trivia) in the parser output (by not reporting leading spaces). ([Issue #19405](https://github.com/dotnet/fsharp/issues/19405), [PR #19408]((https://github.com/dotnet/fsharp/pull/19408))) * Fix UoM value type `ToString()` returning garbage values when `--checknulls+` is enabled, caused by double address-taking in codegen. ([Issue #19435](https://github.com/dotnet/fsharp/issues/19435), [PR #19440](https://github.com/dotnet/fsharp/pull/19440)) +* Fix completion inconsistently showing some obsolete members (fields and events) while hiding others (methods and properties). All obsolete members are now consistently hidden by default. ([Issue #13512](https://github.com/dotnet/fsharp/issues/13512), [PR #19506](https://github.com/dotnet/fsharp/pull/19506)) ### Added diff --git a/eng/Build.ps1 b/eng/Build.ps1 index 40c3275596..cc93c1e68f 100644 --- a/eng/Build.ps1 +++ b/eng/Build.ps1 @@ -48,6 +48,7 @@ param ( [switch]$useGlobalNuGetCache = $true, [switch]$dontUseGlobalNuGetCache = $false, [switch]$warnAsError = $true, + [string]$warnNotAsError = "", [switch][Alias('test')]$testDesktop, [string]$testDesktopBatch = "", [switch]$testCoreClr, @@ -149,6 +150,7 @@ function Print-Usage() { Write-Host " -compressAllMetadata Build product with compressed metadata" Write-Host " -buildnorealsig Build product with realsig- (default use realsig+, where necessary)" Write-Host " -verifypackageshipstatus Verify whether the packages we are building have already shipped to nuget" + Write-Host " -warnNotAsError Suppress specific warnings from being treated as errors (semi-colon delimited)" Write-Host "" Write-Host "Command line arguments starting with '/p:' are passed through to MSBuild." } @@ -305,6 +307,8 @@ function BuildSolution([string] $solutionName, $packSolution) { $pack = if ($packSolution -eq $False) {""} else {$pack} + $msbuildWarnNotAsError = if ($warnAsError -and $warnNotAsError -ne "") { "/warnNotAsError:$warnNotAsError" } else { "" } + MSBuild $toolsetBuildProj ` $bl ` /p:Configuration=$configuration ` @@ -327,7 +331,8 @@ function BuildSolution([string] $solutionName, $packSolution) { /p:BuildNoRealsig=$buildnorealsig ` /v:$verbosity ` $suppressExtensionDeployment ` - @properties + @properties ` + $msbuildWarnNotAsError $env:BUILDING_USING_DOTNET=$BUILDING_USING_DOTNET_ORIG } diff --git a/eng/Version.Details.props b/eng/Version.Details.props index df44899c6b..6ef3746704 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -19,14 +19,14 @@ This file should be imported by eng/Versions.props 1.0.0-prerelease.26180.1 1.0.0-prerelease.26180.1 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 - 5.7.0-1.26209.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 + 5.7.0-1.26210.5 10.0.2 10.0.2 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 505ab393a4..e554d7b0e0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + https://github.com/dotnet/msbuild @@ -18,37 +18,37 @@ https://github.com/dotnet/msbuild e5ebe15655a6be2b2e3209464d0cde1b8825ab57 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 - + https://github.com/dotnet/roslyn - e3a102fb75ef112d064feebd2f9385385a445a06 + 0eca297f565449839436b91fe4aa180f9bcdedd2 diff --git a/eng/build.sh b/eng/build.sh index d0d1871241..9a0ed19d04 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -40,6 +40,7 @@ usage() echo " --fromVMR Set when building from within the VMR" echo " --buildnorealsig Build product with realsig- (default use realsig+ where necessary)" echo " --tfm Override the default target framework" + echo " --warnNotAsError Suppress specific warnings from being treated as errors (semi-colon delimited)" echo "" echo "Command line arguments starting with '/p:' are passed through to MSBuild." } @@ -80,6 +81,7 @@ product_build=false from_vmr=false buildnorealsig=true properties="" +warn_not_as_error="" docker=false args="" @@ -189,6 +191,10 @@ while [[ $# > 0 ]]; do tfm=$2 shift ;; + --warnnotaserror) + warn_not_as_error=$2 + shift + ;; /p:*) properties+=("$1") ;; @@ -328,6 +334,11 @@ function BuildSolution { # do real build BuildMessage="Error building solution" + local msbuild_warn_not_as_error="" + if [[ "$warn_not_as_error" != "" && "$warn_as_error" == true ]]; then + msbuild_warn_not_as_error="/warnNotAsError:$warn_not_as_error" + fi + MSBuild $toolset_build_proj \ $bl \ /p:Configuration=$configuration \ @@ -347,7 +358,8 @@ function BuildSolution { /p:DotNetBuild=$product_build \ /p:DotNetBuildSourceOnly=$source_build \ /p:DotNetBuildFromVMR=$from_vmr \ - ${properties[@]+"${properties[@]}"} + ${properties[@]+"${properties[@]}"} \ + $msbuild_warn_not_as_error fi } diff --git a/src/Compiler/Checking/AttributeChecking.fs b/src/Compiler/Checking/AttributeChecking.fs index ba62a69e4b..a735291472 100755 --- a/src/Compiler/Checking/AttributeChecking.fs +++ b/src/Compiler/Checking/AttributeChecking.fs @@ -639,6 +639,27 @@ let PropInfoIsUnseen _m allowObsolete pinfo = CheckProvidedAttributesForUnseen (pi.PApply((fun st -> (st :> IProvidedCustomAttributeProvider)), m)) m #endif +/// Indicate if an ILFieldInfo has 'Obsolete' attribute. +/// Used to suppress the item in intellisense. +let ILFieldInfoIsUnseen (finfo: ILFieldInfo) = + match finfo with + | ILFieldInfo(_, fdef) -> CheckILAttributesForUnseen fdef.CustomAttrs +#if !NO_TYPEPROVIDERS + | ProvidedField(_amap, fi, m) -> + CheckProvidedAttributesForUnseen (fi.PApply((fun st -> (st :> IProvidedCustomAttributeProvider)), m)) m +#endif + +/// Indicate if an EventInfo has 'Obsolete' or 'CompilerMessageAttribute'. +/// Used to suppress the item in intellisense. +let EventInfoIsUnseen allowObsolete (einfo: EventInfo) = + match einfo with + | ILEvent(ILEventInfo(_, ilEventDef)) -> CheckILAttributesForUnseen ilEventDef.CustomAttrs + | FSEvent(g, _, addValRef, _) -> CheckFSharpAttributesForUnseen g addValRef.Attribs allowObsolete +#if !NO_TYPEPROVIDERS + | ProvidedEvent(_amap, ei, m) -> + CheckProvidedAttributesForUnseen (ei.PApply((fun st -> (st :> IProvidedCustomAttributeProvider)), m)) m +#endif + /// Check the attributes on a union case, returning errors and warnings as data. let CheckUnionCaseAttributes g (x:UnionCaseRef) m = trackErrors { diff --git a/src/Compiler/Checking/AttributeChecking.fsi b/src/Compiler/Checking/AttributeChecking.fsi index c8198e4a98..564957e1bd 100644 --- a/src/Compiler/Checking/AttributeChecking.fsi +++ b/src/Compiler/Checking/AttributeChecking.fsi @@ -101,6 +101,10 @@ val MethInfoIsUnseen: g: TcGlobals -> m: range -> ty: TType -> minfo: MethInfo - val PropInfoIsUnseen: _m: 'a -> allowObsolete: bool -> pinfo: PropInfo -> bool +val ILFieldInfoIsUnseen: finfo: ILFieldInfo -> bool + +val EventInfoIsUnseen: allowObsolete: bool -> einfo: EventInfo -> bool + val CheckEntityAttributes: g: TcGlobals -> tcref: TyconRef -> m: range -> OperationResult val CheckUnionCaseAttributes: g: TcGlobals -> x: UnionCaseRef -> m: range -> OperationResult diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 635a0dff04..5a6bbf619f 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -5522,7 +5522,16 @@ and TcStmtThatCantBeCtorBody (cenv: cenv) env tpenv synExpr = and TcStmt (cenv: cenv) env tpenv synExpr = let g = cenv.g let expr, ty, tpenv = TcExprOfUnknownType cenv env tpenv synExpr - let m = synExpr.Range + + // Use the range of the last expression in a sequential chain for warnings, + // so that "expression is ignored" diagnostics point at the offending expression + // rather than the entire sequential body. See https://github.com/dotnet/fsharp/issues/5735 + let rec lastExprRange (e: SynExpr) = + match e with + | SynExpr.Sequential(expr2 = expr2) -> lastExprRange expr2 + | _ -> e.Range + + let m = lastExprRange synExpr let wasUnit = UnifyUnitType cenv env m ty expr if wasUnit then expr, tpenv diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index 55ab3c9219..07d0ea4743 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -4393,6 +4393,8 @@ let ItemIsUnseen ad g amap m allowObsolete item = isUnseenNameOfOperator || IsValUnseen ad g m allowObsolete x | Item.UnionCase(x, _) -> IsUnionCaseUnseen ad g amap m allowObsolete x.UnionCaseRef | Item.ExnCase x -> IsTyconUnseen ad g amap m allowObsolete x + | Item.ILField finfo -> not allowObsolete && ILFieldInfoIsUnseen finfo + | Item.Event einfo -> not allowObsolete && EventInfoIsUnseen allowObsolete einfo | _ -> false let ItemOfTyconRef ncenv m (x: TyconRef) = @@ -4467,7 +4469,8 @@ let ResolveCompletionsInType (ncenv: NameResolver) nenv (completionTargets: Reso ncenv.InfoReader.GetEventInfosOfType(None, ad, m, ty) |> List.filter (fun x -> IsStandardEventInfo ncenv.InfoReader m ad x && - x.IsStatic = statics) + x.IsStatic = statics && + (allowObsolete || not (EventInfoIsUnseen allowObsolete x))) else [] let nestedTypes = @@ -4482,7 +4485,8 @@ let ResolveCompletionsInType (ncenv: NameResolver) nenv (completionTargets: Reso |> List.filter (fun x -> not x.IsSpecialName && x.IsStatic = statics && - IsILFieldInfoAccessible g amap m ad x) + IsILFieldInfoAccessible g amap m ad x && + (allowObsolete || not (ILFieldInfoIsUnseen x))) let qinfos = ncenv.InfoReader.GetTraitInfosInType None ty diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs index 36e258e4dd..7310f83dbd 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs @@ -50,6 +50,43 @@ type Vehicle() = class end [ (Error 39, Line 3, Col 14, Line 3, Col 28, "The type 'OutOfScopeType' is not defined.") (Error 267, Line 3, Col 7, Line 3, Col 29, "This is not a valid constant expression or custom attribute value") ] +// https://github.com/dotnet/fsharp/issues/10043 +[] +let ``Issue 10043 - backtick in type annotation should not report unexpected keyword`` () = + FSharp + """ +let i:float`1 = 3.0 + """ + |> typecheck + |> shouldFail + |> withDiagnostics + [ (Error 3563, Line 2, Col 12, Line 2, Col 13, "This is not a valid identifier") + (Error 10, Line 2, Col 13, Line 2, Col 14, "Unexpected integer literal in binding. Expected '=' or other token.") ] + +// https://github.com/dotnet/fsharp/issues/10043 +[] +let ``Issue 10043 - at sign in type annotation should report infix operator`` () = + FSharp + """ +let i:float@1 = 3.0 + """ + |> typecheck + |> shouldFail + |> withDiagnostics + [ (Error 615, Line 2, Col 12, Line 2, Col 13, "Unexpected infix operator in type expression") ] + +// https://github.com/dotnet/fsharp/issues/10043 +[] +let ``Issue 10043 - bang in type annotation should report reserved identifier`` () = + FSharp + """ +let i:float!1 = 3.0 + """ + |> typecheck + |> shouldFail + |> withDiagnostics + [ (Error 1141, Line 2, Col 7, Line 2, Col 13, "Identifiers followed by '!' are reserved for future use") + (Error 10, Line 2, Col 13, Line 2, Col 14, "Unexpected integer literal in binding. Expected '=' or other token.") ] // https://github.com/dotnet/fsharp/issues/7177 [] diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs index 942ab64dfc..b5cf1bcbcc 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs @@ -176,6 +176,63 @@ while x < 1 do |> withSingleDiagnostic (Warning 20, Line 6, Col 5, Line 6, Col 9, "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + // https://github.com/dotnet/fsharp/issues/5735 + [] + let ``Warn On Last Expression In For Loop - int``() = + FSharp """ +module ClassLibrary17 + +for i in 1 .. 10 do + printfn "" + printfn "" |> ignore + 123 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 20, Line 7, Col 5, Line 7, Col 8, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + + // https://github.com/dotnet/fsharp/issues/5735 + [] + let ``Warn On Last Expression In For Loop - string``() = + FSharp """ +for i in 1 .. 10 do + printfn "" + "hello" + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 20, Line 4, Col 5, Line 4, Col 12, + "The result of this expression has type 'string' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + + // https://github.com/dotnet/fsharp/issues/5735 + [] + let ``Warn On Last Expression In Integer For Loop``() = + FSharp """ +for i = 1 to 10 do + printfn "" + 42 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 20, Line 4, Col 5, Line 4, Col 7, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + + // https://github.com/dotnet/fsharp/issues/5735 + [] + let ``Warn On Last Expression In While Loop - non-bool``() = + FSharp """ +let mutable x = 0 +while x < 1 do + printfn "unneeded" + x <- x + 1 + 123 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 20, Line 6, Col 5, Line 6, Col 8, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + [] let ``Warn If Possible Property Setter``() = FSharp """ diff --git a/tests/FSharp.Compiler.Service.Tests/Checker.fs b/tests/FSharp.Compiler.Service.Tests/Checker.fs index 5d16f87783..22dcf2ad50 100644 --- a/tests/FSharp.Compiler.Service.Tests/Checker.fs +++ b/tests/FSharp.Compiler.Service.Tests/Checker.fs @@ -162,6 +162,11 @@ module Checker = let parseResults, checkResults = getParseAndCheckResults context.Source checkResults.GetCodeCompletionSuggestions(context, parseResults, options) + let getCompletionInfoWithCompilerAndCompletionOptions (compilerOptions: string array) (completionOptions: FSharpCodeCompletionOptions) (markedSource: string) = + let context = getCompletionContext markedSource + let parseResults, checkResults = getParseAndCheckResultsWithOptions compilerOptions context.Source + checkResults.GetCodeCompletionSuggestions(context, parseResults, completionOptions) + let getCompletionInfo markedSource = getCompletionInfoWithOptions FSharpCodeCompletionOptions.Default markedSource diff --git a/tests/FSharp.Compiler.Service.Tests/CompletionTests.fs b/tests/FSharp.Compiler.Service.Tests/CompletionTests.fs index 43ee08b4ee..e229a6f2b3 100644 --- a/tests/FSharp.Compiler.Service.Tests/CompletionTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/CompletionTests.fs @@ -691,6 +691,86 @@ exception E try () with E{caret} """ + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``Event - Instance 01`` () = + assertItem "Ev" """ +type T() = + [] + member _.Ev = Event().Publish + +T().{caret} +""" + + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``Event - Static 01`` () = + assertItem "Ev" """ +type T() = + [] + static member Ev = Event().Publish + +T.{caret} +""" + + /// Helper to assert completion with a reference to the CSharp_Analysis assembly + let private assertCSharpInteropItem name source = + let csharpAssembly = PathRelativeToTestAssembly "CSharp_Analysis.dll" + let compilerOptions = [| $"-r:{csharpAssembly}" |] + [allowObsoleteOptions; disallowObsoleteOptions] + |> List.iter (fun completionOptions -> + let contains = completionOptions.SuggestObsoleteSymbols + let info = Checker.getCompletionInfoWithCompilerAndCompletionOptions compilerOptions completionOptions source + assertItemsWithNames contains [name] info + ) + + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``CSharp - Obsolete field is hidden`` () = + assertCSharpInteropItem "ObsoleteField" """ +open FSharp.Compiler.Service.Tests +ObsoleteMembersClass.{caret} +""" + + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``CSharp - Obsolete method is hidden`` () = + assertCSharpInteropItem "ObsoleteMethod" """ +open FSharp.Compiler.Service.Tests +ObsoleteMembersClass.{caret} +""" + + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``CSharp - Obsolete property is hidden`` () = + assertCSharpInteropItem "ObsoleteProperty" """ +open FSharp.Compiler.Service.Tests +ObsoleteMembersClass.{caret} +""" + + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``CSharp - Obsolete event is hidden`` () = + assertCSharpInteropItem "ObsoleteEvent" """ +open FSharp.Compiler.Service.Tests +ObsoleteMembersClass.{caret} +""" + + // https://github.com/dotnet/fsharp/issues/13512 + [] + let ``CSharp - Non-obsolete members are always shown`` () = + let csharpAssembly = PathRelativeToTestAssembly "CSharp_Analysis.dll" + let compilerOptions = [| $"-r:{csharpAssembly}" |] + let source = """ +open FSharp.Compiler.Service.Tests +ObsoleteMembersClass.{caret} +""" + [allowObsoleteOptions; disallowObsoleteOptions] + |> List.iter (fun completionOptions -> + let info = Checker.getCompletionInfoWithCompilerAndCompletionOptions compilerOptions completionOptions source + assertItemsWithNames true ["NonObsoleteField"; "NonObsoleteMethod"; "NonObsoleteProperty"; "NonObsoleteEvent"] info + ) + module PatternNameSuggestions = let private suggestPatternNames = { FSharpCodeCompletionOptions.Default with SuggestPatternNames = true } diff --git a/tests/service/data/CSharp_Analysis/CSharpClass.cs b/tests/service/data/CSharp_Analysis/CSharpClass.cs index a8131651b5..e8afc869dc 100644 --- a/tests/service/data/CSharp_Analysis/CSharpClass.cs +++ b/tests/service/data/CSharp_Analysis/CSharpClass.cs @@ -155,4 +155,25 @@ public class DummyClass { } } + + /// + /// Class with obsolete members for testing completion filtering (issue #13512). + /// + public class ObsoleteMembersClass + { + [Obsolete("Field is obsolete")] public static readonly int ObsoleteField = 1; + + [Obsolete("Method is obsolete")] + public static void ObsoleteMethod() + { + } + + [Obsolete("Property is obsolete")] public static int ObsoleteProperty => 1; + [Obsolete("Event is obsolete")] public static event EventHandler ObsoleteEvent; + + public static readonly int NonObsoleteField = 2; + public static void NonObsoleteMethod() { } + public static int NonObsoleteProperty => 2; + public static event EventHandler NonObsoleteEvent; + } }