private static Options ParseCommandLineArgs(string[] args)
        {
            var options = new Options();
            bool result = CommandLine.Parser.Default.ParseArguments(args, options);
            if (!result)
            {
                Console.WriteLine(HelpText.AutoBuild(options).ToString());
                return null;
            }

            return options;
        }
        private static Tuple<string, Assembly> ValidateOptionsAndLoadAnalyzer(Options options)
        {
            if (Path.GetExtension(options.Solution) != ".sln")
            {
                Console.WriteLine($"'{options.Solution}' is not a valid solution file.");
                return null;
            }

            if (!File.Exists(options.Solution))
            {
                Console.WriteLine($"Provided solution file ('{options.Solution}') does not exists. ");
                return null;
            }

            var analyzerExtension = Path.GetExtension(options.Analyzer);
            if (analyzerExtension != ".dll" && analyzerExtension != ".exe")
            {
                Console.WriteLine($"Provided analyzer '{options.Analyzer}' is not dll or exe");
                return null;
            }

            if (!File.Exists(options.Analyzer))
            {
                Console.WriteLine($"Provided analyzer ('{options.Analyzer}') does not exists. ");
            }

            if (!string.IsNullOrEmpty(options.LogFile))
            {
                options.LogFile = Path.GetFullPath(options.LogFile);
                Console.WriteLine($"Log file enabled ('{options.LogFile}')");
                if (File.Exists(options.LogFile))
                {
                    // Need to move it out!
                    File.Delete(options.LogFile);
                }
            }

            try
            {
                return Tuple.Create(options.Solution, Assembly.LoadFile(options.Analyzer));
            }
            catch (Exception e)
            {
                Console.WriteLine($"Failed to load analyzer '{options.Analyzer}':{Environment.NewLine}:{e}");
                return null;
            }
        }
        private static async Task AnalyzeSolutionAsync(string solutionFile, Assembly analyzer, Options options)
        {
            var analyzers = GetAnalyzers(analyzer).ToImmutableArray();

            // Loading the solution
            var sw = Stopwatch.StartNew();

            var workspace = MSBuildWorkspace.Create();

            WriteInfo($"Opening solution '{solutionFile}'...", enabled: true);

            var solution = await workspace.OpenSolutionAsync(solutionFile);

            WriteInfo($"Loaded solution in {sw.ElapsedMilliseconds}ms with '{solution.ProjectIds.Count}' projects and '{solution.DocumentsCount()}' documents", enabled: true);

            WriteInfo("Running the analysis...", enabled: true);

            // Running the analysis
            sw.Restart();

            var diagnostics = await AnalyseSolutionAsync(solution, analyzers, options);

            WriteInfo($"Found {diagnostics.SelectMany(d => d.Diagnostics).Count()} diagnostics in {sw.ElapsedMilliseconds}ms", enabled: true);

            //PrintDiagnostics(diagnostics, options);
        }
        private static async Task<List<ProjectAnalysisResult>> AnalyseSolutionAsync(Solution solution, ImmutableArray<DiagnosticAnalyzer> analyzers, Options options)
        {
            var ruleIds = analyzers.SelectMany(a => a.SupportedDiagnostics.Select(d => d.Id)).ToImmutableHashSet();

            var projectAnalysisTasks = solution.Projects.Select(p => new {Project = p, Task = AnalyzeProjectAsync(p, analyzers)}).ToList();

            foreach (var task in projectAnalysisTasks)
            {
                var local = task;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                task.Task.ContinueWith(tsk =>
                {
                    var relevantRules = tsk.Result.Where(d => ruleIds.Contains(d.Id)).ToImmutableArray();
                    if (options.PrintWarningsAndErrors)
                    {
                        PrintDiagnostics(local.Project, relevantRules);
                    }
                    if (!string.IsNullOrEmpty(options.LogFile))
                    {
                        WriteDiagnosticsToLog(options.LogFile, local.Project, relevantRules);
                    }
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }

            await Task.WhenAll(projectAnalysisTasks.Select(p => p.Task));

            var result = 
                projectAnalysisTasks
                .Select(r => new ProjectAnalysisResult(r.Project, r.Task.Result.Where(d => ruleIds.Contains(d.Id)).ToImmutableArray())).ToList();
            
            return result;
        }