public string[] Generate()
        {
            var globalExecution = Stopwatch.StartNew();

            var details = ProjectLoader.LoadProjectDetails(_environment);

            if (this.Log().IsEnabled(LogLevel.Debug))
            {
                this.Log().Debug($"Got project details after {globalExecution.Elapsed}");
            }

            if (!details.Generators.Any())
            {
                this.Log().Info($"No generators were found.");
                return(new string[0]);
            }

            var compilationResult = GetCompilation().Result;

            if (this.Log().IsEnabled(LogLevel.Debug))
            {
                this.Log().Debug($"Got compilation after {globalExecution.Elapsed}");
            }

            // Build dependencies graph
            var generatorsByName = details.Generators.ToDictionary(g => g.generatorType.FullName);
            var generatorNames   = generatorsByName.Keys;

            // Dependencies list, in the form (before, after)
            var afterGenerators = details.Generators
                                  .Select(g => g.generatorType)
                                  .SelectMany(t => t.GetCustomAttributes <GenerateAfterAttribute>()
                                              .Select(a => a.GeneratorToExecuteBefore)
                                              .Intersect(generatorNames, StringComparer.InvariantCultureIgnoreCase)
                                              .Select(dependency => ((string incoming, string outgoing))(t.FullName, dependency)));

            var beforeGenerators = details.Generators
                                   .Select(g => g.generatorType)
                                   .SelectMany(t => t.GetCustomAttributes <GenerateBeforeAttribute>()
                                               .Select(a => a.GeneratorToExecuteAfter)
                                               .Intersect(generatorNames, StringComparer.InvariantCultureIgnoreCase)
                                               .Select(dependent => ((string incoming, string outgoing))(dependent, t.FullName)));

            var dependencies = afterGenerators.Concat(beforeGenerators)
                               .Where(x => x.incoming != x.outgoing)
                               .Distinct()
                               .ToList();

            if (dependencies.Any())
            {
                this.Log().Info($"Generators Ordering restrictions:\n\t{dependencies.Select(d => $"{d.incoming} -> {d.outgoing}").JoinBy("\n\t")}");
            }

            var groupedGenerators = generatorNames.GroupSort(dependencies);

            if (groupedGenerators == null)
            {
                this.Log().Error("There is a cyclic ordering in the generators. You need to fix it. You may need to set your build output to 'normal' to see dependencies list.");
                return(new string[0]);
            }

            if (dependencies.Any())
            {
                this.Log().Info($"**Generators Execution Plan**\n\tConcurrently: {groupedGenerators.Select(grp=>grp.JoinBy(", ")).JoinBy("\n\tFollowed by: ")}");
            }

            // Run
            var output = new List <string>();

            (string filePath, string content)[] generatedFilesAndContent = null;
        public string[] Generate()
        {
            var globalExecution = Stopwatch.StartNew();

            var details = ProjectLoader.LoadProjectDetails(_environment);

            if (this.Log().IsEnabled(LogLevel.Debug))
            {
                this.Log().Debug($"Got project details after {globalExecution.Elapsed}");
            }

            if (!details.Generators.Any())
            {
                this.Log().Info($"No generators were found.");
                return(new string[0]);
            }

            var compilationResult = GetCompilation(details).Result;

            if (this.Log().IsEnabled(LogLevel.Debug))
            {
                this.Log().Debug($"Got compilation after {globalExecution.Elapsed}");
            }

            var generatorResults = details.Generators
                                   .AsParallel()
                                   .Select(generatorDef =>
            {
                var generator = generatorDef.builder();

                try
                {
                    var context = new InternalSourceGeneratorContext(compilationResult.Item1, compilationResult.Item2);
                    context.SetProjectInstance(details.ExecutedProject);

                    var w = Stopwatch.StartNew();
                    generator.Execute(context);

                    if (this.Log().IsEnabled(LogLevel.Debug))
                    {
                        this.Log().Debug($"Ran {w.Elapsed} for [{generator.GetType()}]");
                    }

                    return(new
                    {
                        Generator = generator,
                        Context = context
                    });
                }
                catch (Exception e)
                {
                    // Wrap the exception into a string to avoid serialization issue when
                    // parts of the stack are coming from an assembly the msbuild task is
                    // not able to load properly.

                    throw new InvalidOperationException($"Generation failed for {generator.GetType()}. {e}");
                }
            })
                                   .ToArray();

            var files = from result in generatorResults
                        from tree in result.Context.Trees
                        select new
            {
                FilePath = Path.Combine(_environment.OutputPath ?? details.IntermediatePath, BuildTreeFileName(result.Generator, tree.Key)),
                Content  = tree.Value
            };

            files = files.ToArray();

            foreach (var file in files)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(file.FilePath));

                if (File.Exists(file.FilePath))
                {
                    if (File.ReadAllText(file.FilePath).SequenceEqual(file.Content))
                    {
                        if (this.Log().IsEnabled(LogLevel.Information))
                        {
                            this.Log().Info($"Skipping generated file with same content: {file.FilePath}");
                        }

                        continue;
                    }
                    else
                    {
                        if (this.Log().IsEnabled(LogLevel.Information))
                        {
                            this.Log().Info($"Overwriting generated file with different content: {file.FilePath}");
                        }
                    }
                }

                File.WriteAllText(file.FilePath, file.Content);
            }

            if (this.Log().IsEnabled(LogLevel.Debug))
            {
                this.Log().Debug($"Code generation ran for {globalExecution.Elapsed}");
            }

            return(files.Select(f => f.FilePath).ToArray());
        }