Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 76 additions & 72 deletions src/Compiler/Checking/AttributeChecking.fs
Original file line number Diff line number Diff line change
Expand Up @@ -267,62 +267,59 @@ let langVersionPrefix = "--langversion:preview"
/// Check F# attributes for 'ObsoleteAttribute', 'CompilerMessageAttribute' and 'ExperimentalAttribute',
/// returning errors and warnings as data
let CheckFSharpAttributes (g:TcGlobals) attribs m =
let isExperimentalAttributeDisabled (s:string) =
if g.compilingFSharpCore then
true
else
g.langVersion.IsPreviewEnabled && (s.IndexOf(langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0)

if isNil attribs then CompleteD
else
(match TryFindFSharpAttribute g g.attrib_SystemObsolete attribs with
| Some(Attrib(_, _, [ AttribStringArg s ], _, _, _, _)) ->
WarnD(ObsoleteWarning(s, m))
| Some(Attrib(_, _, [ AttribStringArg s; AttribBoolArg(isError) ], _, _, _, _)) ->
if isError then
ErrorD (ObsoleteError(s, m))
else
WarnD (ObsoleteWarning(s, m))
| Some _ ->
WarnD(ObsoleteWarning("", m))
| None ->
CompleteD
) ++ (fun () ->

match TryFindFSharpAttribute g g.attrib_CompilerMessageAttribute attribs with
| Some(Attrib(_, _, [ AttribStringArg s ; AttribInt32Arg n ], namedArgs, _, _, _)) ->
let msg = UserCompilerMessage(s, n, m)
let isError =
match namedArgs with
| ExtractAttribNamedArg "IsError" (AttribBoolArg v) -> v
| _ -> false
// If we are using a compiler that supports nameof then error 3501 is always suppressed.
// See attribute on FSharp.Core 'nameof'
if n = 3501 then CompleteD
elif isError && (not g.compilingFSharpCore || n <> 1204) then ErrorD msg
else WarnD msg
| _ ->
CompleteD
) ++ (fun () ->
trackErrors {
match TryFindFSharpAttribute g g.attrib_SystemObsolete attribs with
| Some(Attrib(_, _, [ AttribStringArg s ], _, _, _, _)) ->
do! WarnD(ObsoleteWarning(s, m))
| Some(Attrib(_, _, [ AttribStringArg s; AttribBoolArg(isError) ], _, _, _, _)) ->
if isError then
do! ErrorD (ObsoleteError(s, m))
else
do! WarnD (ObsoleteWarning(s, m))
| Some _ ->
do! WarnD(ObsoleteWarning("", m))
| None ->
do! CompleteD

match TryFindFSharpAttribute g g.attrib_CompilerMessageAttribute attribs with
| Some(Attrib(_, _, [ AttribStringArg s ; AttribInt32Arg n ], namedArgs, _, _, _)) ->
let msg = UserCompilerMessage(s, n, m)
let isError =
match namedArgs with
| ExtractAttribNamedArg "IsError" (AttribBoolArg v) -> v
| _ -> false
// If we are using a compiler that supports nameof then error 3501 is always suppressed.
// See attribute on FSharp.Core 'nameof'
if n = 3501 then do! CompleteD
elif isError && (not g.compilingFSharpCore || n <> 1204) then do! ErrorD msg
else do! WarnD msg
| _ ->
do! CompleteD

match TryFindFSharpAttribute g g.attrib_ExperimentalAttribute attribs with
| Some(Attrib(_, _, [ AttribStringArg(s) ], _, _, _, _)) ->
let isExperimentalAttributeDisabled (s:string) =
if g.compilingFSharpCore then
true
else
g.langVersion.IsPreviewEnabled && (s.IndexOf(langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0)
if isExperimentalAttributeDisabled s then
do! CompleteD
else
do! WarnD(Experimental(s, m))
| Some _ ->
do! WarnD(Experimental(FSComp.SR.experimentalConstruct (), m))
| _ ->
do! CompleteD

match TryFindFSharpAttribute g g.attrib_ExperimentalAttribute attribs with
| Some(Attrib(_, _, [ AttribStringArg(s) ], _, _, _, _)) ->
if isExperimentalAttributeDisabled s then
CompleteD
else
WarnD(Experimental(s, m))
| Some _ ->
WarnD(Experimental(FSComp.SR.experimentalConstruct (), m))
| _ ->
CompleteD
) ++ (fun () ->

match TryFindFSharpAttribute g g.attrib_UnverifiableAttribute attribs with
| Some _ ->
WarnD(PossibleUnverifiableCode(m))
| _ ->
CompleteD
)
match TryFindFSharpAttribute g g.attrib_UnverifiableAttribute attribs with
| Some _ ->
do! WarnD(PossibleUnverifiableCode(m))
| _ ->
do! CompleteD
}

#if !NO_TYPEPROVIDERS
/// Check a list of provided attributes for 'ObsoleteAttribute', returning errors and warnings as data
Expand Down Expand Up @@ -417,31 +414,34 @@ let CheckILEventAttributes g (tcref: TyconRef) cattrs m =
CheckILAttributes g (isByrefLikeTyconRef g m tcref) cattrs m

/// Check the attributes associated with a method, returning warnings and errors as data.
let CheckMethInfoAttributes g m tyargsOpt (minfo: MethInfo) =
match stripTyEqns g minfo.ApparentEnclosingAppType with
| TType_app(tcref, _, _) -> CheckEntityAttributes g tcref m
| _ -> CompleteD
++ (fun () ->
let CheckMethInfoAttributes g m tyargsOpt (minfo: MethInfo) =
trackErrors {
match stripTyEqns g minfo.ApparentEnclosingAppType with
| TType_app(tcref, _, _) -> do! CheckEntityAttributes g tcref m
| _ -> do! CompleteD
let search =
BindMethInfoAttributes m minfo
(fun ilAttribs -> Some(CheckILAttributes g false ilAttribs m))
(fun fsAttribs ->
let res =
CheckFSharpAttributes g fsAttribs m ++ (fun () ->
if Option.isNone tyargsOpt && HasFSharpAttribute g g.attrib_RequiresExplicitTypeArgumentsAttribute fsAttribs then
ErrorD(Error(FSComp.SR.tcFunctionRequiresExplicitTypeArguments(minfo.LogicalName), m))
else
CompleteD)
let res =
trackErrors {
do! CheckFSharpAttributes g fsAttribs m
if Option.isNone tyargsOpt && HasFSharpAttribute g g.attrib_RequiresExplicitTypeArgumentsAttribute fsAttribs then
do! ErrorD(Error(FSComp.SR.tcFunctionRequiresExplicitTypeArguments(minfo.LogicalName), m))
else
do! CompleteD
}

Some res)
#if !NO_TYPEPROVIDERS
(fun provAttribs -> Some (CheckProvidedAttributes g m provAttribs))
#else
(fun _provAttribs -> None)
#endif
match search with
| Some res -> res
| None -> CompleteD // no attribute = no errors
)
| Some res -> do! res
| None -> do! CompleteD // no attribute = no errors
}

/// Indicate if a method has 'Obsolete', 'CompilerMessageAttribute' or 'TypeProviderEditorHideMethodsAttribute'.
/// Used to suppress the item in intellisense.
Expand Down Expand Up @@ -504,14 +504,18 @@ let PropInfoIsUnseen m pinfo =

/// Check the attributes on a union case, returning errors and warnings as data.
let CheckUnionCaseAttributes g (x:UnionCaseRef) m =
CheckEntityAttributes g x.TyconRef m ++ (fun () ->
CheckFSharpAttributes g x.Attribs m)
trackErrors {
do! CheckEntityAttributes g x.TyconRef m
do! CheckFSharpAttributes g x.Attribs m
}

/// Check the attributes on a record field, returning errors and warnings as data.
let CheckRecdFieldAttributes g (x:RecdFieldRef) m =
CheckEntityAttributes g x.TyconRef m ++ (fun () ->
CheckFSharpAttributes g x.PropertyAttribs m) ++ (fun () ->
CheckFSharpAttributes g x.RecdField.FieldAttribs m)
trackErrors {
do! CheckEntityAttributes g x.TyconRef m
do! CheckFSharpAttributes g x.PropertyAttribs m
do! CheckFSharpAttributes g x.RecdField.FieldAttribs m
}

/// Check the attributes on an F# value, returning errors and warnings as data.
let CheckValAttributes g (x:ValRef) m =
Expand Down
Loading