예제 #1
0
 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);
        }