/// <summary>
        /// Called to perform source generation. A generator can use the context to add source files via the AddSource(String, SourceText) method.
        /// </summary>
        /// <param name="context">The context which provides access to the current compilation and allows manipulation of the output.</param>
        public void Execute(GeneratorExecutionContext context)
        {
            try
            {
                context.LogInfo($"Starting source generation for Assembly=[{context.Compilation.Assembly.Name}]");
                var stopwatch = Stopwatch.StartNew();

                // Scan through the assembly and gather all types which should have property bags generated.
                var containerTypeSymbols = ContainerTypeUtility.GetPropertyContainerTypes(context.Compilation.Assembly);
                var propertyBags         = containerTypeSymbols.Select(containerTypeSymbol => new PropertyBagDefinition(containerTypeSymbol)).ToList();

                if (propertyBags.Count != 0)
                {
                    var namespaceDeclarationSyntax  = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("Unity.Properties.Generated"));
                    var usingSystemReflectionSyntax = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System.Reflection"))
                                                      .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($"#if !{Defines.NET_DOTS}"))
                                                      .WithTrailingTrivia(SyntaxFactory.ParseTrailingTrivia("#endif"));

                    foreach (var propertyBag in propertyBags)
                    {
                        if (!propertyBag.IsValidPropertyBag)
                        {
                            var rule = new DiagnosticDescriptor(
                                "SGP002",
                                "Unable to generate PropertyBag",
                                $"Unable to generate PropertyBag for Type=[{propertyBag.ContainerType}]. The type is inaccessible due to its protection level. The type must be flagged as 'public' or 'internal.",
                                "Source Generator",
                                DiagnosticSeverity.Warning,
                                true,
                                string.Empty);

                            context.ReportDiagnostic(Diagnostic.Create(rule, propertyBag.ContainerType.GetSyntaxLocation()));
                            continue;
                        }

                        foreach (var property in propertyBag.GetPropertyMembers().Where(p => !p.IsValidProperty))
                        {
                            var rule = new DiagnosticDescriptor(
                                "SGP003",
                                "Unable to generate Property",
                                $"Unable to generate Property=[{property.PropertyName}] with Type=[{property.MemberType}] for Container=[{propertyBag.ContainerType}]. The member type is inaccessible due to its protection level. The member type must be flagged as 'public' or 'internal.",
                                "Source Generator",
                                DiagnosticSeverity.Warning,
                                true,
                                string.Empty);

                            context.ReportDiagnostic(Diagnostic.Create(rule, propertyBag.ContainerType.GetSyntaxLocation()));
                        }

                        var propertyBagDeclarationSyntax     = PropertyBagFactory.CreatePropertyBagClassDeclarationSyntax(propertyBag);
                        var propertyBagCompilationUnitSyntax = SyntaxFactory.CompilationUnit();

                        if (propertyBag.UsesReflection)
                        {
                            propertyBagCompilationUnitSyntax = propertyBagCompilationUnitSyntax.AddUsings(usingSystemReflectionSyntax);
                        }

                        propertyBagCompilationUnitSyntax = propertyBagCompilationUnitSyntax.AddMembers(namespaceDeclarationSyntax.AddMembers(propertyBagDeclarationSyntax));
                        propertyBagCompilationUnitSyntax = propertyBagCompilationUnitSyntax.NormalizeWhitespace();

                        var propertyBagHint       = propertyBag.PropertyBagClassName;
                        var propertyBagPath       = context.GetGeneratedDebugSourcePath(propertyBagHint);
                        var propertyBagSourceText = propertyBagCompilationUnitSyntax.GetTextUtf8();

                        File.WriteAllText(propertyBagPath, propertyBagSourceText);
                        context.AddSource(propertyBagHint, propertyBagSourceText);
                    }

                    var registryDeclarationSyntax     = PropertyBagRegistryFactory.CreatePropertyBagRegistryClassDeclarationSyntax(propertyBags);
                    var registryCompilationUnitSyntax = SyntaxFactory.CompilationUnit();

                    registryCompilationUnitSyntax = registryCompilationUnitSyntax.AddMembers(namespaceDeclarationSyntax.AddMembers(registryDeclarationSyntax));
                    registryCompilationUnitSyntax = registryCompilationUnitSyntax.NormalizeWhitespace();

                    var propertyBagRegistryHint       = "PropertyBagRegistry";
                    var propertyBagRegistryPath       = context.GetGeneratedDebugSourcePath(propertyBagRegistryHint);
                    var propertyBagRegistrySourceText = registryCompilationUnitSyntax.GetTextUtf8();

                    File.WriteAllText(propertyBagRegistryPath, propertyBagRegistrySourceText);
                    context.AddSource(propertyBagRegistryHint, propertyBagRegistrySourceText);
                }

                context.LogInfo($"Finished source generation for Assembly=[{context.Compilation.Assembly.Name}] with {propertyBags.Count} property bags in {stopwatch.ElapsedMilliseconds}ms");
            }
            catch (Exception exception)
            {
                var rule = new DiagnosticDescriptor(
                    "SGP001",
                    "Unknown Exception",
                    exception.ToString(),
                    "Source Generator",
                    DiagnosticSeverity.Error,
                    true,
                    string.Empty);

                context.ReportDiagnostic(Diagnostic.Create(rule, context.Compilation.SyntaxTrees.First().GetRoot().GetLocation()));
            }
        }