Пример #1
0
        /// <summary>
        /// Add an entity representation to the given DNA definition
        /// </summary>
        private static void AddEntity(DNA dna, CppClass cstruct, bool includeByRef)
        {
            if (dna.Entities.ContainsKey(cstruct.Name))
            {
                return; // Already added
            }

            if (cstruct.Fields.Count < 1)
            {
                throw new Exception(
                          $"Found stub for [{cstruct.Name}] - may have been excluded from loaded files. " +
                          $"This prevents us from calculating accurate struct sizes while converting."
                          );
            }

            var entity = new Entity
            {
                Type   = EntityType.Struct,
                CType  = cstruct.Name,
                Size   = cstruct.SizeOf,
                Offset = 0,
                Fields = new Dictionary <string, Entity>()
            };

            // Add a nested entity per field - each with an offset from the parent
            // based on their individual byte sizes.
            var offset = 0;

            foreach (var cfield in cstruct.Fields)
            {
                var type  = cfield.Type;
                var field = new Entity();

                // Unwrap a typedef and use the underlying type instead
                if (type is CppTypedef typedef)
                {
                    type = typedef.ElementType;
                }

                if (type is CppPointerType pointer)
                {
                    field.Type   = EntityType.Pointer;
                    field.CType  = pointer.ElementType.GetDisplayName();
                    field.Size   = pointer.SizeOf;
                    field.Offset = offset;
                    offset      += field.Size;
                }
                else if (type is CppArrayType arr)
                {
                    field.Type   = EntityType.Array;
                    field.CType  = arr.ElementType.GetDisplayName();
                    field.Size   = arr.ElementType.SizeOf;
                    field.Count  = arr.Size;
                    field.Offset = offset;
                    offset      += field.Size * field.Count;
                }
                else if (type is CppPrimitiveType primitive)
                {
                    field.Type   = EntityType.Primitive;
                    field.CType  = primitive.GetDisplayName();
                    field.Size   = primitive.SizeOf;
                    field.Offset = offset;
                    offset      += field.Size;
                }
                else if (type is CppClass cls)
                {
                    if (cls.ClassKind != CppClassKind.Struct)
                    {
                        throw new Exception(
                                  $"Cannot parse field [{cstruct.Name}.{cfield.Name}] " +
                                  $"- Type [{cls.ClassKind}] is not supported"
                                  );
                    }

                    field.Type   = EntityType.Struct;
                    field.CType  = cls.GetDisplayName();
                    field.Size   = cls.SizeOf;
                    field.Offset = offset;
                    offset      += field.Size;

                    // Recursively include anything added by-ref if we're configured to.
                    if (includeByRef)
                    {
                        AddEntity(dna, cls, true);
                    }
                }
                else
                {
                    throw new Exception(
                              $"Cannot parse field [{cstruct.Name}.{cfield.Name}] " +
                              $"- Type [{type}] is not supported"
                              );
                }

                entity.Fields[cfield.Name] = field;
            }

            dna.Entities[cstruct.Name] = entity;
        }
Пример #2
0
        private GenerateResult GenerateClass(CppClass cppClass)
        {
            if (cppClass.Name == "Node")
            {
                return(CreateNodeInterface(cppClass));
            }

            var isValue         = cppClass.Name == "Value";
            var usingDirectives = new List <UsingDirectiveSyntax>();

            var csClass = new ClassDeclarationSyntax
            {
                Modifiers  = Modifiers.Internal,
                Identifier = CreateMemberName(cppClass)
            };

            if (_config.NodeTypes.Contains(cppClass.Name))
            {
                if (!isValue)
                {
                    AddPgNodeAttribute(usingDirectives, csClass);
                }

                // .. : IPg10Node
                csClass.BaseList = new BaseListSyntax
                {
                    Types =
                    {
                        Syntax.ParseName(nodeInterfaceName)
                    }
                };

                // IPg10Node::Type
                AddPgNodeTypeProperty(csClass, Modifiers.Virtual);
            }

            var nestedClasses = new List <GenerateResult>();

            foreach (var field in cppClass.Fields)
            {
                string fieldName = field.Name;
                string typeName;

                if (cppClass.Equals(field.Type.Parent))
                {
                    var nestedClass = GenerateClass((CppClass)field.Type);

                    nestedClasses.Add(nestedClass);
                    typeName = nestedClass.Type.Identifier;
                }
                else
                {
                    typeName = ConvertToCSharpType(field.Type);
                }

                // IPg10Node::Type
                if (typeName == "int?" && fieldName == "location" ||
                    typeName == nodeTypeName && fieldName == "type")
                {
                    continue;
                }

                if (SyntaxFacts.GetKeywordKind(fieldName) != SyntaxKind.None)
                {
                    fieldName = $"@{fieldName}";
                }

                csClass.Members.Add(new PropertyDeclarationSyntax
                {
                    Modifiers    = Modifiers.Public,
                    AccessorList = Syntax.AccessorList(
                        Syntax.AccessorDeclaration(AccessorDeclarationKind.Get, null),
                        Syntax.AccessorDeclaration(AccessorDeclarationKind.Set, null)),
                    Identifier = fieldName,
                    Type       = Syntax.ParseName(typeName)
                });
            }

            foreach (var nestedClass in nestedClasses)
            {
                foreach (var usingDirective in nestedClass.UsingDirectives ?? Array.Empty <UsingDirectiveSyntax>())
                {
                    if (usingDirectives.Any(d => d.Name.AreEquals(usingDirective.Name)))
                    {
                        continue;
                    }

                    usingDirectives.Add(usingDirective);
                }

                csClass.Members.Add(nestedClass.Type);
            }

            if (isValue)
            {
                var valueUnion = (ClassDeclarationSyntax)nestedClasses[0].Type;

                var typeProperty = (PropertyDeclarationSyntax)csClass.Members[0];
                PropertyDeclarationSyntax[] members = valueUnion.Members.OfType <PropertyDeclarationSyntax>().ToArray();

                valueUnion.Members.Clear();
                csClass.Members.Clear();

                csClass.Members.Add(typeProperty);

                foreach (var m in members)
                {
                    csClass.Members.Add(m);
                }
            }

            return(new GenerateResult(cppClass)
            {
                Type = csClass,
                UsingDirectives = usingDirectives.ToArray()
            });
        }
Пример #3
0
 public CppClassContainer(CppClass cppClass)
 {
     Functions = cppClass.Constructors.Concat(cppClass.Functions).ToList();
     Class     = cppClass;
 }
Пример #4
0
        public static CSharpElement ConvertClass(CSharpConverter converter, CppClass cppClass, CSharpElement context)
        {
            // This converter supports only plain struct or union
            if (cppClass.ClassKind == CppClassKind.Class && cppClass.Functions.Any(x => (x.Flags & CppFunctionFlags.Virtual) != 0))
            {
                return(null);
            }

            // Register the struct as soon as possible
            var csStructName = converter.GetCSharpName(cppClass, context);
            var csStruct     = new CSharpStruct(csStructName)
            {
                CppElement = cppClass,
            };

            var container = converter.GetCSharpContainer(cppClass, context);

            converter.ApplyDefaultVisibility(csStruct, container);
            if (container is CSharpInterface)
            {
                container = container.Parent;
            }
            container.Members.Add(csStruct);

            csStruct.Comment = converter.GetCSharpComment(cppClass, csStruct);

            bool isUnion = cppClass.ClassKind == CppClassKind.Union;

            // Requires System.Runtime.InteropServices
            csStruct.Attributes.Add(isUnion ?
                                    new CSharpStructLayoutAttribute(LayoutKind.Explicit)
            {
                CharSet = converter.Options.DefaultCharSet
            } :
                                    new CSharpStructLayoutAttribute(LayoutKind.Sequential)
            {
                CharSet = converter.Options.DefaultCharSet
            }
                                    );

            // Required by StructLayout
            converter.AddUsing(container, "System.Runtime.InteropServices");

            if (cppClass.BaseTypes.Count == 1)
            {
                var csBaseType = converter.GetCSharpType(cppClass.BaseTypes[0].Type, context, false);
                csStruct.Members.Add(new CSharpField("@base")
                {
                    FieldType = csBaseType, Visibility = CSharpVisibility.Public
                });
            }

            // For opaque type we use a standard representation
            if (!cppClass.IsDefinition && cppClass.Fields.Count == 0)
            {
                csStruct.Modifiers |= CSharpModifiers.ReadOnly;
                csStruct.BaseTypes.Add(new CSharpFreeType($"IEquatable<{csStruct.Name}>"));

                csStruct.Members.Add(new CSharpLineElement("private readonly IntPtr _handle;"));
                csStruct.Members.Add(new CSharpLineElement($"public {csStruct.Name}(IntPtr handle) => _handle = handle;"));
                csStruct.Members.Add(new CSharpLineElement("public IntPtr Handle => _handle;"));
                csStruct.Members.Add(new CSharpLineElement($"public bool Equals({csStruct.Name} other) => _handle.Equals(other._handle);"));
                csStruct.Members.Add(new CSharpLineElement($"public override bool Equals(object obj) => obj is {csStruct.Name} other && Equals(other);"));
                csStruct.Members.Add(new CSharpLineElement($"public override int GetHashCode() => _handle.GetHashCode();"));
                csStruct.Members.Add(new CSharpLineElement($"public override string ToString() => \"0x\" + (IntPtr.Size == 8 ? _handle.ToString(\"X16\") : _handle.ToString(\"X8\"));"));
                csStruct.Members.Add(new CSharpLineElement($"public static bool operator ==({csStruct.Name} left, {csStruct.Name} right) => left.Equals(right);"));
                csStruct.Members.Add(new CSharpLineElement($"public static bool operator !=({csStruct.Name} left, {csStruct.Name} right) => !left.Equals(right);"));
            }

            // If we have any anonymous structs/unions for a field type
            // try to compute a name for them before processing them
            foreach (var cppField in cppClass.Fields)
            {
                var fieldType = cppField.Type;

                if (fieldType is CppClass cppFieldTypeClass && cppFieldTypeClass.IsAnonymous && string.IsNullOrEmpty(cppFieldTypeClass.Name))
                {
                    var parentName = string.Empty;
                    if (cppFieldTypeClass.Parent is CppClass cppParentClass)
                    {
                        parentName = cppParentClass.Name;
                    }

                    if (cppFieldTypeClass.ClassKind == CppClassKind.Union)
                    {
                        parentName = parentName == string.Empty ? "union" : parentName + "_union";
                    }
                    cppFieldTypeClass.Name = $"{parentName}_{cppField.Name}";
                }
            }

            return(csStruct);
        }
Пример #5
0
        private static void GenerateStructures(CodeWriter writer, CppClass cppClass, bool isUnion, string csName, bool isReadOnly, string modifier)
        {
            if (isUnion)
            {
                writer.WriteLine("[StructLayout(LayoutKind.Explicit)]");
            }
            else
            {
                writer.WriteLine("[StructLayout(LayoutKind.Sequential)]");
            }

            using (writer.PushBlock($"{modifier} struct {csName}"))
            {
                if (generateSizeOfStructs && cppClass.SizeOf > 0)
                {
                    writer.WriteLine($"public static readonly int SizeInBytes = {cppClass.SizeOf};");
                    writer.WriteLine();
                }

                foreach (CppField cppField in cppClass.Fields)
                {
                    string csFieldName = NormalizeFieldName(cppField.Name);

                    if (isUnion)
                    {
                        writer.WriteLine("[FieldOffset(0)]");
                    }

                    if (cppField.Type is CppArrayType arrayType)
                    {
                        bool canUseFixed = false;
                        if (arrayType.ElementType is CppPrimitiveType)
                        {
                            canUseFixed = true;
                        }
                        else if (arrayType.ElementType is CppTypedef typedef &&
                                 typedef.ElementType is CppPrimitiveType)
                        {
                            canUseFixed = true;
                        }

                        if (canUseFixed)
                        {
                            var csFieldType = GetCsTypeName(arrayType.ElementType, false);

                            if (string.IsNullOrEmpty(csFieldType))
                            {
                                Console.WriteLine("");
                            }
                            writer.WriteLine($"public unsafe fixed {csFieldType} {csFieldName}[{arrayType.Size}];");
                        }
                        else
                        {
                            var unsafePrefix = string.Empty;
                            var csFieldType  = GetCsTypeName(arrayType.ElementType, false);
                            if (csFieldType.EndsWith('*'))
                            {
                                unsafePrefix = "unsafe ";
                            }

                            for (var i = 0; i < arrayType.Size; i++)
                            {
                                writer.WriteLine($"public {unsafePrefix}{csFieldType} {csFieldName}_{i};");
                            }
                        }
                    }
                    else
                    {
                        if (!s_csNameMappings.TryGetValue(cppField.Type.GetDisplayName(), out var csFieldType))
                        {
                            csFieldType = GetCsTypeName(cppField.Type, false);
                        }
                        else
                        {
                            Console.Write("");
                        }


                        //                         if (csFieldType.Equals("ImGuiDockNodeSettings*") ||
                        //                             csFieldType.Equals("ImGuiDockRequest*"))
                        //                         {
                        //                             csFieldType = "IntPtr";
                        //                         }

                        string fieldPrefix = isReadOnly ? "readonly " : string.Empty;
                        if (csFieldType.EndsWith('*'))
                        {
                            fieldPrefix += "unsafe ";
                        }

                        writer.WriteLine($"public {fieldPrefix}{csFieldType} {csFieldName};");
                    }
                }
            }
        }
Пример #6
0
        public async Task RunMutationTest(MuTestOptions options)
        {
            try
            {
                if (!File.Exists(MuTestSettings.MSBuildPath))
                {
                    throw new MuTestInputException($"Unable to locate MSBuild Path at {MuTestSettings.MSBuildPath}. Please update MSBuildPath in MuTest.Console.exe.config if you are using different version");
                }

                _stopwatch = new Stopwatch();
                _stopwatch.Start();
                _options = options;

                _chalk.Default("\nPreparing Required Files...\n");

                DirectoryFactory.NumberOfMutantsExecutingInParallel = _options.ConcurrentTestRunners;

                _cppClass = new CppClass
                {
                    Configuration      = _options.Configuration,
                    SourceClass        = _options.SourceClass,
                    Platform           = _options.Platform,
                    TestClass          = _options.TestClass,
                    TestProject        = _options.TestProject,
                    Target             = _options.Target,
                    SourceHeader       = _options.SourceHeader,
                    TestSolution       = _options.TestSolution,
                    IncludeBuildEvents = _options.IncludeBuildEvents
                };

                Context = !_options.InIsolation
                    ? DirectoryFactory.PrepareTestFiles(_cppClass)
                    : DirectoryFactory.PrepareSolutionFiles(_cppClass);

                if (Context.TestContexts.Any())
                {
                    await ExecuteBuild();
                    await ExecuteTests();

                    if (!_options.DisableBuildOptimization)
                    {
                        Context.EnableBuildOptimization = true;
                    }

                    _chalk.Default("\nRunning Mutation Analysis...\n");


                    var defaultMutants = CppMutantOrchestrator.GetDefaultMutants(_options.SourceClass, _options.SpecificLines).ToList();
                    defaultMutants = _aridNodeMutantFilterer.FilterMutants(defaultMutants).ToList();
                    defaultMutants = _mutantsSelector.SelectMutants(_options.MutantsPerLine, defaultMutants).ToList();
                    _cppClass.Mutants.AddRange(defaultMutants);

                    if (_cppClass.CoveredLineNumbers.Any())
                    {
                        foreach (var mutant in _cppClass.Mutants)
                        {
                            if (_cppClass.CoveredLineNumbers.All(x => x != mutant.Mutation.LineNumber))
                            {
                                mutant.ResultStatus = MutantStatus.NotCovered;
                            }
                            else if (mutant.Mutation.EndLineNumber > mutant.Mutation.LineNumber)
                            {
                                if (!_cppClass.CoveredLineNumbers.Any(x => x > mutant.Mutation.LineNumber &&
                                                                      x <= mutant.Mutation.EndLineNumber))
                                {
                                    mutant.ResultStatus = MutantStatus.Skipped;
                                }
                            }
                        }
                    }

                    _chalk.Default($"\nNumber of Mutants: {_cppClass.Mutants.Count}\n");

                    var sourceHash = _cppClass
                                     .SourceClass
                                     .GetCodeFileContent()
                                     .ComputeHash();

                    var testHash = _cppClass
                                   .TestClass
                                   .GetCodeFileContent()
                                   .ComputeHash();

                    _cppClass.Sha256 = (sourceHash + testHash).ComputeHash();

                    var data = await _client.GetFileDataFromStorage(_cppClass.Sha256);

                    _cppClass.StoreInDb = true;

                    if (data != null)
                    {
                        var cppClass = JsonConvert.DeserializeObject <CppClass>(data);
                        cppClass.StoreInDb          = false;
                        cppClass.SourceClass        = _cppClass.SourceClass;
                        cppClass.SourceHeader       = _cppClass.SourceHeader;
                        cppClass.TestClass          = _cppClass.TestClass;
                        cppClass.TestProject        = _cppClass.TestProject;
                        cppClass.Configuration      = _cppClass.Configuration;
                        cppClass.Target             = _cppClass.Target;
                        cppClass.Platform           = _cppClass.Platform;
                        cppClass.TestSolution       = _cppClass.TestSolution;
                        cppClass.IncludeBuildEvents = _cppClass.IncludeBuildEvents;

                        _cppClass = cppClass;
                    }

                    MutantsExecutor = new CppMutantExecutor(_cppClass, Context, MuTestSettings)
                    {
                        EnableDiagnostics = _options.EnableDiagnostics,
                        KilledThreshold   = _options.KilledThreshold,
                        SurvivedThreshold = _options.SurvivedThreshold,
                        NumberOfMutantsExecutingInParallel = _options.ConcurrentTestRunners
                    };

                    _totalMutants   = _cppClass.NotRunMutants.Count;
                    _mutantProgress = 0;

                    if (_cppClass.Mutants.Any() && data == null)
                    {
                        MutantsExecutor.MutantExecuted += MutantAnalyzerOnMutantExecuted;
                        await MutantsExecutor.ExecuteMutants();
                    }

                    await GenerateReports();
                }
            }
            finally
            {
                if (Context != null)
                {
                    DirectoryFactory.DeleteTestFiles(Context);
                }
            }
        }
Пример #7
0
 private async Task ProcessAsync(CppClass item)
 {
     await _structBuilder.BuildAsync(new[] { item });
 }
Пример #8
0
 public CppMutantExecutor(CppClass cpp, CppBuildContext context, MuTestSettings settings)
 {
     _cpp      = cpp ?? throw new ArgumentNullException(nameof(cpp));
     _context  = context ?? throw new ArgumentNullException(nameof(context));
     _settings = settings ?? throw new ArgumentNullException(nameof(settings));
 }