/// <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; }
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() }); }
public CppClassContainer(CppClass cppClass) { Functions = cppClass.Constructors.Concat(cppClass.Functions).ToList(); Class = cppClass; }
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); }
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};"); } } } }
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); } } }
private async Task ProcessAsync(CppClass item) { await _structBuilder.BuildAsync(new[] { item }); }
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)); }