|
1 | 1 | open System
|
| 2 | +open System.Collections.Generic |
2 | 3 | open System.IO
|
3 | 4 | open System.Runtime.Loader
|
4 | 5 | open System.Runtime.InteropServices
|
@@ -456,6 +457,32 @@ let getProperties (results: ParseResults<Arguments>) =
|
456 | 457 | | _ -> ()
|
457 | 458 | ]
|
458 | 459 |
|
| 460 | +/// Returns a "does this string match any of these globs" function, |
| 461 | +/// and also an IReadOnlyList you can use to determine whether across all invocations of the function, |
| 462 | +/// any given glob was ever matched. |
| 463 | +/// Note that the returned function will always scan over every element of the input list, so that it |
| 464 | +/// can report the "did anything match this glob" correctly. |
| 465 | +let createFilter (globs: string list) : (string -> bool) * IReadOnlyList<Glob * bool> = |
| 466 | + let globs = globs |> List.map Glob |
| 467 | + |
| 468 | + let unmatchedAnalyzerPatterns = ResizeArray() |
| 469 | + |
| 470 | + globs |> Seq.map (fun glob -> glob, true) |> unmatchedAnalyzerPatterns.AddRange |
| 471 | + |
| 472 | + let anyMatches (s: string) = |
| 473 | + let mutable result = false |
| 474 | + |
| 475 | + globs |
| 476 | + |> List.iteri (fun index glob -> |
| 477 | + if glob.IsMatch s then |
| 478 | + unmatchedAnalyzerPatterns.[index] <- (glob, false) |
| 479 | + result <- true |
| 480 | + ) |
| 481 | + |
| 482 | + result |
| 483 | + |
| 484 | + anyMatches, unmatchedAnalyzerPatterns :> _ |
| 485 | + |
459 | 486 | [<EntryPoint>]
|
460 | 487 | let main argv =
|
461 | 488 | let toolsPath = Init.init (DirectoryInfo Environment.CurrentDirectory) None
|
@@ -555,24 +582,24 @@ let main argv =
|
555 | 582 |
|
556 | 583 | logger.LogInformation("Loading analyzers from {0}", (String.concat ", " analyzersPaths))
|
557 | 584 |
|
558 |
| - let exclInclAnalyzers = |
| 585 | + let exclInclAnalyzers, unmatchedAnalyzerPatterns = |
559 | 586 | let excludeAnalyzers = results.GetResult(<@ Exclude_Analyzers @>, [])
|
560 | 587 | let includeAnalyzers = results.GetResult(<@ Include_Analyzers @>, [])
|
561 | 588 |
|
562 | 589 | match excludeAnalyzers, includeAnalyzers with
|
563 | 590 | | e, [] ->
|
564 |
| - fun (s: string) -> e |> List.map Glob |> List.exists (fun g -> g.IsMatch s) |
565 |
| - |> ExcludeFilter |
| 591 | + let result, list = createFilter e |
| 592 | + ExcludeFilter result, list |
566 | 593 | | [], i ->
|
567 |
| - fun (s: string) -> i |> List.map Glob |> List.exists (fun g -> g.IsMatch s) |
568 |
| - |> IncludeFilter |
| 594 | + let result, list = createFilter i |
| 595 | + IncludeFilter result, list |
569 | 596 | | _e, i ->
|
570 | 597 | logger.LogWarning(
|
571 | 598 | "--exclude-analyzers and --include-analyzers are mutually exclusive, ignoring --exclude-analyzers"
|
572 | 599 | )
|
573 | 600 |
|
574 |
| - fun (s: string) -> i |> List.map Glob |> List.exists (fun g -> g.IsMatch s) |
575 |
| - |> IncludeFilter |
| 601 | + let result, list = createFilter i |
| 602 | + IncludeFilter result, list |
576 | 603 |
|
577 | 604 | AssemblyLoadContext.Default.add_Resolving (fun _ctx assemblyName ->
|
578 | 605 | if assemblyName.Name <> "FSharp.Core" then
|
@@ -634,36 +661,51 @@ let main argv =
|
634 | 661 | |> List.concat
|
635 | 662 | |> Some
|
636 | 663 |
|
637 |
| - match results with |
638 |
| - | None -> -1 |
639 |
| - | Some results -> |
640 |
| - let results, hasError = |
641 |
| - match Result.allOkOrError results with |
642 |
| - | Ok results -> results, false |
643 |
| - | Error(results, _errors) -> results, true |
| 664 | + let results = |
| 665 | + match results with |
| 666 | + | None -> exit -1 |
| 667 | + | Some results -> results |
| 668 | + |
| 669 | + let results, hasError = |
| 670 | + match Result.allOkOrError results with |
| 671 | + | Ok results -> results, false |
| 672 | + | Error(results, _errors) -> results, true |
644 | 673 |
|
645 |
| - let results = results |> List.concat |
| 674 | + let results = results |> List.concat |
646 | 675 |
|
647 |
| - printMessages results |
| 676 | + printMessages results |
648 | 677 |
|
649 |
| - report |> Option.iter (writeReport results codeRoot) |
| 678 | + report |> Option.iter (writeReport results codeRoot) |
650 | 679 |
|
651 |
| - let check = |
652 |
| - results |
653 |
| - |> List.exists (fun analyzerMessage -> |
654 |
| - let message = analyzerMessage.Message |
| 680 | + let check = |
| 681 | + results |
| 682 | + |> List.exists (fun analyzerMessage -> |
| 683 | + let message = analyzerMessage.Message |
655 | 684 |
|
656 |
| - message.Severity = Severity.Error |
657 |
| - ) |
| 685 | + message.Severity = Severity.Error |
| 686 | + ) |
658 | 687 |
|
659 |
| - if failedAssemblies > 0 then |
660 |
| - logger.LogError( |
661 |
| - "Because we failed to load some assemblies to obtain analyzers from them, exiting (failure count: {FailedAssemblyLoadCount})", |
662 |
| - failedAssemblies |
663 |
| - ) |
| 688 | + if failedAssemblies > 0 then |
| 689 | + logger.LogError( |
| 690 | + "Because we failed to load some assemblies to obtain analyzers from them, exiting (failure count: {FailedAssemblyLoadCount})", |
| 691 | + failedAssemblies |
| 692 | + ) |
| 693 | + |
| 694 | + exit -3 |
| 695 | + |
| 696 | + let unmatchedAnalyzerPatterns = |
| 697 | + unmatchedAnalyzerPatterns |
| 698 | + |> Seq.choose (fun (glob, isUnmatched) -> if isUnmatched then Some glob else None) |
| 699 | + |> Seq.toList |
| 700 | + |
| 701 | + if not (List.isEmpty unmatchedAnalyzerPatterns) then |
| 702 | + logger.LogError( |
| 703 | + "The following glob(s) were specified to include or exclude specific analyzers, but they did not match any discovered analyzers. Have you got them right? {UnmatchedAnalyzerGlobs}", |
| 704 | + unmatchedAnalyzerPatterns |> Seq.map _.Pattern |> String.concat ", " |
| 705 | + ) |
664 | 706 |
|
665 |
| - exit -3 |
| 707 | + exit -5 |
666 | 708 |
|
667 |
| - if check then -2 |
668 |
| - elif hasError then -4 |
669 |
| - else 0 |
| 709 | + if check then -2 |
| 710 | + elif hasError then -4 |
| 711 | + else 0 |
0 commit comments