Skip to content

Commit 06c85f0

Browse files
authored
Obsolete attribute was ignored in constructor property assignment. (#16900)
* Raise an warning when Obsolete attribute is used in constructor property assignment.
1 parent b912eb8 commit 06c85f0

File tree

3 files changed

+186
-1
lines changed

3 files changed

+186
-1
lines changed

docs/release-notes/.FSharp.Compiler.Service/8.0.300.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
* Enforce AttributeTargets on enums ([PR #16887](https://github.com/dotnet/fsharp/pull/16887))
2828
* Completion: fix for unfinished record field decl ([PR #16893](https://github.com/dotnet/fsharp/pull/16893))
2929
* Enforce AttributeTargets on delegates ([PR #16891](https://github.com/dotnet/fsharp/pull/16891))
30+
* Obsolete attribute is ignored in constructor property assignment ([PR #16900](https://github.com/dotnet/fsharp/pull/16900))
3031
* Completion: fix completion in empty dot lambda prefix ([#16829](https://github.com/dotnet/fsharp/pull/16829))
3132
* Fix StackOverflow when checking non-recursive bindings in module or namespace in `fscAnyCpu`/`fsiAnyCpu`. ([PR #16908](https://github.com/dotnet/fsharp/pull/16908))
3233

src/Compiler/Checking/CheckExpressions.fs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10086,7 +10086,6 @@ and TcMethodApplication
1008610086
// Handle post-hoc property assignments
1008710087
let setterExprPrebinders, callExpr2b =
1008810088
let expr = callExpr2
10089-
1009010089
CheckRequiredProperties g env cenv finalCalledMethInfo finalAssignedItemSetters mMethExpr
1009110090

1009210091
if isCheckingAttributeCall then
@@ -10161,6 +10160,8 @@ and TcSetterArgExpr (cenv: cenv) env denv objExpr ad assignedSetter calledFromCo
1016110160
match setter with
1016210161
| AssignedPropSetter (propStaticTyOpt, pinfo, pminfo, pminst) ->
1016310162

10163+
CheckPropInfoAttributes pinfo id.idRange |> CommitOperationResult
10164+
1016410165
if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && pinfo.IsSetterInitOnly && not calledFromConstructor then
1016510166
errorR (Error (FSComp.SR.tcInitOnlyPropertyCannotBeSet1 pinfo.PropertyName, m))
1016610167

tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs

+183
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace Language
22

3+
open FSharp.Test
34
open Xunit
45
open FSharp.Test.Compiler
56

@@ -1262,3 +1263,185 @@ let f (x: IFirst) = x.F()
12621263
(Error 101, Line 13, Col 11, Line 13, Col 17, "This construct is deprecated. Use G instead")
12631264
(Error 72, Line 13, Col 21, Line 13, Col 24, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.")
12641265
]
1266+
1267+
[<Fact>]
1268+
let ``Obsolete attribute warning is taken into account in a constructor property assignment`` () =
1269+
Fsx """
1270+
open System
1271+
type JsonSerializerOptions() =
1272+
[<Obsolete("This is bad")>]
1273+
member val DefaultOptions = false with get, set
1274+
1275+
member val UseCustomOptions = false with get, set
1276+
1277+
let options = JsonSerializerOptions(DefaultOptions = true, UseCustomOptions = false)
1278+
let options2 = JsonSerializerOptions(DefaultOptions = true, DefaultOptions = false)
1279+
"""
1280+
|> typecheck
1281+
|> shouldFail
1282+
|> withDiagnostics [
1283+
(Warning 44, Line 9, Col 37, Line 9, Col 51, "This construct is deprecated. This is bad")
1284+
(Error 364, Line 10, Col 16, Line 10, Col 84, "The named argument 'DefaultOptions' has been assigned more than one value")
1285+
(Warning 44, Line 10, Col 38, Line 10, Col 52, "This construct is deprecated. This is bad")
1286+
(Warning 44, Line 10, Col 61, Line 10, Col 75, "This construct is deprecated. This is bad")
1287+
]
1288+
1289+
[<Fact>]
1290+
let ``Obsolete attribute warning is not taken into account in prop setters that can be included in methods which are not constructors`` () =
1291+
Fsx """
1292+
open System
1293+
1294+
type JsonSerializerOptions() =
1295+
[<Obsolete("This is bad")>]
1296+
member val DefaultOptions = false with get, set
1297+
member val UseCustomOptions = false with get, set
1298+
member this.With() = this
1299+
1300+
let options = JsonSerializerOptions()
1301+
let options2 =
1302+
options
1303+
.With(DefaultOptions = true)
1304+
.With(UseCustomOptions = false)
1305+
"""
1306+
|> typecheck
1307+
|> withDiagnostics [
1308+
(Warning 44, Line 13, Col 15, Line 13, Col 29, "This construct is deprecated. This is bad")
1309+
]
1310+
1311+
[<Fact>]
1312+
let ``Obsolete attribute error is not taken into account in prop setters that can be included in methods which are not constructors`` () =
1313+
Fsx """
1314+
open System
1315+
1316+
type JsonSerializerOptions() =
1317+
[<Obsolete("This is bad", true)>]
1318+
member val DefaultOptions = false with get, set
1319+
member val UseCustomOptions = false with get, set
1320+
member this.With() = this
1321+
1322+
let options = JsonSerializerOptions()
1323+
let options2 =
1324+
options
1325+
.With(DefaultOptions = true)
1326+
.With(UseCustomOptions = false)
1327+
"""
1328+
|> typecheck
1329+
|> shouldFail
1330+
|> withDiagnostics [
1331+
(Error 101, Line 13, Col 15, Line 13, Col 29, "This construct is deprecated. This is bad")
1332+
]
1333+
1334+
[<Fact>]
1335+
let ``Obsolete attribute error is taken into account in a constructor property assignment`` () =
1336+
Fsx """
1337+
open System
1338+
type JsonSerializerOptions() =
1339+
[<Obsolete("This is bad", true)>]
1340+
member val DefaultOptions = false with get, set
1341+
1342+
member val UseCustomOptions = false with get, set
1343+
1344+
let options = JsonSerializerOptions(DefaultOptions = true, UseCustomOptions = false)
1345+
let options2 = JsonSerializerOptions(DefaultOptions = true, DefaultOptions = false)
1346+
"""
1347+
|> typecheck
1348+
|> shouldFail
1349+
|> withDiagnostics [
1350+
(Error 101, Line 9, Col 37, Line 9, Col 51, "This construct is deprecated. This is bad");
1351+
(Error 364, Line 10, Col 16, Line 10, Col 84, "The named argument 'DefaultOptions' has been assigned more than one value");
1352+
(Error 101, Line 10, Col 38, Line 10, Col 52, "This construct is deprecated. This is bad")
1353+
]
1354+
1355+
[<Fact>]
1356+
let ``Obsolete attribute warning is taken into account in a nested constructor property assignment`` () =
1357+
Fsx """
1358+
open System
1359+
type JsonSerializer1Options() =
1360+
[<Obsolete("This is bad")>]
1361+
member val DefaultOptions = false with get, set
1362+
1363+
member val UseCustomOptions = false with get, set
1364+
1365+
type JsonSerializerOptions() =
1366+
member val DefaultOptions = JsonSerializer1Options() with get, set
1367+
1368+
member val UseCustomOptions = false with get, set
1369+
1370+
let options = JsonSerializerOptions(DefaultOptions = JsonSerializer1Options(DefaultOptions = true), UseCustomOptions = false)
1371+
"""
1372+
|> typecheck
1373+
|> shouldFail
1374+
|> withDiagnostics [
1375+
(Warning 44, Line 14, Col 77, Line 14, Col 91, "This construct is deprecated. This is bad")
1376+
]
1377+
1378+
[<Fact>]
1379+
let ``Obsolete attribute error is taken into account in a nested constructor property assignment`` () =
1380+
Fsx """
1381+
open System
1382+
type JsonSerializer1Options() =
1383+
[<Obsolete("This is bad", true)>]
1384+
member val DefaultOptions = false with get, set
1385+
1386+
member val UseCustomOptions = false with get, set
1387+
1388+
type JsonSerializerOptions() =
1389+
member val DefaultOptions = JsonSerializer1Options() with get, set
1390+
1391+
member val UseCustomOptions = false with get, set
1392+
1393+
let options = JsonSerializerOptions(DefaultOptions = JsonSerializer1Options(DefaultOptions = true), UseCustomOptions = false)
1394+
"""
1395+
|> typecheck
1396+
|> shouldFail
1397+
|> withDiagnostics [
1398+
(Error 101, Line 14, Col 77, Line 14, Col 91, "This construct is deprecated. This is bad")
1399+
]
1400+
1401+
[<Fact>]
1402+
let ``Obsolete attribute warning is taken into account in a constructor property assignment from a csharp class`` () =
1403+
let CSLib =
1404+
CSharp """
1405+
using System;
1406+
public class JsonProtocolTestData {
1407+
[Obsolete("Use Json instead")]
1408+
public bool IgnoreNullValues { get; set; }
1409+
}
1410+
""" |> withName "CSLib"
1411+
1412+
let app =
1413+
FSharp """
1414+
module ObsoleteStruct.FS
1415+
let res = JsonProtocolTestData(IgnoreNullValues = false)
1416+
""" |> withReferences [CSLib]
1417+
1418+
app
1419+
|> compile
1420+
|> shouldFail
1421+
|> withDiagnostics [
1422+
(Warning 44, Line 3, Col 32, Line 3, Col 48, "This construct is deprecated. Use Json instead")
1423+
]
1424+
1425+
[<Fact>]
1426+
let ``Obsolete attribute error is taken into account in a constructor property assignment from a csharp class`` () =
1427+
let CSLib =
1428+
CSharp """
1429+
using System;
1430+
public class JsonProtocolTestData {
1431+
[Obsolete("Use Json instead", true)]
1432+
public bool IgnoreNullValues { get; set; }
1433+
}
1434+
""" |> withName "CSLib"
1435+
1436+
let app =
1437+
FSharp """
1438+
module ObsoleteStruct.FS
1439+
let res = JsonProtocolTestData(IgnoreNullValues = false)
1440+
""" |> withReferences [CSLib]
1441+
1442+
app
1443+
|> compile
1444+
|> shouldFail
1445+
|> withDiagnostics [
1446+
(Error 101, Line 3, Col 32, Line 3, Col 48, "This construct is deprecated. Use Json instead")
1447+
]

0 commit comments

Comments
 (0)