Skip to content

Commit ef436ad

Browse files
committed
CheckILObsoleteAttributes
1 parent 3d0241c commit ef436ad

File tree

4 files changed

+210
-13
lines changed

4 files changed

+210
-13
lines changed

src/Compiler/Checking/AttributeChecking.fs

+28-12
Original file line numberDiff line numberDiff line change
@@ -249,28 +249,44 @@ let private CheckCompilerFeatureRequiredAttribute (g: TcGlobals) cattrs msg m =
249249
| _ ->
250250
ErrorD (ObsoleteDiagnostic(true, "", msg, "", m))
251251

252-
/// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data
253-
let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
252+
let private CheckILObsoleteAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
253+
let extractILAttribValueFrom name namedArgs =
254+
match namedArgs with
255+
| ExtractILAttributeNamedArg name (AttribElemStringArg v) -> v
256+
| _ -> ""
254257
let (AttribInfo(tref,_)) = g.attrib_SystemObsolete
255258
match TryDecodeILAttribute tref cattrs with
256-
| Some ([ILAttribElem.String (Some msg) ], _) when not isByrefLikeTyconRef ->
257-
WarnD(ObsoleteDiagnostic(false, "", msg, "", m))
258-
| Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], _) when not isByrefLikeTyconRef ->
259+
| Some ([ILAttribElem.String (Some msg) ], namedArgs) when not isByrefLikeTyconRef ->
260+
let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs
261+
let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs
262+
WarnD(ObsoleteDiagnostic(false, diagnosticId, msg, urlFormat, m))
263+
| Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], namedArgs) when not isByrefLikeTyconRef ->
264+
let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs
265+
let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs
259266
if isError then
260267
if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) then
261268
CheckCompilerFeatureRequiredAttribute g cattrs msg m
262269
else
263-
ErrorD (ObsoleteDiagnostic(true, "", msg, "", m))
270+
ErrorD (ObsoleteDiagnostic(true, diagnosticId, msg, urlFormat, m))
264271
else
265-
WarnD (ObsoleteDiagnostic(false, "", msg, "", m))
266-
267-
| Some ([ILAttribElem.String None ], _) when not isByrefLikeTyconRef ->
268-
WarnD(ObsoleteDiagnostic(false, "", "", "", m))
269-
| Some _ when not isByrefLikeTyconRef ->
270-
WarnD(ObsoleteDiagnostic(false, "", "", "", m))
272+
WarnD (ObsoleteDiagnostic(false, diagnosticId, msg, urlFormat, m))
273+
274+
| Some ([ILAttribElem.String None ], namedArgs) when not isByrefLikeTyconRef ->
275+
let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs
276+
let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs
277+
WarnD(ObsoleteDiagnostic(false, diagnosticId, "", urlFormat, m))
278+
| Some (_, namedArgs) when not isByrefLikeTyconRef ->
279+
let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs
280+
let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs
281+
WarnD(ObsoleteDiagnostic(false, diagnosticId, "", urlFormat, m))
271282
| _ ->
272283
CompleteD
273284

285+
/// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data
286+
let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
287+
trackErrors {
288+
do! CheckILObsoleteAttributes g isByrefLikeTyconRef cattrs m
289+
}
274290
let langVersionPrefix = "--langversion:preview"
275291

276292
let private CheckObsoleteAttributes g attribs m =

src/Compiler/TypedTree/TypedTreeOps.fs

+6
Original file line numberDiff line numberDiff line change
@@ -3524,6 +3524,10 @@ let IsMatchingFSharpAttributeOpt g attrOpt (Attrib(tcref2, _, _, _, _, _, _)) =
35243524
[<return: Struct>]
35253525
let (|ExtractAttribNamedArg|_|) nm args =
35263526
args |> List.tryPick (function AttribNamedArg(nm2, _, _, v) when nm = nm2 -> Some v | _ -> None) |> ValueOptionInternal.ofOption
3527+
3528+
[<return: Struct>]
3529+
let (|ExtractILAttributeNamedArg|_|) nm (args: ILAttributeNamedArg list) =
3530+
args |> List.tryPick (function nm2, _, _, v when nm = nm2 -> Some v | _ -> None) |> ValueOptionInternal.ofOption
35273531

35283532
[<return: Struct>]
35293533
let (|StringExpr|_|) = function Expr.Const (Const.String n, _, _) -> ValueSome n | _ -> ValueNone
@@ -3540,6 +3544,8 @@ let (|AttribBoolArg|_|) = function AttribExpr(_, Expr.Const (Const.Bool n, _, _)
35403544
[<return: Struct>]
35413545
let (|AttribStringArg|_|) = function AttribExpr(_, Expr.Const (Const.String n, _, _)) -> ValueSome n | _ -> ValueNone
35423546

3547+
let (|AttribElemStringArg|_|) = function ILAttribElem.String(n) -> n | _ -> None
3548+
35433549
let TryFindFSharpBoolAttributeWithDefault dflt g nm attrs =
35443550
match TryFindFSharpAttribute g nm attrs with
35453551
| Some(Attrib(_, _, [ ], _, _, _, _)) -> Some dflt

src/Compiler/TypedTree/TypedTreeOps.fsi

+5
Original file line numberDiff line numberDiff line change
@@ -2598,6 +2598,9 @@ val (|ConstToILFieldInit|_|): Const -> ILFieldInit voption
25982598
[<return: Struct>]
25992599
val (|ExtractAttribNamedArg|_|): string -> AttribNamedArg list -> AttribExpr voption
26002600

2601+
[<return: Struct>]
2602+
val (|ExtractILAttributeNamedArg|_|): string -> ILAttributeNamedArg list -> ILAttribElem voption
2603+
26012604
[<return: Struct>]
26022605
val (|AttribInt32Arg|_|): (AttribExpr -> int32 voption)
26032606

@@ -2610,6 +2613,8 @@ val (|AttribBoolArg|_|): (AttribExpr -> bool voption)
26102613
[<return: Struct>]
26112614
val (|AttribStringArg|_|): (AttribExpr -> string voption)
26122615

2616+
val (|AttribElemStringArg|_|): (ILAttribElem -> string option)
2617+
26132618
[<return: Struct>]
26142619
val (|Int32Expr|_|): Expr -> int32 voption
26152620

tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs

+171-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ let x = MyClass()
258258
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
259259
Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId)
260260
Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat))
261-
261+
262262
[<Fact>]
263263
let ``Warning - ObsoleteDiagnosticExtendedData 02`` () =
264264
FSharp """
@@ -307,6 +307,176 @@ let x = MyClass()
307307
Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId)
308308
Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat))
309309

310+
311+
[<Fact>]
312+
let ``Warning - ObsoleteDiagnosticExtendedData 05`` () =
313+
let CSLib =
314+
CSharp """
315+
using System;
316+
[Obsolete("Use something else", false, DiagnosticId = "FS222")]
317+
public static class Class1
318+
{
319+
public static string Test()
320+
{
321+
return "Hello";
322+
}
323+
}
324+
"""
325+
|> withName "CSLib"
326+
327+
let app =
328+
FSharp """
329+
open MyLib
330+
331+
let text = Class1.Test();
332+
""" |> withReferences [CSLib]
333+
334+
app
335+
|> typecheckResults
336+
|> checkDiagnostic
337+
(44, "This construct is deprecated. Use something else")
338+
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
339+
Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId)
340+
Assert.Equal("", obsoleteDiagnostic.UrlFormat))
341+
342+
[<Fact>]
343+
let ``Warning - ObsoleteDiagnosticExtendedData 06`` () =
344+
let CSLib =
345+
CSharp """
346+
using System;
347+
[Obsolete("Use something else", false, DiagnosticId = "FS222", UrlFormat = "https://example.com")]
348+
public static class Class1
349+
{
350+
public static string Test()
351+
{
352+
return "Hello";
353+
}
354+
}
355+
"""
356+
|> withName "CSLib"
357+
358+
let app =
359+
FSharp """
360+
open MyLib
361+
362+
let text = Class1.Test();
363+
""" |> withReferences [CSLib]
364+
365+
app
366+
|> typecheckResults
367+
|> checkDiagnostic
368+
(44, "This construct is deprecated. Use something else")
369+
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
370+
Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId)
371+
Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat))
372+
373+
[<Fact>]
374+
let ``Warning - ObsoleteDiagnosticExtendedData 07`` () =
375+
let CSLib =
376+
CSharp """
377+
using System;
378+
[Obsolete("Use something else", false)]
379+
public static class Class1
380+
{
381+
public static string Test()
382+
{
383+
return "Hello";
384+
}
385+
}
386+
"""
387+
|> withName "CSLib"
388+
389+
let app =
390+
FSharp """
391+
open MyLib
392+
393+
let text = Class1.Test();
394+
""" |> withReferences [CSLib]
395+
396+
app
397+
|> typecheckResults
398+
|> checkDiagnostic
399+
(44, "This construct is deprecated. Use something else")
400+
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
401+
Assert.Equal("", obsoleteDiagnostic.DiagnosticId)
402+
Assert.Equal("", obsoleteDiagnostic.UrlFormat))
403+
404+
[<Fact>]
405+
let ``Warning - ObsoleteDiagnosticExtendedData 08`` () =
406+
let CSLib =
407+
CSharp """
408+
using System;
409+
[Obsolete(DiagnosticId = "FS222", UrlFormat = "https://example.com")]
410+
public static class Class1
411+
{
412+
public static string Test()
413+
{
414+
return "Hello";
415+
}
416+
}
417+
"""
418+
|> withName "CSLib"
419+
420+
let app =
421+
FSharp """
422+
open MyLib
423+
424+
let text = Class1.Test();
425+
""" |> withReferences [CSLib]
426+
427+
app
428+
|> typecheckResults
429+
|> checkDiagnostic
430+
(44, "This construct is deprecated")
431+
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
432+
Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId)
433+
Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat))
434+
435+
[<Fact>]
436+
let ``Warning - ObsoleteDiagnosticExtendedData 09`` () =
437+
FSharp """
438+
open System
439+
[<Obsolete>]
440+
type MyClass() = class end
441+
442+
let x = MyClass()
443+
"""
444+
|> typecheckResults
445+
|> checkDiagnostic
446+
(44, "This construct is deprecated")
447+
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
448+
Assert.Equal("", obsoleteDiagnostic.DiagnosticId)
449+
Assert.Equal("", obsoleteDiagnostic.UrlFormat))
450+
451+
let ``Warning - ObsoleteDiagnosticExtendedData 10`` () =
452+
let CSLib =
453+
CSharp """
454+
using System;
455+
[Obsolete]
456+
public static class Class1
457+
{
458+
public static string Test()
459+
{
460+
return "Hello";
461+
}
462+
}
463+
"""
464+
|> withName "CSLib"
465+
466+
let app =
467+
FSharp """
468+
open MyLib
469+
470+
let text = Class1.Test();
471+
""" |> withReferences [CSLib]
472+
473+
app
474+
|> typecheckResults
475+
|> checkDiagnostic
476+
(44, "This construct is deprecated")
477+
(fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) ->
478+
Assert.Equal("", obsoleteDiagnostic.DiagnosticId)
479+
Assert.Equal("", obsoleteDiagnostic.UrlFormat))
310480

311481
[<Fact>]
312482
let ``Error - ObsoleteDiagnosticExtendedData 01`` () =

0 commit comments

Comments
 (0)