Skip to content

Commit 4044fce

Browse files
dbrattliclaude
andcommitted
[Beam] Fix Ionide.Analyzers warnings in Beam target files
- Add StringComparison.Ordinal to all StartsWith/EndsWith calls - Add %s/%d format specifiers to interpolated string holes - Replace `string` function with .ToString() for type safety - All 792 tests still pass, 0 failures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e819b75 commit 4044fce

File tree

4 files changed

+45
-39
lines changed

4 files changed

+45
-39
lines changed

src/Fable.Transforms/Beam/ErlangPrinter.fs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module Output =
99

1010
let rec printLiteral (sb: System.Text.StringBuilder) (lit: ErlLiteral) =
1111
match lit with
12-
| Integer i -> sb.Append(string i) |> ignore
12+
| Integer i -> sb.Append(i.ToString()) |> ignore
1313
| Float f ->
1414
// Use full double precision (17 significant digits) to avoid lossy rounding
1515
let s = sprintf "%.17g" f
@@ -18,7 +18,7 @@ module Output =
1818
sb.Append(s) |> ignore
1919
else
2020
sb.Append(s + ".0") |> ignore
21-
| StringLit s -> sb.Append($"<<\"{escapeErlangString s}\">>") |> ignore
21+
| StringLit s -> sb.Append($"<<\"%s{escapeErlangString s}\">>") |> ignore
2222
| AtomLit(Atom a) -> sb.Append(a) |> ignore
2323
| BoolLit true -> sb.Append("true") |> ignore
2424
| BoolLit false -> sb.Append("false") |> ignore
@@ -108,8 +108,8 @@ module Output =
108108

109109
| Call(module_, func, args) ->
110110
match module_ with
111-
| Some m -> sb.Append($"{m}:{func}(") |> ignore
112-
| None -> sb.Append($"{func}(") |> ignore
111+
| Some m -> sb.Append($"%s{m}:%s{func}(") |> ignore
112+
| None -> sb.Append($"%s{func}(") |> ignore
113113

114114
args
115115
|> List.iteri (fun i a ->
@@ -185,7 +185,7 @@ module Output =
185185
if i > 0 then
186186
sb.Append(";") |> ignore
187187

188-
sb.Append($"{name}(") |> ignore
188+
sb.Append($"%s{name}(") |> ignore
189189

190190
clause.Patterns
191191
|> List.iteri (fun j p ->
@@ -290,7 +290,7 @@ module Output =
290290
if needsParens left then
291291
sb.Append(")") |> ignore
292292

293-
sb.Append($" {op} ") |> ignore
293+
sb.Append($" %s{op} ") |> ignore
294294

295295
if needsParens right then
296296
sb.Append("(") |> ignore
@@ -326,7 +326,7 @@ module Output =
326326
writeIndent ()
327327
sb.AppendLine($"catch") |> ignore
328328
writeIndent ()
329-
sb.AppendLine($" _:{catchVar} ->") |> ignore
329+
sb.AppendLine($" _:%s{catchVar} ->") |> ignore
330330

331331
catchBody
332332
|> List.iteri (fun i bodyExpr ->
@@ -351,14 +351,14 @@ module Output =
351351
|> List.iteri (fun i arg ->
352352
let argSb = System.Text.StringBuilder()
353353
printExpr argSb indent arg
354-
result <- result.Replace($"${i}", argSb.ToString())
354+
result <- result.Replace($"$%d{i}", argSb.ToString())
355355
)
356356

357357
sb.Append(result) |> ignore
358358

359359
let printFunClause (sb: System.Text.StringBuilder) (name: Atom) (clause: ErlFunClause) =
360360
let (Atom atomName) = name
361-
sb.Append($"{atomName}(") |> ignore
361+
sb.Append($"%s{atomName}(") |> ignore
362362

363363
clause.Patterns
364364
|> List.iteri (fun i p ->
@@ -384,17 +384,17 @@ module Output =
384384

385385
let printAttribute (sb: System.Text.StringBuilder) (attr: ErlAttribute) =
386386
match attr with
387-
| ModuleAttr(Atom name) -> sb.AppendLine($"-module({name}).") |> ignore
387+
| ModuleAttr(Atom name) -> sb.AppendLine($"-module(%s{name}).") |> ignore
388388

389389
| ExportAttr exports ->
390390
let exportStrs =
391391
exports
392-
|> List.map (fun (Atom name, arity) -> $"{name}/{arity}")
392+
|> List.map (fun (Atom name, arity) -> $"%s{name}/%d{arity}")
393393
|> String.concat ", "
394394

395-
sb.AppendLine($"-export([{exportStrs}]).") |> ignore
395+
sb.AppendLine($"-export([%s{exportStrs}]).") |> ignore
396396

397-
| CustomAttr(Atom name, value) -> sb.AppendLine($"-{name}({value}).") |> ignore
397+
| CustomAttr(Atom name, value) -> sb.AppendLine($"-%s{name}(%s{value}).") |> ignore
398398

399399
let printForm (sb: System.Text.StringBuilder) (form: ErlForm) =
400400
match form with
@@ -413,7 +413,7 @@ module Output =
413413

414414
sb.AppendLine(".") |> ignore
415415

416-
| Comment text -> sb.AppendLine($"%% {text}") |> ignore
416+
| Comment text -> sb.AppendLine($"%%%% %s{text}") |> ignore
417417

418418
let printModule (sb: System.Text.StringBuilder) (erlModule: ErlModule) =
419419
erlModule.Forms |> List.iter (printForm sb)

src/Fable.Transforms/Beam/Fable2Beam.Reflection.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ let rec transformTypeInfo
7171
| Fable.DelegateType(argTypes, returnType) ->
7272
let genArgs = resolveGenerics (argTypes @ [ returnType ])
7373
let arity = List.length argTypes + 1
74-
makeTypeInfoMap $"System.Func`{arity}" genArgs
74+
makeTypeInfoMap $"System.Func`%d{arity}" genArgs
7575
| Fable.Tuple(genArgs, isStruct) ->
7676
let resolved = resolveGenerics genArgs
7777
let n = List.length genArgs
@@ -82,7 +82,7 @@ let rec transformTypeInfo
8282
else
8383
"System.Tuple"
8484

85-
makeTypeInfoMap $"{prefix}`{n}" resolved
85+
makeTypeInfoMap $"%s{prefix}`%d{n}" resolved
8686
| Fable.Option(genArg, _) ->
8787
let resolved = resolveGenerics [ genArg ]
8888
makeTypeInfoMap "Microsoft.FSharp.Core.FSharpOption`1" resolved

src/Fable.Transforms/Beam/Fable2Beam.fs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ let private sanitizeErlangName (name: string) =
4949
let c = char (System.Convert.ToInt32(m.Groups.[1].Value, 16))
5050

5151
if System.Char.IsLetterOrDigit(c) then
52-
string c
52+
c.ToString()
5353
else
5454
"_"
5555
)
@@ -79,7 +79,7 @@ let private sanitizeErlangVar (name: string) =
7979
let private toErlangVar (ident: Ident) =
8080
let name = capitalizeFirst ident.Name |> sanitizeErlangVar
8181
// Prefix unit parameters with _ to suppress Erlang unused variable warnings
82-
if ident.Name.StartsWith("unitVar") then
82+
if ident.Name.StartsWith("unitVar", System.StringComparison.Ordinal) then
8383
"_" + name
8484
else
8585
name
@@ -224,7 +224,10 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
224224
let erlExprs = exprs |> List.map (transformExpr com ctx)
225225
Beam.ErlExpr.Block erlExprs
226226

227-
| Let(ident, value, body) when ident.IsMutable && not (ident.Name.StartsWith("copyOfStruct")) ->
227+
| Let(ident, value, body) when
228+
ident.IsMutable
229+
&& not (ident.Name.StartsWith("copyOfStruct", System.StringComparison.Ordinal))
230+
->
228231
// Mutable variable: use process dictionary put/get
229232
// (but not for compiler-generated struct copies which aren't truly mutated)
230233
let atomKey =
@@ -449,7 +452,7 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
449452
if allAreLambdas && bindings.Length > 1 then
450453
// Mutual recursion: bundle all functions into a single named fun
451454
// that dispatches on an atom tag
452-
let bundleName = $"Mk_rec_{com.IncrementCounter()}"
455+
let bundleName = $"Mk_rec_%d{com.IncrementCounter()}"
453456

454457
// Build atom tags and the MutualRecBindings map
455458
let bindingInfos =
@@ -596,7 +599,7 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
596599
// Create a temp var for the raw reason, then wrap it in a map with "message" field
597600
// so that e.Message field access works via maps:get
598601
let ctr = com.IncrementCounter()
599-
let reasonVar = $"Exn_reason_{ctr}"
602+
let reasonVar = $"Exn_reason_%d{ctr}"
600603
let identVar = capitalizeFirst ident.Name
601604

602605
let erlCatchBody = transformExpr com ctx catchExpr
@@ -672,7 +675,7 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
672675
// end,
673676
// WhileLoop_()
674677
let ctr = com.IncrementCounter()
675-
let loopName = $"While_loop_{ctr}"
678+
let loopName = $"While_loop_%d{ctr}"
676679
let erlGuard = transformExpr com ctx guard
677680
let erlBody = transformExpr com ctx body
678681

@@ -727,7 +730,7 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
727730
// end,
728731
// For_loop_(Start)
729732
let ctr = com.IncrementCounter()
730-
let loopName = $"For_loop_{ctr}"
733+
let loopName = $"For_loop_%d{ctr}"
731734
let varName = capitalizeFirst ident.Name |> sanitizeErlangVar
732735
let erlStart = transformExpr com ctx start
733736
let erlLimit = transformExpr com ctx limit
@@ -810,7 +813,7 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
810813

811814
| _ ->
812815
let exprName = expr.GetType().Name
813-
Beam.ErlExpr.Literal(Beam.ErlLiteral.AtomLit(Beam.Atom $"todo_{exprName.ToLowerInvariant()}"))
816+
Beam.ErlExpr.Literal(Beam.ErlLiteral.AtomLit(Beam.Atom $"todo_%s{exprName.ToLowerInvariant()}"))
814817

815818
and transformValue (com: IBeamCompiler) (ctx: Context) (value: ValueKind) : Beam.ErlExpr =
816819
match value with
@@ -890,7 +893,7 @@ and transformValue (com: IBeamCompiler) (ctx: Context) (value: ValueKind) : Beam
890893
let entries =
891894
values
892895
|> List.mapi (fun i v ->
893-
Beam.ErlExpr.Literal(Beam.ErlLiteral.AtomLit(Beam.Atom $"field_{i}")), transformExpr com ctx v
896+
Beam.ErlExpr.Literal(Beam.ErlLiteral.AtomLit(Beam.Atom $"field_%d{i}")), transformExpr com ctx v
894897
)
895898

896899
Beam.ErlExpr.Map entries
@@ -961,7 +964,7 @@ and transformValue (com: IBeamCompiler) (ctx: Context) (value: ValueKind) : Beam
961964

962965
| _ ->
963966
let kindName = value.GetType().Name
964-
Beam.ErlExpr.Literal(Beam.ErlLiteral.AtomLit(Beam.Atom $"todo_{kindName.ToLowerInvariant()}"))
967+
Beam.ErlExpr.Literal(Beam.ErlLiteral.AtomLit(Beam.Atom $"todo_%s{kindName.ToLowerInvariant()}"))
965968

966969
and transformOperation
967970
(com: IBeamCompiler)
@@ -1187,7 +1190,7 @@ and transformCall (com: IBeamCompiler) (ctx: Context) (callee: Expr) (info: Call
11871190
| Beam.ErlExpr.Literal _
11881191
| Beam.ErlExpr.Variable _ -> ([], expr)
11891192
| _ ->
1190-
let varName = $"{name}_{counter}"
1193+
let varName = $"%s{name}_%d{counter}"
11911194
([ Beam.ErlExpr.Match(Beam.PVar varName, expr) ], Beam.ErlExpr.Variable varName)
11921195

11931196
let tempActualH, useActual = storeIfComplex "Assert_actual" cleanActual
@@ -1242,7 +1245,7 @@ and transformCall (com: IBeamCompiler) (ctx: Context) (callee: Expr) (info: Call
12421245
| Beam.ErlExpr.Literal _
12431246
| Beam.ErlExpr.Variable _ -> ([], expr)
12441247
| _ ->
1245-
let varName = $"{name}_{counter}"
1248+
let varName = $"%s{name}_%d{counter}"
12461249
([ Beam.ErlExpr.Match(Beam.PVar varName, expr) ], Beam.ErlExpr.Variable varName)
12471250

12481251
let tempActualH, useActual = storeIfComplex "Assert_actual" cleanActual
@@ -1330,7 +1333,7 @@ and transformCall (com: IBeamCompiler) (ctx: Context) (callee: Expr) (info: Call
13301333
match cleanArgs with
13311334
| [ f; state; list ] ->
13321335
let ctr = com.IncrementCounter()
1333-
let xVar, accVar = $"Fold_x_{ctr}", $"Fold_acc_{ctr}"
1336+
let xVar, accVar = $"Fold_x_%d{ctr}", $"Fold_acc_%d{ctr}"
13341337

13351338
let wrapper =
13361339
Beam.ErlExpr.Fun
@@ -1478,7 +1481,7 @@ and transformCall (com: IBeamCompiler) (ctx: Context) (callee: Expr) (info: Call
14781481
match cleanArgs with
14791482
| [ sub ] ->
14801483
let ctr = com.IncrementCounter()
1481-
let posVar = $"Idx_pos_{ctr}"
1484+
let posVar = $"Idx_pos_%d{ctr}"
14821485

14831486
Beam.ErlExpr.Case(
14841487
Beam.ErlExpr.Call(Some "binary", "match", [ cleanCallee; sub ]),
@@ -1540,7 +1543,7 @@ and transformClassDeclaration
15401543
|> List.map (fun a ->
15411544
let name = capitalizeFirst a.Name |> sanitizeErlangVar
15421545

1543-
if a.Name.StartsWith("unitVar") then
1546+
if a.Name.StartsWith("unitVar", System.StringComparison.Ordinal) then
15441547
Beam.PVar("_" + name)
15451548
else
15461549
Beam.PVar(name)
@@ -1602,7 +1605,10 @@ and transformClassDeclaration
16021605
// The body typically calls the primary constructor
16031606
let ctorArgs =
16041607
memb.Args
1605-
|> List.filter (fun a -> a.Name <> "this" && not (a.Name.StartsWith("unitVar")))
1608+
|> List.filter (fun a ->
1609+
a.Name <> "this"
1610+
&& not (a.Name.StartsWith("unitVar", System.StringComparison.Ordinal))
1611+
)
16061612

16071613
let argPatterns =
16081614
ctorArgs
@@ -1633,7 +1639,7 @@ and transformClassDeclaration
16331639
elif not memb.IsMangled && info.IsGetter then
16341640
// Property getter: class_name_get_prop(This) -> maps:get(prop, get(This)).
16351641
let propName = sanitizeErlangName memb.Name
1636-
let funcName = $"{className}_{propName}"
1642+
let funcName = $"%s{className}_%s{propName}"
16371643
// The getter body references `this` — the first arg
16381644
let thisArg = memb.Args |> List.tryFind (fun a -> a.Name = "this")
16391645

@@ -1665,7 +1671,7 @@ and transformClassDeclaration
16651671
elif not memb.IsMangled && info.IsSetter then
16661672
// Property setter: class_name_set_prop(This, Value) -> put(This, maps:put(prop, Value, get(This))).
16671673
let propName = sanitizeErlangName memb.Name
1668-
let funcName = $"{className}_set_{propName}"
1674+
let funcName = $"%s{className}_set_%s{propName}"
16691675
let nonThisArgs = memb.Args |> List.filter (fun a -> a.Name <> "this")
16701676

16711677
let argPatterns =
@@ -1698,7 +1704,7 @@ and transformClassDeclaration
16981704
else
16991705
// Regular method: class_name_method(This, Args...) -> Body.
17001706
let methodName = sanitizeErlangName memb.Name
1701-
let funcName = $"{className}_{methodName}"
1707+
let funcName = $"%s{className}_%s{methodName}"
17021708
let allArgs = memb.Args
17031709
let nonThisArgs = allArgs |> List.filter (fun a -> a.Name <> "this")
17041710

@@ -1755,7 +1761,7 @@ and transformDeclaration (com: IBeamCompiler) (ctx: Context) (decl: Declaration)
17551761
// Erlang's `_` is anonymous (can't be referenced), need a real var
17561762
if n = "_" || n = "__" then
17571763
"This"
1758-
elif n.EndsWith("$") then
1764+
elif n.EndsWith("$", System.StringComparison.Ordinal) then
17591765
n.TrimEnd('$') // e.g., This$ -> This
17601766
else
17611767
n

src/Fable.Transforms/Beam/Replacements.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,10 +1373,10 @@ let tryCall
13731373
// Large BigInt literals: FromString("12345...") → binary_to_integer
13741374
| "FromString", None, [ arg ] -> emitExpr r t [ arg ] "binary_to_integer($0)" |> Some
13751375
// FromInt32/FromInt64/etc: identity (Erlang native integers)
1376-
| name, None, [ arg ] when name.StartsWith("From") -> Some arg
1376+
| name, None, [ arg ] when name.StartsWith("From", System.StringComparison.Ordinal) -> Some arg
13771377
// ToInt/ToDouble/etc: identity
1378-
| name, None, [ arg ] when name.StartsWith("To") -> Some arg
1379-
| name, Some c, _ when name.StartsWith("To") -> Some c
1378+
| name, None, [ arg ] when name.StartsWith("To", System.StringComparison.Ordinal) -> Some arg
1379+
| name, Some c, _ when name.StartsWith("To", System.StringComparison.Ordinal) -> Some c
13801380
| _ -> None
13811381
| _ -> None
13821382

0 commit comments

Comments
 (0)