Пример #1
0
        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);
            }
        }
Пример #2
0
        public static CGFAttributeData Parse(CGFParserReporter reporter, Microsoft.CodeAnalysis.AttributeData attributeData)
        {
            //TODO - Add way to have custom validation for ArrayAttribute to validate variable name actually matches an serialized variable
            Type attributeType     = Type.GetType(attributeData.AttributeClass.ToString(), false);
            Type baseAttributeType = typeof(CGFAttribute);

            if (!attributeType.IsSubclassOf(baseAttributeType))
            {
                reporter.LogInfo($"Unrecognized attribute type {attributeType.Name}. Attributes are expected to be subtypes of {baseAttributeType.Name}.");
                return(null);
            }

            Attribute attribute = null;

            using (reporter.CreateContextScope(CGFParserReporterContext.Type.Type, attributeType.Name))
            {
                System.Reflection.ConstructorInfo[] constructors = attributeType.GetConstructors();
                foreach (System.Reflection.ConstructorInfo constructorInfo in constructors)
                {
                    System.Reflection.ParameterInfo[] parameters = constructorInfo.GetParameters();
                    if (attributeData.ConstructorArguments.Length != parameters.Length)
                    {
                        continue;
                    }

                    bool matchingParameters = true;
                    for (int paramIndex = 0; paramIndex < parameters.Length; ++paramIndex)
                    {
                        Microsoft.CodeAnalysis.TypedConstant cgfTypedConstant = attributeData.ConstructorArguments[paramIndex];
                        System.Reflection.ParameterInfo      parameterInfo    = parameters[paramIndex];

                        Type cgfParameterType = null;
                        if (string.IsNullOrEmpty(cgfTypedConstant.Type.Name))
                        {
                            cgfParameterType = Type.GetType(cgfTypedConstant.Type.Name, false);
                        }
                        else
                        {
                            cgfParameterType = Type.GetType($"{cgfTypedConstant.Type.ContainingSymbol.Name}.{cgfTypedConstant.Type.Name}", false);
                        }

                        if (cgfParameterType != parameterInfo.ParameterType)
                        {
                            matchingParameters = false;
                            break;
                        }
                    }

                    if (matchingParameters)
                    {
                        if (parameters.Length > 0)
                        {
                            Object[] parameterObjects = new Object[parameters.Length];
                            for (int paramIndex = 0; paramIndex < parameters.Length; ++paramIndex)
                            {
                                Microsoft.CodeAnalysis.TypedConstant cgfTypedConstant = attributeData.ConstructorArguments[paramIndex];
                                System.Reflection.ParameterInfo      parameterInfo    = parameters[paramIndex];

                                Object convertedParam = null;
                                if (parameterInfo.ParameterType.IsEnum)
                                {
                                    convertedParam = Enum.ToObject(parameterInfo.ParameterType, cgfTypedConstant.Value);
                                }
                                else
                                {
                                    convertedParam = System.Convert.ChangeType(cgfTypedConstant.Value, parameterInfo.ParameterType);
                                }

                                parameterObjects[paramIndex] = convertedParam;
                            }

                            attribute = Activator.CreateInstance(attributeType, parameterObjects) as Attribute;
                        }
                        else
                        {
                            attribute = Activator.CreateInstance(attributeType) as Attribute;
                        }
                    }
                }

                if (attribute == null)
                {
                    //TODO - Add provided constructor param list to help finding the error.
                    //       List most likely constructors.
                    reporter.LogError($"No matching constructor found for {attributeType.Name}.");
                    return(null);
                }

                CGFAttributeData CGFAttributeData = new CGFAttributeData(attribute, attributeData);
                return(CGFAttributeData);
            }
        }
Пример #3
0
        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);
            }
        }