Skip to content
Draft
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
56 changes: 52 additions & 4 deletions src/Fable.Cli/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ open Fable.Transforms.State
open Fable.Compiler.ProjectCracker
open Fable.Compiler.Util

module private Util =
module Util =
type PathResolver with

static member Dummy =
Expand Down Expand Up @@ -78,10 +78,18 @@ module private Util =
| Severity.Error -> "error"
| Severity.Info -> "info"

// MSBuild-style `<severity> <tag> <code>`: without the code there is no way to
// discover what to put in a `// fable-disable-line` comment, and rendering it here
// also makes Fable warnings parseable by IDEs and MSBuild loggers.
let tag =
match log.Code with
| Some code -> $"%s{log.Tag} %s{code}"
| None -> log.Tag

match log.Range with
| Some r ->
$"%s{file}(%i{r.start.line},%i{r.start.column}): (%i{r.``end``.line},%i{r.``end``.column}) %s{severity} %s{log.Tag}: %s{log.Message}"
| None -> $"%s{file}(1,1): %s{severity} %s{log.Tag}: %s{log.Message}"
$"%s{file}(%i{r.start.line},%i{r.start.column}): (%i{r.``end``.line},%i{r.``end``.column}) %s{severity} %s{tag}: %s{log.Message}"
| None -> $"%s{file}(1,1): %s{severity} %s{tag}: %s{log.Message}"

let logErrors rootDir (logs: LogEntry seq) =
logs
Expand Down Expand Up @@ -356,6 +364,18 @@ type FsWatcher(delayMs: int) =

type ProjectCracked(cliArgs: CliArgs, crackerResponse: CrackerResponse, sourceFiles: Fable.Compiler.File array) =

let sourceReader = lazy (snd (Fable.Compiler.File.MakeSourceReader sourceFiles))

// Shared by every file of the project: a warning can point at any file (inlined calls) and
// files compile in parallel. A new ProjectCracked is built on every watch rebuild, so this
// never outlives the source it was computed from.
let warningSuppression =
lazy
(WarningSuppression.Resolver.FromCompilerOptions(
crackerResponse.ProjectOptions.OtherOptions,
sourceReader.Value
))

member _.CliArgs = cliArgs
member _.ProjectFile = cliArgs.ProjectFile
member _.FableOptions = cliArgs.CompilerOptions
Expand Down Expand Up @@ -392,9 +412,32 @@ type ProjectCracked(cliArgs: CliArgs, crackerResponse: CrackerResponse, sourceFi
fableLibDir,
crackerResponse.OutputType,
?outDir = cliArgs.OutDir,
?watchDependencies = watchDependencies
?watchDependencies = watchDependencies,
warningSuppression = warningSuppression.Value
)

/// Problems with the `fable-disable` directives themselves (typo'd codes, directives that
/// suppress nothing). Only valid once every file has been compiled, since a directive in one
/// file can be what suppresses a warning raised while compiling another.
member _.DirectiveDiagnostics(files: string seq) =
warningSuppression.Value.GetDiagnostics(files)
|> List.map (fun (file, d) ->
let pos: Position =
{
line = d.Line
column = 0
}

LogEntry.Make(
Severity.Warning,
d.Message,
fileName = file,
range = SourceLocation.Create(pos, pos, file),
code = d.Code
)
)
|> Array.ofList

member _.MapSourceFiles(f) =
ProjectCracked(cliArgs, crackerResponse, Array.map f sourceFiles)

Expand Down Expand Up @@ -1444,6 +1487,11 @@ let private compilationCycle (state: State) (changes: ISet<string>) =
Array.append logs [| log |], deps
)

// Every file is compiled by now, so a directive that still hasn't suppressed anything
// really is unused - checking earlier would flag directives that only ever fire for a
// warning raised while some later file was being compiled.
let logs = Array.append logs (projCracked.DirectiveDiagnostics filesToCompile)

let state =
{ state with
PendingFiles = [||]
Expand Down
19 changes: 17 additions & 2 deletions src/Fable.Compiler/Library.fs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,12 @@ module CodeServices =
opts,
fableLibDir,
crackerResponse.OutputType,
?outDir = cliArgs.OutDir
?outDir = cliArgs.OutDir,
warningSuppression =
WarningSuppression.Resolver.FromCompilerOptions(
crackerResponse.ProjectOptions.OtherOptions,
sourceReader
)
)

// TODO: make it configurable if FableTransforms.transformFile is applied?
Expand Down Expand Up @@ -220,6 +225,9 @@ module CodeServices =
async {
let fableLibDir = Path.getRelativePath currentFile crackerResponse.FableLibDir

// No `warningSuppression`: this overload is handed an already type-checked
// project rather than a `SourceReader`, so there is no source to scan for
// `// fable-disable` comments. Not a bug, just a limitation of the entry point.
let compiler: Compiler =
CompilerImpl(
currentFile,
Expand Down Expand Up @@ -305,6 +313,12 @@ module CodeServices =

let opts = cliArgs.CompilerOptions

let warningSuppression =
WarningSuppression.Resolver.FromCompilerOptions(
crackerResponse.ProjectOptions.OtherOptions,
sourceReader
)

let! compiledFiles =
dependentFiles
|> Array.filter (fun filePath -> not (filePath.EndsWith(".fsi", StringComparison.Ordinal)))
Expand All @@ -319,7 +333,8 @@ module CodeServices =
opts,
fableLibDir,
crackerResponse.OutputType,
?outDir = cliArgs.OutDir
?outDir = cliArgs.OutDir,
warningSuppression = warningSuppression
)

let outputPath = Path.ChangeExtension(currentFile, ".js")
Expand Down
4 changes: 2 additions & 2 deletions src/Fable.Transforms/Babel/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4987,8 +4987,8 @@ module Compiler =

member _.AddWatchDependency(fileName) = com.AddWatchDependency(fileName)

member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag)
member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string, ?code: string) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag, ?code = code)

let makeCompiler com = BabelCompiler(com)

Expand Down
4 changes: 2 additions & 2 deletions src/Fable.Transforms/Beam/Fable2Beam.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3760,8 +3760,8 @@ let transformFile (com: Fable.Compiler) (file: File) : Beam.ErlModule =
member _.GetInlineExpr(key) = com.GetInlineExpr(key)
member _.AddWatchDependency(file) = com.AddWatchDependency(file)

member _.AddLog(msg, severity, ?range, ?fileName, ?tag) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag)
member _.AddLog(msg, severity, ?range, ?fileName, ?tag, ?code) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag, ?code = code)
}

let forms =
Expand Down
4 changes: 2 additions & 2 deletions src/Fable.Transforms/Dart/Fable2Dart.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3117,8 +3117,8 @@ module Compiler =

member _.AddWatchDependency(fileName) = com.AddWatchDependency(fileName)

member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag)
member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string, ?code: string) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag, ?code = code)

let makeCompiler com = DartCompiler(com)

Expand Down
53 changes: 40 additions & 13 deletions src/Fable.Transforms/Dart/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1395,7 +1395,7 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt
| "GetEnumerator", Some c, _ -> stringToCharSeq c |> getEnumerator com r t |> Some
| ("Contains" | "StartsWith" | "EndsWith" as meth), Some c, arg :: _ ->
if List.isMultiple args then
addWarning com ctx.InlinePath r $"String.%s{meth}: second argument is ignored"
WarningCodes.stringComparisonIgnored |> addWarningWithCode com ctx.InlinePath r

Helper.InstanceCall(c, Naming.lowerFirst meth, t, [ arg ], ?loc = r) |> Some
| ReplaceName [ "ToUpper", "toUpperCase"
Expand Down Expand Up @@ -2085,19 +2085,22 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op
let intConst = int System.Globalization.NumberStyles.Integer

if style <> hexConst && style <> intConst then
$"%s{i.DeclaringEntityFullName}.%s{meth}(): NumberStyle %d{style} is ignored"
|> addWarning com ctx.InlinePath r
WarningCodes.numberStylesIgnored style
|> addWarningWithCode com ctx.InlinePath r

let acceptedArgs =
if meth = "Parse" then
2
else
3

if List.length args > acceptedArgs then
match List.tryItem acceptedArgs args with
// InvariantCulture asks for exactly what Fable does, so there is nothing to report.
| None
| Some InvariantCulture -> ()
| Some _ ->
// e.g. Double.Parse(string, style, IFormatProvider) etc.
$"%s{i.DeclaringEntityFullName}.%s{meth}(): provider argument is ignored"
|> addWarning com ctx.InlinePath r
WarningCodes.formatProviderIgnored |> addWarningWithCode com ctx.InlinePath r

parseCall meth str args style
| ("Parse" | "TryParse") as meth, str :: _ ->
Expand All @@ -2107,10 +2110,13 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op
else
2

if List.length args > acceptedArgs then
match List.tryItem acceptedArgs args with
// InvariantCulture asks for exactly what Fable does, so there is nothing to report.
| None
| Some InvariantCulture -> ()
| Some _ ->
// e.g. Double.Parse(string, IFormatProvider) etc.
$"%s{i.DeclaringEntityFullName}.%s{meth}(): provider argument is ignored"
|> addWarning com ctx.InlinePath r
WarningCodes.formatProviderIgnored |> addWarningWithCode com ctx.InlinePath r

let style = int System.Globalization.NumberStyles.Any
parseCall meth str args style
Expand Down Expand Up @@ -2708,8 +2714,7 @@ let convert (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (
| "ToBase64String"
| "FromBase64String" ->
if not (List.isSingle args) then
$"Convert.%s{Naming.upperFirst i.CompiledName} only accepts one single argument"
|> addWarning com ctx.InlinePath r
WarningCodes.base64ArgumentsIgnored |> addWarningWithCode com ctx.InlinePath r

Helper.LibCall(
com,
Expand Down Expand Up @@ -2858,11 +2863,33 @@ let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio

Helper.InstanceCall(thisArg.Value, meth, t, args, ?loc = r) |> Some
| meth ->
// Drops the IFormatProvider (and DateTimeStyles, where present), warning once per
// discarded argument. `Parse arg` with no extra argument discards nothing.
let args =
// Passing InvariantCulture asks for exactly what Fable does, so nothing to report.
let warnProvider culture =
match culture with
| InvariantCulture -> ()
| _ -> WarningCodes.formatProviderIgnored |> addWarningWithCode com ctx.InlinePath r

let warnStyles styles =
match styles with
| NumberConst(NumberValue.Int32 0, _) -> () // DateTimeStyles.None: no special handling
| _ -> WarningCodes.dateTimeStylesIgnored |> addWarningWithCode com ctx.InlinePath r

match meth, args with
// Ignore IFormatProvider
| "Parse", arg :: culture :: styles :: _ ->
warnProvider culture
warnStyles styles
[ arg ]
| "Parse", arg :: culture :: _ ->
warnProvider culture
[ arg ]
| "Parse", arg :: _ -> [ arg ]
| "TryParse", input :: _culture :: _styles :: defVal :: _ -> [ input; defVal ]
| "TryParse", input :: culture :: styles :: defVal :: _ ->
warnProvider culture
warnStyles styles
[ input; defVal ]
| _ -> args

let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst
Expand Down
4 changes: 2 additions & 2 deletions src/Fable.Transforms/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2857,8 +2857,8 @@ type FableCompiler(com: Compiler) =
member _.GetInlineExpr(fullName) = com.GetInlineExpr(fullName)
member _.AddWatchDependency(fileName) = com.AddWatchDependency(fileName)

member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag)
member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string, ?code: string) =
com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag, ?code = code)


let rec attachClassMembers (com: FableCompiler) =
Expand Down
2 changes: 2 additions & 0 deletions src/Fable.Transforms/Fable.Transforms.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<Compile Include="Global/Metadata.fs" />
<Compile Include="Global/Prelude.fs" />
<Compile Include="Global/Compiler.fs" />
<Compile Include="Global/WarningCodes.fs" />
<Compile Include="Global/WarningSuppression.fs" />
<Compile Include="Global/Naming.fs" />
<Compile Include="Python/Prelude.fs" />
<Compile Include="MonadicTrampoline.fs" />
Expand Down
3 changes: 2 additions & 1 deletion src/Fable.Transforms/Global/Compiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ type Compiler =
abstract AddWatchDependency: file: string -> unit

abstract AddLog:
msg: string * severity: Severity * ?range: SourceLocation * ?fileName: string * ?tag: string -> unit
msg: string * severity: Severity * ?range: SourceLocation * ?fileName: string * ?tag: string * ?code: string ->
unit

type InlineExprLazy(f: Compiler -> InlineExpr) =
let mutable value: InlineExpr voption = ValueNone
Expand Down
Loading
Loading