diff --git a/src/Fable.Cli/CHANGELOG.md b/src/Fable.Cli/CHANGELOG.md index ce1258499..0966367b7 100644 --- a/src/Fable.Cli/CHANGELOG.md +++ b/src/Fable.Cli/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006) +* [All] Add `[]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009) * [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave) * [Python] Fix `DateTimeOffset` millisecond constructor and property (by @ncave) * [Python] Fix `String.IndexOf`/`LastIndexOf` with `StringComparison` argument emitting it as a start-index instead of a compile error (by @repo-assist) diff --git a/src/Fable.Compiler/CHANGELOG.md b/src/Fable.Compiler/CHANGELOG.md index 1fe7753e5..ed2c1046d 100644 --- a/src/Fable.Compiler/CHANGELOG.md +++ b/src/Fable.Compiler/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006) +* [All] Add `[]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009) * [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave) * [Python] Fix `DateTimeOffset` millisecond constructor and property (by @ncave) * [Python] Fix `String.IndexOf`/`LastIndexOf` with `StringComparison` argument emitting it as a start-index instead of a compile error (by @repo-assist) diff --git a/src/Fable.Transforms/Dart/Fable2Dart.fs b/src/Fable.Transforms/Dart/Fable2Dart.fs index bd0169f73..3324c8120 100644 --- a/src/Fable.Transforms/Dart/Fable2Dart.fs +++ b/src/Fable.Transforms/Dart/Fable2Dart.fs @@ -89,17 +89,19 @@ module Util = let (|TransformType|) (com: IDartCompiler) ctx e = com.TransformType(ctx, e) + [] let (|Function|_|) = function - | Fable.Lambda(arg, body, _) -> Some([ arg ], body) - | Fable.Delegate(args, body, _, []) -> Some(args, body) - | _ -> None + | Fable.Lambda(arg, body, _) -> ValueSome([ arg ], body) + | Fable.Delegate(args, body, _, []) -> ValueSome(args, body) + | _ -> ValueNone + [] let (|Lets|_|) = function - | Fable.Let(ident, value, body) -> Some([ ident, value ], body) - | Fable.LetRec(bindings, body) -> Some(bindings, body) - | _ -> None + | Fable.Let(ident, value, body) -> ValueSome([ ident, value ], body) + | Fable.LetRec(bindings, body) -> ValueSome(bindings, body) + | _ -> ValueNone let makeTypeRefFromName typeName genArgs = let ident = makeImmutableIdent MetaType typeName diff --git a/src/Fable.Transforms/Dart/Replacements.fs b/src/Fable.Transforms/Dart/Replacements.fs index 5f8dd6f1f..c19628489 100644 --- a/src/Fable.Transforms/Dart/Replacements.fs +++ b/src/Fable.Transforms/Dart/Replacements.fs @@ -10,6 +10,7 @@ open Fable.AST.Fable open Fable.Transforms open Replacements.Util +[] let (|DartInt|_|) = function | Int8 @@ -19,14 +20,15 @@ let (|DartInt|_|) = | Int32 | UInt32 | Int64 - | UInt64 -> Some DartInt - | _ -> None + | UInt64 -> ValueSome DartInt + | _ -> ValueNone +[] let (|DartDouble|_|) = function | Float32 - | Float64 -> Some DartDouble - | _ -> None + | Float64 -> ValueSome DartDouble + | _ -> ValueNone let error com msg = let e = makeImportLib com Any "ExceptionBase" "Types" @@ -1201,10 +1203,12 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o let meth = Naming.lowerFirst meth match meth, t with - | ("min" | "max"), Number((DartInt | DartDouble), NumberInfo.Empty) -> + | ("min" | "max"), Number(DartInt, NumberInfo.Empty) + | ("min" | "max"), Number(DartDouble, NumberInfo.Empty) -> Helper.ImportedCall("dart:math", meth, t, args, i.SignatureArgTypes, ?loc = r) |> Some - | ("minMagnitude" | "maxMagnitude"), Number((DartInt | DartDouble), NumberInfo.Empty) -> + | ("minMagnitude" | "maxMagnitude"), Number(DartInt, NumberInfo.Empty) + | ("minMagnitude" | "maxMagnitude"), Number(DartDouble, NumberInfo.Empty) -> Helper.LibCall(com, "Util", meth, t, args, i.SignatureArgTypes, ?loc = r) |> Some | _ -> diff --git a/src/Fable.Transforms/Python/Replacements.fs b/src/Fable.Transforms/Python/Replacements.fs index 2c74811a0..c39ac5272 100644 --- a/src/Fable.Transforms/Python/Replacements.fs +++ b/src/Fable.Transforms/Python/Replacements.fs @@ -3245,7 +3245,7 @@ let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Exp | "get_Item" when i.DeclaringEntityFullName = Types.regexGroupCollection -> Helper.LibCall(com, "RegExp", "get_item", t, [ thisArg.Value; args.Head ], [ thisArg.Value.Type ], ?loc = r) |> Some - | "get_Item" -> getExpr r t thisArg.Value args.Head |> Some + | "get_Item" -> thisArg |> Option.map (fun this -> getExpr r t this args.Head) | "get_Count" -> // Use int32(len()) to ensure consistent return type thisArg diff --git a/src/Fable.Transforms/Rust/Fable2Rust.fs b/src/Fable.Transforms/Rust/Fable2Rust.fs index 2a0dc91fc..186a4a13d 100644 --- a/src/Fable.Transforms/Rust/Fable2Rust.fs +++ b/src/Fable.Transforms/Rust/Fable2Rust.fs @@ -897,6 +897,7 @@ module TypeInfo = // most abstract classes are implemented as non-abstract makeFullNamePathTy entName genArgsOpt + [] let (|HasEmitAttribute|_|) (ent: Fable.Entity) = ent.Attributes |> Seq.tryPick (fun att -> @@ -907,6 +908,7 @@ module TypeInfo = else None ) + |> Option.toValueOption type PointerType = | Lrc @@ -914,6 +916,7 @@ module TypeInfo = | Arc | Box + [] let (|HasReferenceTypeAttribute|_|) (ent: Fable.Entity) = ent.Attributes |> Seq.tryPick (fun att -> @@ -930,17 +933,19 @@ module TypeInfo = else None ) + |> Option.toValueOption + [] let (|IsNonErasedInterface|_|) (com: Compiler) = function | Fable.DeclaredType(entRef, genArgs) -> let ent = com.GetEntity(entRef) if ent.IsInterface && not (ent |> FSharp2Fable.Util.hasAttribute Atts.erase) then - Some(entRef, genArgs) + ValueSome(entRef, genArgs) else - None - | _ -> None + ValueNone + | _ -> ValueNone let transformEntityType (com: IRustCompiler) ctx (entRef: Fable.EntityRef) genArgs : Rust.Ty = match com.GetEntity(entRef) with @@ -1176,43 +1181,50 @@ module Util = let (|TransformExpr|) (com: IRustCompiler) ctx e = com.TransformExpr(ctx, e) + [] let (|Function|_|) = function - | Fable.Lambda(arg, body, info) -> Some([ arg ], body, info) - | Fable.Delegate(args, body, info, []) -> Some(args, body, info) - | _ -> None + | Fable.Lambda(arg, body, info) -> ValueSome([ arg ], body, info) + | Fable.Delegate(args, body, info, []) -> ValueSome(args, body, info) + | _ -> ValueNone + [] let (|Lets|_|) = function - | Fable.Let(ident, value, body) -> Some([ ident, value ], body) - | Fable.LetRec(bindings, body) -> Some(bindings, body) - | _ -> None + | Fable.Let(ident, value, body) -> ValueSome([ ident, value ], body) + | Fable.LetRec(bindings, body) -> ValueSome(bindings, body) + | _ -> ValueNone + [] let (|IDisposable|_|) = function - | Replacements.Util.IsEntity (Types.idisposable) _ -> Some() - | _ -> None + | Replacements.Util.IsEntity (Types.idisposable) _ -> ValueSome() + | _ -> ValueNone + [] let (|IFormattable|_|) = function - | Replacements.Util.IsEntity (Types.iformattable) _ -> Some() - | _ -> None + | Replacements.Util.IsEntity (Types.iformattable) _ -> ValueSome() + | _ -> ValueNone + [] let (|IComparable|_|) = function - | Replacements.Util.IsEntity (Types.icomparableGeneric) (_, [ genArg ]) -> Some(genArg) - | _ -> None + | Replacements.Util.IsEntity (Types.icomparableGeneric) (_, [ genArg ]) -> ValueSome(genArg) + | _ -> ValueNone + [] let (|IEquatable|_|) = function - | Replacements.Util.IsEntity (Types.iequatableGeneric) (_, [ genArg ]) -> Some(genArg) - | _ -> None + | Replacements.Util.IsEntity (Types.iequatableGeneric) (_, [ genArg ]) -> ValueSome(genArg) + | _ -> ValueNone + [] let (|IEnumerable|_|) = function - | Replacements.Util.IsEntity (Types.ienumerableGeneric) (_, [ genArg ]) -> Some(genArg) - | Replacements.Util.IsEntity (Types.ienumerable) _ -> Some(Fable.Any) - | _ -> None + | Replacements.Util.IsEntity (Types.ienumerableGeneric) (_, [ genArg ]) -> ValueSome(genArg) + | Replacements.Util.IsEntity (Types.ienumerable) _ -> ValueSome(Fable.Any) + | _ -> ValueNone let isUnitArg (ident: Fable.Ident) = ident.IsCompilerGenerated @@ -3779,10 +3791,9 @@ module Util = let getFunctionBodyCtx com ctx (name: string option) (args: Fable.Ident list) (body: Fable.Expr) isTailRec = let tco = - if isTailRec then - Some(NamedTailCallOpportunity(com, ctx, name.Value, args) :> ITailCallOpportunity) - else - None + match isTailRec, name with + | true, Some n -> Some(NamedTailCallOpportunity(com, ctx, n, args) :> ITailCallOpportunity) + | _ -> None let usages = calcIdentUsages args [ body ] @@ -3867,17 +3878,17 @@ module Util = let fnBody = transformFunctionBody com ctx args body let fnBody = - if isRecursive && not isTailRec then + match isRecursive && not isTailRec, name with + | true, Some n -> // make the closure recursive with fixed-point combinator - let fixedArgs = (makeIdent name.Value) :: args + let fixedArgs = (makeIdent n) :: args let fixedDecl = transformFunctionDecl com ctx fixedArgs [] Fable.Unit let fixedBody = mkClosureExpr true fixedDecl fnBody let argExprs = args |> List.map Fable.IdentExpr let callArgs = transformCallArgs com ctx argExprs [] [] let fixCallArgs = (fixedBody |> mkAddrOfExpr) :: callArgs makeLibCall com ctx None "Native" ("fix" + argCount) fixCallArgs - else - fnBody + | _ -> fnBody let cloneStmts = // clone captured idents (in 'move' closures)