static List <CGFDocument> ProcessDocuments(CGFParserReporter reporter, List <Microsoft.CodeAnalysis.Document> documents, Microsoft.CodeAnalysis.Project project)
        {
            using (reporter.CreateContextScope(CGFParserReporterContext.Type.Project, project.FilePath))
            {
                List <CGFDocument> documentsToProcess = new List <CGFDocument>();
                foreach (Microsoft.CodeAnalysis.Document document in documents)
                {
                    using (reporter.CreateContextScope(CGFParserReporterContext.Type.File, document.FilePath))
                    {
                        List <CGFTypeSymbol> typesToProcess = new List <CGFTypeSymbol>();

                        Microsoft.CodeAnalysis.SemanticModel semanticModel = document.GetSemanticModelAsync().Result;

                        Microsoft.CodeAnalysis.SyntaxTree syntaxTree = document.GetSyntaxTreeAsync().Result;
                        IEnumerable <Microsoft.CodeAnalysis.SyntaxNode> syntaxNodes = syntaxTree.GetRoot().DescendantNodes().Where(n => (n as ClassDeclarationSyntax) != null || (n as EnumDeclarationSyntax) != null);
                        foreach (Microsoft.CodeAnalysis.SyntaxNode node in syntaxNodes)
                        {
                            ClassDeclarationSyntax classSyntax = node as ClassDeclarationSyntax;
                            if (classSyntax != null)
                            {
                                Microsoft.CodeAnalysis.INamedTypeSymbol typeSymbol = semanticModel.GetDeclaredSymbol(classSyntax);
                                using (reporter.CreateContextScope(CGFParserReporterContext.Type.Type, typeSymbol.Name))
                                {
                                    CGFTypeSymbol cgfTypeSymbol = CGFTypeSymbol.Parse(reporter, typeSymbol);
                                    typesToProcess.Add(cgfTypeSymbol);
                                }
                            }
                            else
                            {
                                EnumDeclarationSyntax enumSyntax = node as EnumDeclarationSyntax;
                                Microsoft.CodeAnalysis.INamedTypeSymbol typeSymbol = semanticModel.GetDeclaredSymbol(enumSyntax);

                                using (reporter.CreateContextScope(CGFParserReporterContext.Type.Type, typeSymbol.Name))
                                {
                                    CGFTypeSymbol cgfTypeSymbol = CGFTypeSymbol.Parse(reporter, typeSymbol);
                                    typesToProcess.Add(cgfTypeSymbol);
                                }
                            }
                        }

                        if (typesToProcess.Count > 0)
                        {
                            CGFDocument cgfDocument = CGFDocument.Parse(reporter, document, typesToProcess);
                            documentsToProcess.Add(cgfDocument);
                        }
                    }
                }

                return(documentsToProcess);
            }
        }
        public static CGFTypeSymbol Parse(CGFParserReporter reporter, INamedTypeSymbol typeSymbol)
        {
            CGFTypeSymbol cgfTypeSymbol = new CGFTypeSymbol(typeSymbol);

            foreach (ISymbol member in typeSymbol.GetMembers())
            {
                if (member.Kind == SymbolKind.Field)
                {
                    IFieldSymbol   fieldMember    = member as IFieldSymbol;
                    CGFFieldSymbol cgfFieldSymbol = CGFFieldSymbol.Parse(reporter, fieldMember);
                    cgfTypeSymbol.Fields.Add(cgfFieldSymbol);
                }
            }

            cgfTypeSymbol.Fields.Sort((leftField, rightField) => leftField.DeclaredAccessibilityType - rightField.DeclaredAccessibilityType);

            foreach (CGFFieldSymbol cgfFieldSymbol in cgfTypeSymbol.Fields)
            {
                switch (cgfFieldSymbol.DeclaredAccessibilityType)
                {
                case Accessibility.Public:
                {
                    cgfTypeSymbol.PublicFields.Add(cgfFieldSymbol);
                    break;
                }

                case Accessibility.Protected:
                {
                    cgfTypeSymbol.ProtectedFields.Add(cgfFieldSymbol);
                    break;
                }

                case Accessibility.Private:
                {
                    cgfTypeSymbol.PrivateFields.Add(cgfFieldSymbol);
                    break;
                }
                }
            }

            cgfTypeSymbol.m_AttributeDataList = CGFAttributeDataList.Parse(reporter, typeSymbol.GetAttributes());

            return(cgfTypeSymbol);
        }
        public static CGFParser ParseSolution(CGFParserReporter reporter, string solutionPath)
        {
            string fullSolutionPath = Path.GetFullPath(solutionPath);

            reporter.LogInfo($"CGFParser parsing {solutionPath} (FullPath: {fullSolutionPath})");

            if (!File.Exists(fullSolutionPath))
            {
                reporter.LogError($"{fullSolutionPath} does not exist.");
                return(null);
            }

            CGFParser cgfParser = new CGFParser(reporter);

            string[] documentsToExclude = { "AssemblyAttributes.cs" };

            reporter.LogInfo($"Opening solution {solutionPath}");

            IEnumerable <VisualStudioInstance> visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances(new VisualStudioInstanceQueryOptions {
                DiscoveryTypes = DiscoveryType.VisualStudioSetup
            });
            VisualStudioInstance visualStudioInstance = visualStudioInstances.OrderByDescending(i => i.Version)
                                                        .Where(i => Directory.Exists(i.MSBuildPath))
                                                        .FirstOrDefault();

            if (string.IsNullOrEmpty(visualStudioInstance.MSBuildPath))
            {
                reporter.LogError($"Unable to find a proper VisualStudio instance. MSBuild workspace creation/solution parsing may fail");
            }
            else
            {
                MSBuildLocator.RegisterInstance(visualStudioInstance);
            }

            MSBuildWorkspace workspace = MSBuildWorkspace.Create();

            workspace.LoadMetadataForReferencedProjects = false;
            workspace.WorkspaceFailed         += cgfParser.Workspace_WorkspaceFailed;
            workspace.SkipUnrecognizedProjects = true;
            Microsoft.CodeAnalysis.Solution solution = workspace.OpenSolutionAsync(solutionPath).Result;

            reporter.LogInfo($"Solution opened");

            using (reporter.CreateContextScope(CGFParserReporterContext.Type.Solution, solution.FilePath))
            {
                reporter.LogInfo($"Parsing");
                List <CGFDocument> cgfDocuments = new List <CGFDocument>();
                foreach (Microsoft.CodeAnalysis.Project project in solution.Projects)
                {
                    List <Microsoft.CodeAnalysis.Document> documentsToProcess = new List <Microsoft.CodeAnalysis.Document>();

                    foreach (Microsoft.CodeAnalysis.Document document in project.Documents)
                    {
                        bool includeDocument = true;
                        foreach (string documentToExclude in documentsToExclude)
                        {
                            if (document.FilePath.EndsWith(documentToExclude, StringComparison.CurrentCultureIgnoreCase))
                            {
                                includeDocument = false;
                                break;
                            }
                        }

                        if (includeDocument)
                        {
                            documentsToProcess.Add(document);
                        }
                    }

                    cgfDocuments.AddRange(ProcessDocuments(reporter, documentsToProcess, project));
                }

                reporter.LogInfo($"Parsing complete");

                Dictionary <string, string>        typeNameToPathMap = new Dictionary <string, string>();
                Dictionary <string, CGFTypeSymbol> typeNameToTypeMap = new Dictionary <string, CGFTypeSymbol>();
                foreach (CGFDocument cgfDocument in cgfDocuments)
                {
                    using (reporter.CreateContextScope(CGFParserReporterContext.Type.File, cgfDocument.DocumentFilePath))
                    {
                        foreach (CGFTypeSymbol cgfType in cgfDocument.Types)
                        {
                            using (reporter.CreateContextScope(CGFParserReporterContext.Type.Type, cgfType.Name))
                            {
                                if (typeNameToPathMap.ContainsKey(cgfType.Name))
                                {
                                    reporter.LogError($"Duplicate type {cgfType.Name} found. Other instance found in {typeNameToPathMap[cgfType.Name]}");
                                }
                                else
                                {
                                    typeNameToPathMap.Add(cgfType.Name, cgfDocument.DocumentFilePath);
                                    typeNameToTypeMap.Add(cgfType.Name, cgfType);
                                }
                            }
                        }
                    }
                }

                foreach (CGFTypeSymbol type in typeNameToTypeMap.Values)
                {
                    foreach (CGFFieldSymbol field in type.Fields)
                    {
                        CGFTypeSymbol typeSymbol = null;
                        if (typeNameToTypeMap.TryGetValue(field.TypeName, out typeSymbol))
                        {
                            field.TypeSymbol = typeSymbol;
                        }
                    }
                }

                cgfParser.m_Documents         = cgfDocuments;
                cgfParser.m_TypeNameToPathMap = typeNameToPathMap;

                return(cgfParser);
            }
        }