@@ -24,8 +24,12 @@ open FSharp.Compiler.TypeProviders
24
24
open FSharp.Core .CompilerServices
25
25
#endif
26
26
27
- exception ObsoleteWarning of string * range
28
- exception ObsoleteError of string * range
27
+ exception ObsoleteDiagnostic of
28
+ isError: bool *
29
+ diagnosticId: string *
30
+ message: string *
31
+ urlFormat: string *
32
+ range: range
29
33
30
34
let fail () = failwith " This custom attribute has an argument that cannot yet be converted using this API"
31
35
@@ -234,7 +238,6 @@ let MethInfoHasAttribute g m attribSpec minfo =
234
238
( fun _ -> Some ())
235
239
|> Option.isSome
236
240
237
-
238
241
let private CheckCompilerFeatureRequiredAttribute ( g : TcGlobals ) cattrs msg m =
239
242
// In some cases C# will generate both ObsoleteAttribute and CompilerFeatureRequiredAttribute.
240
243
// Specifically, when default constructor is generated for class with any required members in them.
@@ -244,104 +247,177 @@ let private CheckCompilerFeatureRequiredAttribute (g: TcGlobals) cattrs msg m =
244
247
| Some([ ILAttribElem.String ( Some featureName) ], _) when featureName = " RequiredMembers" ->
245
248
CompleteD
246
249
| _ ->
247
- ErrorD ( ObsoleteError( msg, m))
250
+ ErrorD ( ObsoleteDiagnostic( true , " " , msg, " " , m))
251
+
252
+ let private extractILObsoleteAttributeInfo namedArgs =
253
+ let extractILAttribValueFrom name namedArgs =
254
+ match namedArgs with
255
+ | ExtractILAttributeNamedArg name ( AttribElemStringArg v) -> v
256
+ | _ -> " "
257
+ let diagnosticId = extractILAttribValueFrom " DiagnosticId" namedArgs
258
+ let urlFormat = extractILAttribValueFrom " UrlFormat" namedArgs
259
+ ( diagnosticId, urlFormat)
260
+
261
+ let private CheckILObsoleteAttributes ( g : TcGlobals ) isByrefLikeTyconRef cattrs m =
262
+ if isByrefLikeTyconRef then
263
+ CompleteD
264
+ else
265
+ let ( AttribInfo ( tref , _ )) = g.attrib_ SystemObsolete
266
+ match TryDecodeILAttribute tref cattrs with
267
+ // [<Obsolete>]
268
+ // [<Obsolete("Message")>]
269
+ // [<Obsolete("Message", true)>]
270
+ // [<Obsolete("Message", DiagnosticId = "DiagnosticId")>]
271
+ // [<Obsolete("Message", DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
272
+ // [<Obsolete(DiagnosticId = "DiagnosticId")>]
273
+ // [<Obsolete(DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
274
+ // [<Obsolete("Message", true, DiagnosticId = "DiagnosticId")>]
275
+ // [<Obsolete("Message", true, DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
276
+ // Constructors deciding on IsError and Message properties.
277
+ | Some ([ attribElement ], namedArgs) ->
278
+ let diagnosticId , urlFormat = extractILObsoleteAttributeInfo namedArgs
279
+ let msg =
280
+ match attribElement with
281
+ | ILAttribElem.String ( Some msg) -> msg
282
+ | ILAttribElem.String None
283
+ | _ -> " "
284
+
285
+ WarnD ( ObsoleteDiagnostic( false , diagnosticId, msg, urlFormat, m))
286
+ | Some ([ ILAttribElem.String ( Some msg); ILAttribElem.Bool isError ], namedArgs) ->
287
+ let diagnosticId , urlFormat = extractILObsoleteAttributeInfo namedArgs
288
+ if isError then
289
+ if g.langVersion.SupportsFeature( LanguageFeature.RequiredPropertiesSupport) then
290
+ CheckCompilerFeatureRequiredAttribute g cattrs msg m
291
+ else
292
+ ErrorD ( ObsoleteDiagnostic( true , diagnosticId, msg, urlFormat, m))
293
+ else
294
+ WarnD ( ObsoleteDiagnostic( false , diagnosticId, msg, urlFormat, m))
295
+ // Only DiagnosticId, UrlFormat
296
+ | Some (_, namedArgs) ->
297
+ let diagnosticId , urlFormat = extractILObsoleteAttributeInfo namedArgs
298
+ WarnD( ObsoleteDiagnostic( false , diagnosticId, " " , urlFormat, m))
299
+ // No arguments
300
+ | None -> CompleteD
248
301
249
302
/// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data
250
303
let private CheckILAttributes ( g : TcGlobals ) isByrefLikeTyconRef cattrs m =
251
- let ( AttribInfo ( tref , _ )) = g.attrib_ SystemObsolete
252
- match TryDecodeILAttribute tref cattrs with
253
- | Some ([ ILAttribElem.String ( Some msg) ], _) when not isByrefLikeTyconRef ->
254
- WarnD( ObsoleteWarning( msg, m))
255
- | Some ([ ILAttribElem.String ( Some msg); ILAttribElem.Bool isError ], _) when not isByrefLikeTyconRef ->
256
- if isError then
257
- if g.langVersion.SupportsFeature( LanguageFeature.RequiredPropertiesSupport) then
258
- CheckCompilerFeatureRequiredAttribute g cattrs msg m
259
- else
260
- ErrorD ( ObsoleteError( msg, m))
261
- else
262
- WarnD ( ObsoleteWarning( msg, m))
263
- | Some ([ ILAttribElem.String None ], _) when not isByrefLikeTyconRef ->
264
- WarnD( ObsoleteWarning( " " , m))
265
- | Some _ when not isByrefLikeTyconRef ->
266
- WarnD( ObsoleteWarning( " " , m))
267
- | _ ->
268
- CompleteD
304
+ trackErrors {
305
+ do ! CheckILObsoleteAttributes g isByrefLikeTyconRef cattrs m
306
+ }
269
307
270
308
let langVersionPrefix = " --langversion:preview"
271
309
310
+ let private extractObsoleteAttributeInfo namedArgs =
311
+ let extractILAttribValueFrom name namedArgs =
312
+ match namedArgs with
313
+ | ExtractAttribNamedArg name ( AttribStringArg v) -> v
314
+ | _ -> " "
315
+ let diagnosticId = extractILAttribValueFrom " DiagnosticId" namedArgs
316
+ let urlFormat = extractILAttribValueFrom " UrlFormat" namedArgs
317
+ ( diagnosticId, urlFormat)
318
+
319
+ let private CheckObsoleteAttributes g attribs m =
320
+ trackErrors {
321
+ match TryFindFSharpAttribute g g.attrib_ SystemObsolete attribs with
322
+ // [<Obsolete>]
323
+ // [<Obsolete("Message")>]
324
+ // [<Obsolete("Message", true)>]
325
+ // [<Obsolete("Message", DiagnosticId = "DiagnosticId")>]
326
+ // [<Obsolete("Message", DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
327
+ // [<Obsolete(DiagnosticId = "DiagnosticId")>]
328
+ // [<Obsolete(DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
329
+ // [<Obsolete("Message", true, DiagnosticId = "DiagnosticId")>]
330
+ // [<Obsolete("Message", true, DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
331
+ // Constructors deciding on IsError and Message properties.
332
+ | Some( Attrib( unnamedArgs= [ AttribStringArg s ]; propVal= namedArgs)) ->
333
+ let diagnosticId , urlFormat = extractObsoleteAttributeInfo namedArgs
334
+ do ! WarnD( ObsoleteDiagnostic( false , diagnosticId, s, urlFormat, m))
335
+ | Some( Attrib( unnamedArgs= [ AttribStringArg s; AttribBoolArg( isError) ]; propVal= namedArgs)) ->
336
+ let diagnosticId , urlFormat = extractObsoleteAttributeInfo namedArgs
337
+ if isError then
338
+ do ! ErrorD ( ObsoleteDiagnostic( true , diagnosticId, s, urlFormat, m))
339
+ else
340
+ do ! WarnD ( ObsoleteDiagnostic( false , diagnosticId, s, urlFormat, m))
341
+ // Only DiagnosticId, UrlFormat
342
+ | Some( Attrib( propVal= namedArgs)) ->
343
+ let diagnosticId , urlFormat = extractObsoleteAttributeInfo namedArgs
344
+ do ! WarnD( ObsoleteDiagnostic( false , diagnosticId, " " , urlFormat, m))
345
+ | None -> ()
346
+ }
347
+
348
+ let private CheckCompilerMessageAttribute g attribs m =
349
+ trackErrors {
350
+ match TryFindFSharpAttribute g g.attrib_ CompilerMessageAttribute attribs with
351
+ | Some( Attrib( unnamedArgs= [ AttribStringArg s ; AttribInt32Arg n ]; propVal= namedArgs)) ->
352
+ let msg = UserCompilerMessage( s, n, m)
353
+ let isError =
354
+ match namedArgs with
355
+ | ExtractAttribNamedArg " IsError" ( AttribBoolArg v) -> v
356
+ | _ -> false
357
+ // If we are using a compiler that supports nameof then error 3501 is always suppressed.
358
+ // See attribute on FSharp.Core 'nameof'
359
+ if n = 3501 then
360
+ ()
361
+ elif isError && ( not g.compilingFSharpCore || n <> 1204 ) then
362
+ do ! ErrorD msg
363
+ else
364
+ do ! WarnD msg
365
+ | _ ->
366
+ ()
367
+ }
368
+
369
+ let private CheckExperimentalAttribute g attribs m =
370
+ trackErrors {
371
+ match TryFindFSharpAttribute g g.attrib_ ExperimentalAttribute attribs with
372
+ | Some( Attrib( unnamedArgs= [ AttribStringArg( s) ])) ->
373
+ let isExperimentalAttributeDisabled ( s : string ) =
374
+ if g.compilingFSharpCore then
375
+ true
376
+ else
377
+ g.langVersion.IsPreviewEnabled && ( s.IndexOf( langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0 )
378
+ if not ( isExperimentalAttributeDisabled s) then
379
+ do ! WarnD( Experimental( s, m))
380
+ | Some _ ->
381
+ do ! WarnD( Experimental( FSComp.SR.experimentalConstruct (), m))
382
+ | _ ->
383
+ ()
384
+ }
385
+
386
+ let private CheckUnverifiableAttribute g attribs m =
387
+ trackErrors {
388
+ match TryFindFSharpAttribute g g.attrib_ UnverifiableAttribute attribs with
389
+ | Some _ ->
390
+ do ! WarnD( PossibleUnverifiableCode( m))
391
+ | _ -> ()
392
+ }
393
+
272
394
/// Check F# attributes for 'ObsoleteAttribute', 'CompilerMessageAttribute' and 'ExperimentalAttribute',
273
395
/// returning errors and warnings as data
274
396
let CheckFSharpAttributes ( g : TcGlobals ) attribs m =
275
397
if isNil attribs then CompleteD
276
398
else
277
399
trackErrors {
278
- match TryFindFSharpAttribute g g.attrib_ SystemObsolete attribs with
279
- | Some( Attrib(_, _, [ AttribStringArg s ], _, _, _, _)) ->
280
- do ! WarnD( ObsoleteWarning( s, m))
281
- | Some( Attrib(_, _, [ AttribStringArg s; AttribBoolArg( isError) ], _, _, _, _)) ->
282
- if isError then
283
- do ! ErrorD ( ObsoleteError( s, m))
284
- else
285
- do ! WarnD ( ObsoleteWarning( s, m))
286
- | Some _ ->
287
- do ! WarnD( ObsoleteWarning( " " , m))
288
- | None ->
289
- ()
290
-
291
- match TryFindFSharpAttribute g g.attrib_ CompilerMessageAttribute attribs with
292
- | Some( Attrib(_, _, [ AttribStringArg s ; AttribInt32Arg n ], namedArgs, _, _, _)) ->
293
- let msg = UserCompilerMessage( s, n, m)
294
- let isError =
295
- match namedArgs with
296
- | ExtractAttribNamedArg " IsError" ( AttribBoolArg v) -> v
297
- | _ -> false
298
- // If we are using a compiler that supports nameof then error 3501 is always suppressed.
299
- // See attribute on FSharp.Core 'nameof'
300
- if n = 3501 then
301
- ()
302
- elif isError && ( not g.compilingFSharpCore || n <> 1204 ) then
303
- do ! ErrorD msg
304
- else
305
- do ! WarnD msg
306
- | _ ->
307
- ()
308
-
309
- match TryFindFSharpAttribute g g.attrib_ ExperimentalAttribute attribs with
310
- | Some( Attrib(_, _, [ AttribStringArg( s) ], _, _, _, _)) ->
311
- let isExperimentalAttributeDisabled ( s : string ) =
312
- if g.compilingFSharpCore then
313
- true
314
- else
315
- g.langVersion.IsPreviewEnabled && ( s.IndexOf( langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0 )
316
- if not ( isExperimentalAttributeDisabled s) then
317
- do ! WarnD( Experimental( s, m))
318
- | Some _ ->
319
- do ! WarnD( Experimental( FSComp.SR.experimentalConstruct (), m))
320
- | _ ->
321
- ()
322
-
323
- match TryFindFSharpAttribute g g.attrib_ UnverifiableAttribute attribs with
324
- | Some _ ->
325
- do ! WarnD( PossibleUnverifiableCode( m))
326
- | _ ->
327
- ()
400
+ do ! CheckObsoleteAttributes g attribs m
401
+ do ! CheckCompilerMessageAttribute g attribs m
402
+ do ! CheckExperimentalAttribute g attribs m
403
+ do ! CheckUnverifiableAttribute g attribs m
328
404
}
329
405
330
406
#if ! NO_ TYPEPROVIDERS
331
407
/// Check a list of provided attributes for 'ObsoleteAttribute', returning errors and warnings as data
332
408
let private CheckProvidedAttributes ( g : TcGlobals ) m ( provAttribs : Tainted < IProvidedCustomAttributeProvider >) =
333
409
let ( AttribInfo ( tref , _ )) = g.attrib_ SystemObsolete
334
410
match provAttribs.PUntaint(( fun a -> a.GetAttributeConstructorArgs( provAttribs.TypeProvider.PUntaintNoFailure( id), tref.FullName)), m) with
335
- | Some ([ Some (:? string as msg) ], _) -> WarnD( ObsoleteWarning ( msg, m))
411
+ | Some ([ Some (:? string as msg) ], _) -> WarnD( ObsoleteDiagnostic ( false , " " , msg, " " , m))
336
412
| Some ([ Some (:? string as msg); Some (:? bool as isError) ], _) ->
337
413
if isError then
338
- ErrorD ( ObsoleteError ( msg, m))
414
+ ErrorD ( ObsoleteDiagnostic ( true , " " , msg, " " , m))
339
415
else
340
- WarnD ( ObsoleteWarning ( msg, m))
416
+ WarnD ( ObsoleteDiagnostic ( false , " " , msg, " " , m))
341
417
| Some ([ None ], _) ->
342
- WarnD( ObsoleteWarning ( " " , m))
418
+ WarnD( ObsoleteDiagnostic ( false , " " , " " , " " , m))
343
419
| Some _ ->
344
- WarnD( ObsoleteWarning ( " " , m))
420
+ WarnD( ObsoleteDiagnostic ( false , " " , " " , " " , m))
345
421
| None ->
346
422
CompleteD
347
423
#endif
0 commit comments