private GraphVizGraph ExportTypeGraph(NullCheckingEngine engine) { if (FilterGraph.Count == 0) { // Show complete graph return(engine.ExportTypeGraph()); } else { // Show filtered graph var list = new List <(string file, int start, int end)>(); foreach (var entry in FilterGraph) { var m = Regex.Match(entry, @"^([\w_.-]+):(\d+)-(\d+)$"); if (!m.Success) { Console.WriteLine("Invalid value for --show-graph/--export-graph. Expected filename.cs:100-200"); } list.Add((m.Groups[1].Value, int.Parse(m.Groups[2].Value), int.Parse(m.Groups[3].Value))); } return(engine.ExportTypeGraph(location => list.Any(e => MatchesEntry(e, location))));
/// <remarks>Used by reflection in CommandLineApplication.ExecuteAsync</remarks> private async Task <int> OnExecuteAsync(CommandLineApplication _) { var outputDirectory = new DirectoryInfo(Path.GetDirectoryName(ProjectName)); if (await CouldOverwriteUncommittedFilesAsync(outputDirectory)) { await Console.Error.WriteLineAsync($"WARNING: There are files in {outputDirectory.FullName} which may be overwritten, and aren't committed to git"); if (Force) { await Console.Error.WriteLineAsync("Continuing with possibility of data loss due to force option."); } else { await Console.Error.WriteLineAsync("Aborting to avoid data loss (see above warning). Commit the files to git, or use the --force option to override this check."); return(1); } } var buildProps = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { ["Configuration"] = "Debug", ["Platform"] = "AnyCPU" }; var cancellationToken = CancellationToken.None; using var workspace = await CreateWorkspaceAsync(buildProps); await Console.Error.WriteLineAsync("Loading project..."); Project project; try { project = await workspace.OpenProjectAsync(ProjectName, cancellationToken : cancellationToken); } catch (Exception ex) { await Console.Error.WriteLineAsync(ex.ToString()); return(1); } await Console.Error.WriteLineAsync("Compiling..."); var compilation = await project.GetCompilationAsync(cancellationToken) as CSharpCompilation; if (compilation == null) { await Console.Error.WriteLineAsync("project.GetCompilationAsync() did not return CSharpCompilation"); return(1); } compilation = AllNullableSyntaxRewriter.MakeAllReferenceTypesNullable(compilation, cancellationToken); bool hasErrors = false; foreach (var diag in compilation.GetDiagnostics(cancellationToken)) { if (diag.Severity == DiagnosticSeverity.Error) { await Console.Error.WriteLineAsync(diag.ToString()); hasErrors = true; } } if (hasErrors) { await Console.Error.WriteLineAsync("Compilation failed. Cannot infer nullability."); return(1); } await Console.Error.WriteLineAsync("Inferring nullabilities..."); var engine = new NullCheckingEngine(compilation); engine.Analyze(cancellationToken); #if DEBUG if (ShowGraph) { await Console.Error.WriteLineAsync("Showing graph..."); engine.ExportTypeGraph().Show(); } #endif if (DryRun) { await Console.Error.WriteLineAsync("Analysis successful. Results are discarded due to --dry-run."); } else { await Console.Error.WriteLineAsync("Writing modified code..."); engine.ConvertSyntaxTrees(cancellationToken).ForAll(tree => { if (string.IsNullOrEmpty(tree.FilePath)) { return; } using var stream = new FileStream(tree.FilePath, FileMode.Create, FileAccess.Write); using var writer = new StreamWriter(stream, tree.Encoding); writer.Write(tree.GetText(cancellationToken)); }); } await Console.Error.WriteLineAsync("Success!"); return(0); }