Skip to content

Commit

Permalink
- add a --include-files flag
Browse files Browse the repository at this point in the history
- add globing support for analyzer filters
- rename filter flags for consistency
  • Loading branch information
dawedawe committed Jan 4, 2024
1 parent 334ca3d commit 408f0e2
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 33 deletions.
2 changes: 1 addition & 1 deletion docs/content/Getting Started Using.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ You can extend the value of `$(FSharpAnalyzersOtherFlags)` by setting it again i
<FSharpAnalyzersOtherFlags>--analyzers-path &quot;$(PkgG-Research_FSharp_Analyzers)/analyzers/dotnet/fs&quot;</FSharpAnalyzersOtherFlags>
<FSharpAnalyzersOtherFlags>$(FSharpAnalyzersOtherFlags) --analyzers-path &quot;$(PkgIonide_Analyzers)/analyzers/dotnet/fs&quot;</FSharpAnalyzersOtherFlags>
<FSharpAnalyzersOtherFlags>$(FSharpAnalyzersOtherFlags) --configuration $(Configuration)</FSharpAnalyzersOtherFlags>
<FSharpAnalyzersOtherFlags>$(FSharpAnalyzersOtherFlags) --exclude-analyzer PartialAppAnalyzer</FSharpAnalyzersOtherFlags>
<FSharpAnalyzersOtherFlags>$(FSharpAnalyzersOtherFlags) --exclude-analyzers PartialAppAnalyzer</FSharpAnalyzersOtherFlags>
</PropertyGroup>
```

Expand Down
82 changes: 55 additions & 27 deletions src/FSharp.Analyzers.Cli/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ type Arguments =
| [<Unique>] Treat_As_Hint of string list
| [<Unique>] Treat_As_Warning of string list
| [<Unique>] Treat_As_Error of string list
| [<Unique>] Ignore_Files of string list
| [<Unique>] Exclude_Analyzer of string list
| [<Unique>] Include_Analyzer of string list
| [<Unique>] Exclude_Files of string list
| [<Unique>] Include_Files of string list
| [<Unique>] Exclude_Analyzers of string list
| [<Unique>] Include_Analyzers of string list
| [<Unique>] Report of string
| [<Unique>] FSC_Args of string
| [<Unique>] Code_Root of string
Expand All @@ -52,10 +53,12 @@ type Arguments =
"List of analyzer codes that should be treated as severity Warning by the tool. Regardless of the original severity."
| Treat_As_Error _ ->
"List of analyzer codes that should be treated as severity Error by the tool. Regardless of the original severity."
| Ignore_Files _ -> "Source files that shouldn't be processed."
| Exclude_Analyzer _ -> "The names of analyzers that should not be executed."
| Include_Analyzer _ ->
"The names of analyzers that should exclusively be executed while all others are ignored. Takes precedence over --exclude-analyzer."
| Exclude_Files _ -> "Source files that shouldn't be processed."
| Include_Files _ ->
"Source files that should be processed exclusively while all others are ignored. Takes precedence over --exclude-files."
| Exclude_Analyzers _ -> "The names of analyzers that should not be executed."
| Include_Analyzers _ ->
"The names of analyzers that should exclusively be executed while all others are ignored. Takes precedence over --exclude-analyzers."
| Report _ -> "Write the result messages to a (sarif) report file."
| Verbosity _ ->
"The verbosity level. The available verbosity levels are: n[ormal], d[etailed], diag[nostic]."
Expand Down Expand Up @@ -131,7 +134,7 @@ let loadProject toolsPath properties projPath =
let runProjectAux
(client: Client<CliAnalyzerAttribute, CliContext>)
(fsharpOptions: FSharpProjectOptions)
(ignoreFiles: Glob list)
(excludeIncludeFiles: Choice<Glob list, Glob list>)
(mappings: SeverityMappings)
=
async {
Expand All @@ -140,11 +143,19 @@ let runProjectAux
let! messagesPerAnalyzer =
fsharpOptions.SourceFiles
|> Array.filter (fun file ->
match ignoreFiles |> List.tryFind (fun g -> g.IsMatch file) with
| Some g ->
logger.LogInformation("Ignoring file {0} for pattern {1}", file, g.Pattern)
false
| None -> true
match excludeIncludeFiles with
| Choice1Of2 excludeFiles ->
match excludeFiles |> List.tryFind (fun g -> g.IsMatch file) with
| Some g ->
logger.LogInformation("Ignoring file {0} for pattern {1}", file, g.Pattern)
false
| None -> true
| Choice2Of2 includeFiles ->
match includeFiles |> List.tryFind (fun g -> g.IsMatch file) with
| Some g ->
logger.LogInformation("Including file {0} for pattern {1}", file, g.Pattern)
true
| None -> false
)
|> Array.choose (fun fileName ->
let fileContent = File.ReadAllText fileName
Expand Down Expand Up @@ -173,13 +184,13 @@ let runProject
toolsPath
properties
proj
(globs: Glob list)
(excludeIncludeFiles: Choice<Glob list, Glob list>)
(mappings: SeverityMappings)
=
async {
let path = Path.Combine(Environment.CurrentDirectory, proj) |> Path.GetFullPath
let! option = loadProject toolsPath properties path
return! runProjectAux client option globs mappings
return! runProjectAux client option excludeIncludeFiles mappings
}

let fsharpFiles = set [| ".fs"; ".fsi"; ".fsx" |]
Expand All @@ -190,7 +201,7 @@ let isFSharpFile (file: string) =
let runFscArgs
(client: Client<CliAnalyzerAttribute, CliContext>)
(fscArgs: string)
(globs: Glob list)
(excludeIncludeFiles: Choice<Glob list, Glob list>)
(mappings: SeverityMappings)
=
if String.IsNullOrWhiteSpace fscArgs then
Expand Down Expand Up @@ -229,7 +240,7 @@ let runFscArgs
Stamp = None
}

runProjectAux client projectOptions globs mappings
runProjectAux client projectOptions excludeIncludeFiles mappings

let printMessages (msgs: AnalyzerMessage list) =

Expand Down Expand Up @@ -507,9 +518,24 @@ let main argv =
let fscArgs = results.TryGetResult <@ FSC_Args @>
let report = results.TryGetResult <@ Report @>
let codeRoot = results.TryGetResult <@ Code_Root @>
let ignoreFiles = results.GetResult(<@ Ignore_Files @>, [])
logger.LogInformation("Ignore Files: [{0}]", (ignoreFiles |> String.concat ", "))
let ignoreFiles = ignoreFiles |> List.map Glob

let exclInclFiles =
let excludeFiles = results.GetResult(<@ Exclude_Files @>, [])
logger.LogInformation("Exclude Files: [{0}]", (excludeFiles |> String.concat ", "))
let excludeFiles = excludeFiles |> List.map Glob

let includeFiles = results.GetResult(<@ Include_Files @>, [])
logger.LogInformation("Include Files: [{0}]", (includeFiles |> String.concat ", "))
let includeFiles = includeFiles |> List.map Glob

match excludeFiles, includeFiles with
| e, [] -> Choice1Of2 e
| [], i -> Choice2Of2 i
| _e, i ->
logger.LogWarning("--exclude-files and --include-files are mutually exclusive, ignoring --exclude-files")

Choice2Of2 i

let properties = getProperties results

if Option.isSome fscArgs && not properties.IsEmpty then
Expand All @@ -534,14 +560,14 @@ let main argv =

logger.LogInformation("Loading analyzers from {0}", (String.concat ", " analyzersPaths))

let includeExclude =
let excludeAnalyzers = results.GetResult(<@ Exclude_Analyzer @>, [])
let includeAnalyzers = results.GetResult(<@ Include_Analyzer @>, [])
let exclInclAnalyzers =
let excludeAnalyzers = results.GetResult(<@ Exclude_Analyzers @>, [])
let includeAnalyzers = results.GetResult(<@ Include_Analyzers @>, [])

match excludeAnalyzers, includeAnalyzers with
| e, [] -> Exclude(Set.ofList e)
| [], i -> Include(Set.ofList i)
| i, _e ->
| _e, i ->
logger.LogWarning(
"--exclude-analyzers and --include-analyzers are mutually exclusive, ignoring --exclude-analyzers"
)
Expand All @@ -568,7 +594,7 @@ let main argv =
let dlls, analyzers =
((0, 0), analyzersPaths)
||> List.fold (fun (accDlls, accAnalyzers) analyzersPath ->
let dlls, analyzers = client.LoadAnalyzers(analyzersPath, includeExclude)
let dlls, analyzers = client.LoadAnalyzers(analyzersPath, exclInclAnalyzers)
(accDlls + dlls), (accAnalyzers + analyzers)
)

Expand All @@ -586,7 +612,9 @@ let main argv =
| _ :: _, Some _ ->
logger.LogError("`--project` and `--fsc-args` cannot be combined.")
exit 1
| [], Some fscArgs -> runFscArgs client fscArgs ignoreFiles severityMapping |> Async.RunSynchronously
| [], Some fscArgs ->
runFscArgs client fscArgs exclInclFiles severityMapping
|> Async.RunSynchronously
| projects, None ->
for projPath in projects do
if not (File.Exists(projPath)) then
Expand All @@ -595,7 +623,7 @@ let main argv =

projects
|> List.map (fun projPath ->
runProject client toolsPath properties projPath ignoreFiles severityMapping
runProject client toolsPath properties projPath exclInclFiles severityMapping
)
|> Async.Sequential
|> Async.RunSynchronously
Expand Down
20 changes: 15 additions & 5 deletions src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open System.Collections.Concurrent
open System.Reflection
open System.Runtime.Loader
open System.Text.RegularExpressions
open GlobExpressions
open McMaster.NETCore.Plugins
open Microsoft.Extensions.Logging

Expand Down Expand Up @@ -141,6 +142,13 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC

member x.LoadAnalyzers(dir: string, ?excludeInclude: ExcludeInclude) : int * int =
if Directory.Exists dir then

let excludeInclude =
match excludeInclude with
| Some(Exclude excluded) -> Some(Choice1Of2(List.ofSeq excluded |> List.map Glob))
| Some(Include included) -> Some(Choice2Of2(List.ofSeq included |> List.map Glob))
| None -> None

let analyzerAssemblies =
let regex = Regex(@".*test.*\.dll$")

Expand All @@ -149,7 +157,7 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC
let s = Path.GetFileName(a)

not (
s.EndsWith("fsharp.analyzers.sdk.dll", StringComparison.InvariantCultureIgnoreCase)
s.EndsWith("fsharp.analyzers.sdk.dll", StringComparison.OrdinalIgnoreCase)
|| regex.IsMatch(s)
)
)
Expand Down Expand Up @@ -200,8 +208,9 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC
|> Seq.collect (Client.analyzersFromType<'TAttribute, 'TContext> path)
|> Seq.filter (fun registeredAnalyzer ->
match excludeInclude with
| Some(Exclude excluded) ->
let shouldExclude = excluded.Contains(registeredAnalyzer.Name)
| Some(Choice1Of2 excluded) ->
let shouldExclude =
excluded |> List.exists (fun g -> g.IsMatch registeredAnalyzer.Name)

if shouldExclude then
logger.LogInformation(
Expand All @@ -211,8 +220,9 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC
)

not shouldExclude
| Some(Include included) ->
let shouldInclude = included.Contains(registeredAnalyzer.Name)
| Some(Choice2Of2 included) ->
let shouldInclude =
included |> List.exists (fun g -> g.IsMatch registeredAnalyzer.Name)

if shouldInclude then
logger.LogInformation(
Expand Down
1 change: 1 addition & 0 deletions src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
<PackageReference Include="FSharp.Compiler.Service" />
<PackageReference Include="McMaster.NETCore.Plugins" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Glob" />
</ItemGroup>
</Project>

0 comments on commit 408f0e2

Please sign in to comment.