Skip to content

Commit ea87e3b

Browse files
github-actions[bot]claudedbrattli
authored
[Repo Assist] Fix code scanning alerts: unsafe option unwrapping and struct active patterns (#4473)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Dag Brattli <dag@brattli.net>
1 parent 1e9df07 commit ea87e3b

6 files changed

Lines changed: 62 additions & 41 deletions

File tree

src/Fable.Cli/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Fixed
1818

19+
* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006)
20+
* [All] Add `[<return: Struct>]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009)
1921
* [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave)
2022
* [Python] Fix `DateTimeOffset` millisecond constructor and property (by @ncave)
2123
* [Python] Implement missing `DateTimeOffset` members and fix equality/comparison to use UTC-normalized instants (by @dbrattli)

src/Fable.Compiler/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Fixed
1818

19+
* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006)
20+
* [All] Add `[<return: Struct>]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009)
1921
* [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave)
2022
* [Python] Fix `DateTimeOffset` millisecond constructor and property (by @ncave)
2123
* [Python] Implement missing `DateTimeOffset` members and fix equality/comparison to use UTC-normalized instants (by @dbrattli)

src/Fable.Transforms/Dart/Fable2Dart.fs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,19 @@ module Util =
8989

9090
let (|TransformType|) (com: IDartCompiler) ctx e = com.TransformType(ctx, e)
9191

92+
[<return: Struct>]
9293
let (|Function|_|) =
9394
function
94-
| Fable.Lambda(arg, body, _) -> Some([ arg ], body)
95-
| Fable.Delegate(args, body, _, []) -> Some(args, body)
96-
| _ -> None
95+
| Fable.Lambda(arg, body, _) -> ValueSome([ arg ], body)
96+
| Fable.Delegate(args, body, _, []) -> ValueSome(args, body)
97+
| _ -> ValueNone
9798

99+
[<return: Struct>]
98100
let (|Lets|_|) =
99101
function
100-
| Fable.Let(ident, value, body) -> Some([ ident, value ], body)
101-
| Fable.LetRec(bindings, body) -> Some(bindings, body)
102-
| _ -> None
102+
| Fable.Let(ident, value, body) -> ValueSome([ ident, value ], body)
103+
| Fable.LetRec(bindings, body) -> ValueSome(bindings, body)
104+
| _ -> ValueNone
103105

104106
let makeTypeRefFromName typeName genArgs =
105107
let ident = makeImmutableIdent MetaType typeName

src/Fable.Transforms/Dart/Replacements.fs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ open Fable.AST.Fable
1010
open Fable.Transforms
1111
open Replacements.Util
1212

13+
[<return: Struct>]
1314
let (|DartInt|_|) =
1415
function
1516
| Int8
@@ -19,14 +20,15 @@ let (|DartInt|_|) =
1920
| Int32
2021
| UInt32
2122
| Int64
22-
| UInt64 -> Some DartInt
23-
| _ -> None
23+
| UInt64 -> ValueSome DartInt
24+
| _ -> ValueNone
2425

26+
[<return: Struct>]
2527
let (|DartDouble|_|) =
2628
function
2729
| Float32
28-
| Float64 -> Some DartDouble
29-
| _ -> None
30+
| Float64 -> ValueSome DartDouble
31+
| _ -> ValueNone
3032

3133
let error com msg =
3234
let e = makeImportLib com Any "ExceptionBase" "Types"
@@ -1201,10 +1203,12 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o
12011203
let meth = Naming.lowerFirst meth
12021204

12031205
match meth, t with
1204-
| ("min" | "max"), Number((DartInt | DartDouble), NumberInfo.Empty) ->
1206+
| ("min" | "max"), Number(DartInt, NumberInfo.Empty)
1207+
| ("min" | "max"), Number(DartDouble, NumberInfo.Empty) ->
12051208
Helper.ImportedCall("dart:math", meth, t, args, i.SignatureArgTypes, ?loc = r)
12061209
|> Some
1207-
| ("minMagnitude" | "maxMagnitude"), Number((DartInt | DartDouble), NumberInfo.Empty) ->
1210+
| ("minMagnitude" | "maxMagnitude"), Number(DartInt, NumberInfo.Empty)
1211+
| ("minMagnitude" | "maxMagnitude"), Number(DartDouble, NumberInfo.Empty) ->
12081212
Helper.LibCall(com, "Util", meth, t, args, i.SignatureArgTypes, ?loc = r)
12091213
|> Some
12101214
| _ ->

src/Fable.Transforms/Python/Replacements.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3388,7 +3388,7 @@ let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Exp
33883388
| "get_Item" when i.DeclaringEntityFullName = Types.regexGroupCollection ->
33893389
Helper.LibCall(com, "RegExp", "get_item", t, [ thisArg.Value; args.Head ], [ thisArg.Value.Type ], ?loc = r)
33903390
|> Some
3391-
| "get_Item" -> getExpr r t thisArg.Value args.Head |> Some
3391+
| "get_Item" -> thisArg |> Option.map (fun this -> getExpr r t this args.Head)
33923392
| "get_Count" ->
33933393
// Use int32(len()) to ensure consistent return type
33943394
thisArg

src/Fable.Transforms/Rust/Fable2Rust.fs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,7 @@ module TypeInfo =
897897
// most abstract classes are implemented as non-abstract
898898
makeFullNamePathTy entName genArgsOpt
899899

900+
[<return: Struct>]
900901
let (|HasEmitAttribute|_|) (ent: Fable.Entity) =
901902
ent.Attributes
902903
|> Seq.tryPick (fun att ->
@@ -907,13 +908,15 @@ module TypeInfo =
907908
else
908909
None
909910
)
911+
|> Option.toValueOption
910912

911913
type PointerType =
912914
| Lrc
913915
| Rc
914916
| Arc
915917
| Box
916918

919+
[<return: Struct>]
917920
let (|HasReferenceTypeAttribute|_|) (ent: Fable.Entity) =
918921
ent.Attributes
919922
|> Seq.tryPick (fun att ->
@@ -930,17 +933,19 @@ module TypeInfo =
930933
else
931934
None
932935
)
936+
|> Option.toValueOption
933937

938+
[<return: Struct>]
934939
let (|IsNonErasedInterface|_|) (com: Compiler) =
935940
function
936941
| Fable.DeclaredType(entRef, genArgs) ->
937942
let ent = com.GetEntity(entRef)
938943

939944
if ent.IsInterface && not (ent |> FSharp2Fable.Util.hasAttribute Atts.erase) then
940-
Some(entRef, genArgs)
945+
ValueSome(entRef, genArgs)
941946
else
942-
None
943-
| _ -> None
947+
ValueNone
948+
| _ -> ValueNone
944949

945950
let transformEntityType (com: IRustCompiler) ctx (entRef: Fable.EntityRef) genArgs : Rust.Ty =
946951
match com.GetEntity(entRef) with
@@ -1183,43 +1188,50 @@ module Util =
11831188

11841189
let (|TransformExpr|) (com: IRustCompiler) ctx e = com.TransformExpr(ctx, e)
11851190

1191+
[<return: Struct>]
11861192
let (|Function|_|) =
11871193
function
1188-
| Fable.Lambda(arg, body, info) -> Some([ arg ], body, info)
1189-
| Fable.Delegate(args, body, info, []) -> Some(args, body, info)
1190-
| _ -> None
1194+
| Fable.Lambda(arg, body, info) -> ValueSome([ arg ], body, info)
1195+
| Fable.Delegate(args, body, info, []) -> ValueSome(args, body, info)
1196+
| _ -> ValueNone
11911197

1198+
[<return: Struct>]
11921199
let (|Lets|_|) =
11931200
function
1194-
| Fable.Let(ident, value, body) -> Some([ ident, value ], body)
1195-
| Fable.LetRec(bindings, body) -> Some(bindings, body)
1196-
| _ -> None
1201+
| Fable.Let(ident, value, body) -> ValueSome([ ident, value ], body)
1202+
| Fable.LetRec(bindings, body) -> ValueSome(bindings, body)
1203+
| _ -> ValueNone
11971204

1205+
[<return: Struct>]
11981206
let (|IDisposable|_|) =
11991207
function
1200-
| Replacements.Util.IsEntity (Types.idisposable) _ -> Some()
1201-
| _ -> None
1208+
| Replacements.Util.IsEntity (Types.idisposable) _ -> ValueSome()
1209+
| _ -> ValueNone
12021210

1211+
[<return: Struct>]
12031212
let (|IFormattable|_|) =
12041213
function
1205-
| Replacements.Util.IsEntity (Types.iformattable) _ -> Some()
1206-
| _ -> None
1214+
| Replacements.Util.IsEntity (Types.iformattable) _ -> ValueSome()
1215+
| _ -> ValueNone
12071216

1217+
[<return: Struct>]
12081218
let (|IComparable|_|) =
12091219
function
1210-
| Replacements.Util.IsEntity (Types.icomparableGeneric) (_, [ genArg ]) -> Some(genArg)
1211-
| _ -> None
1220+
| Replacements.Util.IsEntity (Types.icomparableGeneric) (_, [ genArg ]) -> ValueSome(genArg)
1221+
| _ -> ValueNone
12121222

1223+
[<return: Struct>]
12131224
let (|IEquatable|_|) =
12141225
function
1215-
| Replacements.Util.IsEntity (Types.iequatableGeneric) (_, [ genArg ]) -> Some(genArg)
1216-
| _ -> None
1226+
| Replacements.Util.IsEntity (Types.iequatableGeneric) (_, [ genArg ]) -> ValueSome(genArg)
1227+
| _ -> ValueNone
12171228

1229+
[<return: Struct>]
12181230
let (|IEnumerable|_|) =
12191231
function
1220-
| Replacements.Util.IsEntity (Types.ienumerableGeneric) (_, [ genArg ]) -> Some(genArg)
1221-
| Replacements.Util.IsEntity (Types.ienumerable) _ -> Some(Fable.Any)
1222-
| _ -> None
1232+
| Replacements.Util.IsEntity (Types.ienumerableGeneric) (_, [ genArg ]) -> ValueSome(genArg)
1233+
| Replacements.Util.IsEntity (Types.ienumerable) _ -> ValueSome(Fable.Any)
1234+
| _ -> ValueNone
12231235

12241236
let isUnitArg (ident: Fable.Ident) =
12251237
ident.IsCompilerGenerated
@@ -3786,10 +3798,9 @@ module Util =
37863798
let getFunctionBodyCtx com ctx (name: string option) (args: Fable.Ident list) (body: Fable.Expr) isTailRec =
37873799

37883800
let tco =
3789-
if isTailRec then
3790-
Some(NamedTailCallOpportunity(com, ctx, name.Value, args) :> ITailCallOpportunity)
3791-
else
3792-
None
3801+
match isTailRec, name with
3802+
| true, Some n -> Some(NamedTailCallOpportunity(com, ctx, n, args) :> ITailCallOpportunity)
3803+
| _ -> None
37933804

37943805
let usages = calcIdentUsages args [ body ]
37953806

@@ -3874,17 +3885,17 @@ module Util =
38743885
let fnBody = transformFunctionBody com ctx args body
38753886

38763887
let fnBody =
3877-
if isRecursive && not isTailRec then
3888+
match isRecursive && not isTailRec, name with
3889+
| true, Some n ->
38783890
// make the closure recursive with fixed-point combinator
3879-
let fixedArgs = (makeIdent name.Value) :: args
3891+
let fixedArgs = (makeIdent n) :: args
38803892
let fixedDecl = transformFunctionDecl com ctx fixedArgs [] Fable.Unit
38813893
let fixedBody = mkClosureExpr true fixedDecl fnBody
38823894
let argExprs = args |> List.map Fable.IdentExpr
38833895
let callArgs = transformCallArgs com ctx argExprs [] []
38843896
let fixCallArgs = (fixedBody |> mkAddrOfExpr) :: callArgs
38853897
makeLibCall com ctx None "Native" ("fix" + argCount) fixCallArgs
3886-
else
3887-
fnBody
3898+
| _ -> fnBody
38883899

38893900
let cloneStmts =
38903901
// clone captured idents (in 'move' closures)

0 commit comments

Comments
 (0)