Пример #1
0
        public void BasicWrapper(string name)
        {
            // Create a unique directory
            var dir = Path.GetRandomFileName();

            _ = Directory.CreateDirectory(dir);

            try
            {
                // Create a file with the right name
                var file = new FileInfo(Path.Combine(dir, name + ".c"));
                File.WriteAllText(file.FullName, "int main() { return 0; }");

                var index               = CXIndex.Create();
                var translationUnit     = CXTranslationUnit.Parse(index, file.FullName, Array.Empty <string>(), Array.Empty <CXUnsavedFile>(), CXTranslationUnit_Flags.CXTranslationUnit_None);
                var clangFile           = translationUnit.GetFile(file.FullName);
                var clangFileName       = clangFile.Name;
                var clangFileNameString = clangFileName.CString;

                Assert.Equal(file.FullName, clangFileNameString);
            }
            finally
            {
                Directory.Delete(dir, true);
            }
        }
Пример #2
0
        private async Task ValidateGeneratedBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions configOptions, string[] excludedNames, IReadOnlyDictionary <string, string> remappedNames, IReadOnlyDictionary <string, IReadOnlyList <string> > withAttributes, IReadOnlyDictionary <string, string> withCallConvs, IReadOnlyDictionary <string, string> withLibraryPaths, string[] withSetLastErrors, IReadOnlyDictionary <string, string> withTypes, IReadOnlyDictionary <string, IReadOnlyList <string> > withUsings, IEnumerable <Diagnostic> expectedDiagnostics, string libraryPath)
        {
            Assert.True(File.Exists(DefaultInputFileName));

            using var outputStream = new MemoryStream();
            using var unsavedFile  = CXUnsavedFile.Create(DefaultInputFileName, inputContents);

            var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
            var config       = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, configOptions, excludedNames, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings);

            using (var pinvokeGenerator = new PInvokeGenerator(config, (path) => outputStream))
            {
                var handle = CXTranslationUnit.Parse(pinvokeGenerator.IndexHandle, DefaultInputFileName, DefaultClangCommandLineArgs, unsavedFiles, DefaultTranslationUnitFlags);
                using var translationUnit = TranslationUnit.GetOrCreate(handle);

                pinvokeGenerator.GenerateBindings(translationUnit);

                if (expectedDiagnostics is null)
                {
                    Assert.Empty(pinvokeGenerator.Diagnostics);
                }
                else
                {
                    Assert.Equal(expectedDiagnostics, pinvokeGenerator.Diagnostics);
                }
            }
            outputStream.Position = 0;

            var actualOutputContents = await new StreamReader(outputStream).ReadToEndAsync();

            Assert.Equal(expectedOutputContents, actualOutputContents);
        }
Пример #3
0
        protected static TranslationUnit CreateTranslationUnit(string inputContents)
        {
            Assert.True(File.Exists(DefaultInputFileName));

            using var unsavedFile = CXUnsavedFile.Create(DefaultInputFileName, inputContents);
            var unsavedFiles = new CXUnsavedFile[] { unsavedFile };

            var index           = CXIndex.Create();
            var translationUnit = CXTranslationUnit.Parse(index, DefaultInputFileName, DefaultClangCommandLineArgs, unsavedFiles, DefaultTranslationUnitFlags);

            if (translationUnit.NumDiagnostics != 0)
            {
                var errorDiagnostics = new StringBuilder();
                _ = errorDiagnostics.AppendLine($"The provided {nameof(CXTranslationUnit)} has the following diagnostics which prevent its use:");
                var invalidTranslationUnitHandle = false;

                for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
                {
                    using var diagnostic = translationUnit.GetDiagnostic(i);

                    if (diagnostic.Severity is CXDiagnosticSeverity.CXDiagnostic_Error or CXDiagnosticSeverity.CXDiagnostic_Fatal)
                    {
                        invalidTranslationUnitHandle = true;
                        _ = errorDiagnostics.Append(' ', 4);
                        _ = errorDiagnostics.AppendLine(diagnostic.Format(CXDiagnosticDisplayOptions.CXDiagnostic_DisplayOption).ToString());
                    }
                }

                Assert.False(invalidTranslationUnitHandle, errorDiagnostics.ToString());
            }

            return(TranslationUnit.GetOrCreate(translationUnit));
        }
Пример #4
0
    public void Run(string[] args, CodeBuilder result)
    {
        ParseCommandLineArgs(args, out var commandLineArgs, out var sourceContents);

        using (var unsavedFile = CXUnsavedFile.Create("Source", sourceContents))
            using (var index = Index.Create(false, true))
            {
                var unsavedFiles = new CXUnsavedFile[] { unsavedFile };

                var handle = CXTranslationUnit.Parse(
                    index.Handle,
                    unsavedFile.FilenameString,
                    commandLineArgs,
                    unsavedFiles,
                    CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes    // Include attributed types in CXType
                    | CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes // Implicit attributes should be visited
                    | CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies
                    );

                var translationUnit = TranslationUnit.GetOrCreate(handle);

                CheckTranslationUnitErrors(translationUnit, sourceContents);
                VisitTranslationUnit(translationUnit);
            }

        WriteNamespace(result);
    }
Пример #5
0
        public unsafe void GenerateTypes(string libraryName = "imobiledevice")
        {
            string[] arguments =
            {
                // Use the C++ backend
                "-x",
                "c++",

                // Parse the doxygen comments
                "-Wdocumentation",

                // Target 32-bit OS
                "-m32"
            };

            arguments = arguments.Concat(this.IncludeDirectories.Select(x => "-I" + x)).ToArray();

            FunctionVisitor functionVisitor;

            using (var createIndex = ClangSharp.Index.Create(false, true))
                using (var translationUnit = CXTranslationUnit.Parse(createIndex.Handle, this.InputFile, arguments, null, CXTranslationUnit_Flags.CXTranslationUnit_None))
                {
                    StringWriter errorWriter    = new StringWriter();
                    var          set            = translationUnit.DiagnosticSet;
                    var          numDiagnostics = set.NumDiagnostics;

                    bool hasError   = false;
                    bool hasWarning = false;

                    for (uint i = 0; i < numDiagnostics; ++i)
                    {
                        CXDiagnostic diagnostic = set.GetDiagnostic(i);
                        var          severity   = diagnostic.Severity;

                        switch (severity)
                        {
                        case CXDiagnosticSeverity.CXDiagnostic_Error:
                        case CXDiagnosticSeverity.CXDiagnostic_Fatal:
                            hasError = true;
                            break;

                        case CXDiagnosticSeverity.CXDiagnostic_Warning:
                            hasWarning = true;
                            break;
                        }

                        var location = diagnostic.Location;

                        location.GetFileLocation(out CXFile file, out uint line, out _, out _);
                        var fileName = file.Name.CString;

                        var message = diagnostic.Spelling.CString;
                        errorWriter.WriteLine($"{severity}: {fileName}:{line} {message}");
                    }

                    if (hasError)
                    {
                        throw new Exception(errorWriter.ToString());
                    }

                    if (hasWarning)
                    {
                        // Dump the warnings to the console output.
                        Console.WriteLine(errorWriter.ToString());
                    }

                    // Generate the marhaler types for string arrays (char **)
                    var arrayMarshalerGenerator = new ArrayMarshalerGenerator(this);
                    arrayMarshalerGenerator.Generate();

                    // Creates enums
                    var enumVisitor     = new EnumVisitor(this);
                    var realEnumVisitor = new DelegatingCXCursorVisitor(enumVisitor.Visit);
                    translationUnit.Cursor.VisitChildren(realEnumVisitor.Visit, new CXClientData());

                    // Creates structs
                    var structVisitor     = new StructVisitor(this);
                    var realStructVisitor = new DelegatingCXCursorVisitor(structVisitor.Visit);
                    translationUnit.Cursor.VisitChildren(realStructVisitor.Visit, new CXClientData());

                    // Creates safe handles & delegates
                    var typeDefVisitor     = new TypeDefVisitor(this);
                    var realTypeDefVisitor = new DelegatingCXCursorVisitor(typeDefVisitor.Visit);
                    translationUnit.Cursor.VisitChildren(realTypeDefVisitor.Visit, new CXClientData());

                    // Creates functions in a NativeMethods class
                    functionVisitor = new FunctionVisitor(this, libraryName);
                    var realFunctionVisitor = new DelegatingCXCursorVisitor(functionVisitor.Visit);
                    translationUnit.Cursor.VisitChildren(realFunctionVisitor.Visit, new CXClientData());

                    createIndex.Dispose();
                }

            // Update the SafeHandle to call the _free method
            var handles = this.Types.Where(t => t.Name.EndsWith("Handle"));

            foreach (var handle in handles)
            {
                var freeMethod = functionVisitor.NativeMethods.Members
                                 .OfType <CodeMemberMethod>()
                                 .Where(m =>
                                        (m.Name.EndsWith("_free") || m.Name.EndsWith("_disconnect")) &&
                                        m.Parameters.Count == 1 &&
                                        m.Parameters[0].Type.BaseType == handle.Name)
                                 .SingleOrDefault();

                if (freeMethod == null)
                {
                    continue;
                }

                var type = (HandleType)((NustacheGeneratedType)handle).Type;
                type.ReleaseMethodName         = freeMethod.Name;
                type.ReleaseMethodReturnsValue = freeMethod.ReturnType.BaseType != "System.Void";

                // Directly pass the IntPtr, becuase the handle itself will already be in the 'closed' state
                // when this method is called.
                freeMethod.Parameters[0].Type      = new CodeTypeReference(typeof(IntPtr));
                freeMethod.Parameters[0].Direction = FieldDirection.In;
            }

            // Extract the API interface and class, as well as the Exception class. Used for DI.
            ApiExtractor extractor = new ApiExtractor(this, functionVisitor);

            extractor.Generate();

            // Add the 'Error' extension IsError and ThrowOnError extension methods
            var extensionsExtractor = new ErrorExtensionExtractor(this, functionVisitor);

            extensionsExtractor.Generate();

            // Patch the native methods to be compatible with .NET Core - basically,
            // do the marshalling ourselves
            NativeMethodOverloadGenerator.Generate(this);
        }
Пример #6
0
        public static int Run(InvocationContext context)
        {
            var additionalArgs = context.ParseResult.ValueForOption <string[]>("additional");
            var config         = new ConfigurationOptions(context.ParseResult.ValueForOption <string[]>("config"))
            {
                ExcludedFunctions   = context.ParseResult.ValueForOption <string[]>("excludeFunction"),
                LibraryPath         = context.ParseResult.ValueForOption <string>("libraryPath"),
                MethodClassName     = context.ParseResult.ValueForOption <string>("methodClassName"),
                Namespace           = context.ParseResult.ValueForOption <string>("namespace"),
                OutputLocation      = context.ParseResult.ValueForOption <string>("output"),
                MethodPrefixToStrip = context.ParseResult.ValueForOption <string>("prefixStrip"),
            };
            var defines     = context.ParseResult.ValueForOption <string[]>("define");
            var files       = context.ParseResult.ValueForOption <string[]>("file");
            var includeDirs = context.ParseResult.ValueForOption <string[]>("include");

            var errorList = new List <string>();

            if (!files.Any())
            {
                errorList.Add("Error: No input C/C++ files provided. Use --file or -f");
            }

            if (string.IsNullOrWhiteSpace(config.Namespace))
            {
                errorList.Add("Error: No namespace provided. Use --namespace or -n");
            }

            if (string.IsNullOrWhiteSpace(config.OutputLocation))
            {
                errorList.Add("Error: No output file location provided. Use --output or -o");
            }

            if (string.IsNullOrWhiteSpace(config.LibraryPath))
            {
                errorList.Add("Error: No library path location provided. Use --libraryPath or -l");
            }

            if (errorList.Any())
            {
                foreach (var error in errorList)
                {
                    context.Console.Error.WriteLine(error);
                }
                context.Console.Error.WriteLine();

                new HelpBuilder(context.Console).Write(s_rootCommand);
                return(-1);
            }

            var arr = new string[]
            {
                "-xc++",                                // The input files are C++
                "-Wno-pragma-once-outside-header"       // We are processing files which may be header files
            };

            arr = arr.Concat(includeDirs.Select(x => "-I" + x)).ToArray();
            arr = arr.Concat(defines.Select(x => "-D" + x)).ToArray();
            arr = arr.Concat(additionalArgs).ToArray();

            var translationFlags = CXTranslationUnit_Flags.CXTranslationUnit_None;

            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;                   // Don't traverse function bodies
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes;               // Include attributed types in CXType
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes;              // Implicit attributes should be visited

            using (var createIndex = CXIndex.Create())
                using (var cursorWriter = new CursorWriter(config))
                {
                    foreach (var file in files)
                    {
                        var  translationUnitError = CXTranslationUnit.Parse(createIndex, file, arr, Array.Empty <CXUnsavedFile>(), translationFlags, out CXTranslationUnit translationUnitHandle);
                        bool skipProcessing       = false;

                        if (translationUnitError != CXErrorCode.CXError_Success)
                        {
                            Console.WriteLine($"Error: Parsing failed for '{file}' due to '{translationUnitError}'.");
                            skipProcessing = true;
                        }
                        else if (translationUnitHandle.NumDiagnostics != 0)
                        {
                            Console.WriteLine($"Diagnostics for '{file}':");

                            for (uint i = 0; i < translationUnitHandle.NumDiagnostics; ++i)
                            {
                                using (var diagnostic = translationUnitHandle.GetDiagnostic(i))
                                {
                                    Console.Write("    ");
                                    Console.WriteLine(diagnostic.Format(CXDiagnosticDisplayOptions.CXDiagnostic_DisplayOption).ToString());

                                    skipProcessing |= (diagnostic.Severity == CXDiagnosticSeverity.CXDiagnostic_Error);
                                    skipProcessing |= (diagnostic.Severity == CXDiagnosticSeverity.CXDiagnostic_Fatal);
                                }
                            }
                        }

                        if (skipProcessing)
                        {
                            Console.WriteLine($"Skipping '{file}' due to one or more errors listed above.");
                            Console.WriteLine();
                            continue;
                        }

                        using (translationUnitHandle)
                        {
                            var translationUnit = new TranslationUnit(translationUnitHandle.Cursor);
                            translationUnit.Visit(clientData: default);
Пример #7
0
        /// <summary>
        /// Private method parsing file or content.
        /// </summary>
        /// <param name="cppFiles">A list of path to C/C++ header files on the disk to parse</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <returns>The result of the compilation</returns>
        private static CppCompilation ParseInternal(List <CppFileOrString> cppFiles, CppParserOptions options = null)
        {
            if (cppFiles == null)
            {
                throw new ArgumentNullException(nameof(cppFiles));
            }

            options = options ?? new CppParserOptions();

            var arguments = new List <string>();

            // Make sure that paths are absolute
            var normalizedIncludePaths = new List <string>();

            normalizedIncludePaths.AddRange(options.IncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            var normalizedSystemIncludePaths = new List <string>();

            normalizedSystemIncludePaths.AddRange(options.SystemIncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            arguments.AddRange(options.AdditionalArguments);
            arguments.AddRange(normalizedIncludePaths.Select(x => $"-I{x}"));
            arguments.AddRange(normalizedSystemIncludePaths.Select(x => $"-isystem{x}"));
            arguments.AddRange(options.Defines.Select(x => $"-D{x}"));

            if (options.ParseAsCpp && !arguments.Contains("-xc++"))
            {
                arguments.Add("-xc++");
            }

            if (!arguments.Any(x => x.StartsWith("--target=")))
            {
                arguments.Add($"--target={GetTripleFromOptions(options)}");
            }

            if (options.ParseComments)
            {
                arguments.Add("-fparse-all-comments");
            }

            var translationFlags = CXTranslationUnit_Flags.CXTranslationUnit_None;

            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;                   // Don't traverse function bodies
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes;               // Include attributed types in CXType
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes;              // Implicit attributes should be visited

            if (options.ParseMacros)
            {
                translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;
            }

            var argumentsArray = arguments.ToArray();

            using (var createIndex = CXIndex.Create())
            {
                var builder = new CppModelBuilder {
                    AutoSquashTypedef = options.AutoSquashTypedef
                };
                var compilation = builder.RootCompilation;

                string rootFileName    = CppAstRootFileName;
                string rootFileContent = null;

                // Build the root input source file
                var tempBuilder = new StringBuilder();
                if (options.PreHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PreHeaderText);
                }

                foreach (var file in cppFiles)
                {
                    if (file.Content != null)
                    {
                        tempBuilder.AppendLine(file.Content);
                    }
                    else
                    {
                        var filePath = Path.Combine(Environment.CurrentDirectory, file.Filename);
                        tempBuilder.AppendLine($"#include \"{filePath}\"");
                    }
                }

                if (options.PostHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PostHeaderText);
                }

                // TODO: Add debug
                rootFileContent = tempBuilder.ToString();

                compilation.InputText = rootFileContent;

                {
                    CXTranslationUnit translationUnit;
                    CXErrorCode       translationUnitError;

                    translationUnitError = CXTranslationUnit.Parse(createIndex, rootFileName, argumentsArray, new CXUnsavedFile[] { new CXUnsavedFile()
                                                                                                                                    {
                                                                                                                                        Contents = rootFileContent,
                                                                                                                                        Filename = rootFileName,
                                                                                                                                        Length   = (uint)Encoding.UTF8.GetByteCount(rootFileContent)
                                                                                                                                    } }, translationFlags, out translationUnit);

                    bool skipProcessing = false;

                    if (translationUnitError != CXErrorCode.CXError_Success)
                    {
                        compilation.Diagnostics.Error($"Parsing failed due to '{translationUnitError}'", new CppSourceLocation(rootFileName, 0, 1, 1));
                        skipProcessing = true;
                    }
                    else if (translationUnit.NumDiagnostics != 0)
                    {
                        for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
                        {
                            using (var diagnostic = translationUnit.GetDiagnostic(i))
                            {
                                CppSourceLocation location;
                                var message = GetMessageAndLocation(rootFileContent, diagnostic, out location);

                                switch (diagnostic.Severity)
                                {
                                case CXDiagnosticSeverity.CXDiagnostic_Ignored:
                                case CXDiagnosticSeverity.CXDiagnostic_Note:
                                    compilation.Diagnostics.Info(message, location);
                                    break;

                                case CXDiagnosticSeverity.CXDiagnostic_Warning:
                                    compilation.Diagnostics.Warning(message, location);
                                    break;

                                case CXDiagnosticSeverity.CXDiagnostic_Error:
                                case CXDiagnosticSeverity.CXDiagnostic_Fatal:
                                    compilation.Diagnostics.Error(message, location);
                                    skipProcessing = true;
                                    break;
                                }
                            }
                        }
                    }

                    if (skipProcessing)
                    {
                        compilation.Diagnostics.Warning($"Compilation aborted due to one or more errors listed above.", new CppSourceLocation(rootFileName, 0, 1, 1));
                    }
                    else
                    {
                        using (translationUnit)
                        {
                            translationUnit.Cursor.VisitChildren(builder.VisitTranslationUnit, clientData: default);
                        }
                    }
                }

                return(compilation);
            }
        }
Пример #8
0
        /// <summary>
        /// Private method parsing file or content.
        /// </summary>
        /// <param name="cppFiles">A list of path to C/C++ header files on the disk to parse</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <returns>The result of the compilation</returns>
        private static unsafe CppCompilation ParseInternal(List <CppFileOrString> cppFiles, CppParserOptions options = null)
        {
            if (cppFiles == null)
            {
                throw new ArgumentNullException(nameof(cppFiles));
            }

            options = options ?? new CppParserOptions();

            var arguments = new List <string>();

            // Make sure that paths are absolute
            var normalizedIncludePaths = new List <string>();

            normalizedIncludePaths.AddRange(options.IncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            var normalizedSystemIncludePaths = new List <string>();

            normalizedSystemIncludePaths.AddRange(options.SystemIncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            arguments.AddRange(options.AdditionalArguments);
            arguments.AddRange(normalizedIncludePaths.Select(x => $"-I{x}"));
            arguments.AddRange(normalizedSystemIncludePaths.Select(x => $"-isystem{x}"));
            arguments.AddRange(options.Defines.Select(x => $"-D{x}"));

            arguments.Add("-dM");
            arguments.Add("-E");

            if (options.ParseAsCpp && !arguments.Contains("-xc++"))
            {
                arguments.Add("-xc++");
            }

            if (!arguments.Any(x => x.StartsWith("--target=")))
            {
                arguments.Add($"--target={GetTripleFromOptions(options)}");
            }

            if (options.ParseComments)
            {
                arguments.Add("-fparse-all-comments");
            }

            var translationFlags = CXTranslationUnit_Flags.CXTranslationUnit_None;

            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;                   // Don't traverse function bodies
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes;               // Include attributed types in CXType
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes;              // Implicit attributes should be visited

            if (options.ParseMacros)
            {
                translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;
            }
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;

            var argumentsArray = arguments.ToArray();

            using (var createIndex = CXIndex.Create())
            {
                var builder = new CppModelBuilder
                {
                    AutoSquashTypedef     = options.AutoSquashTypedef,
                    ParseSystemIncludes   = options.ParseSystemIncludes,
                    ParseAttributeEnabled = options.ParseAttributes,
                };
                var compilation = builder.RootCompilation;

                string rootFileName    = CppAstRootFileName;
                string rootFileContent = null;

                // Creates a fake 'header.hpp' that includes all the files we passed, so they are parsed all at once

                // Build the root input source file
                var tempBuilder = new StringBuilder();
                if (options.PreHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PreHeaderText);
                }

                foreach (var file in cppFiles)
                {
                    if (file.Content != null)
                    {
                        tempBuilder.AppendLine(file.Content);
                    }
                    else
                    {
                        var filePath = Path.Combine(Environment.CurrentDirectory, file.Filename);
                        tempBuilder.AppendLine($"#include \"{filePath}\"");
                    }
                }

                if (options.PostHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PostHeaderText);
                }

                // TODO: Add debug
                rootFileContent = tempBuilder.ToString();

                var rootFileContentUTF8 = Encoding.UTF8.GetBytes(rootFileContent);
                compilation.InputText = rootFileContent;

                fixed(void *rootFileContentUTF8Ptr = rootFileContentUTF8)
                {
                    CXTranslationUnit translationUnit;

                    var rootFileNameUTF8 = Marshal.StringToHGlobalAnsi(rootFileName);

                    translationUnit = CXTranslationUnit.Parse(createIndex, rootFileName, argumentsArray, new CXUnsavedFile[]
                    {
                        new CXUnsavedFile()
                        {
                            Contents = (sbyte *)rootFileContentUTF8Ptr,
                            Filename = (sbyte *)rootFileNameUTF8,
                            Length   = new UIntPtr((uint)rootFileContentUTF8.Length)
                        }
                    }, translationFlags);

                    // Skips the processing of the file if 1 error is raised
                    // We don't want that, so remove that part

                    //bool skipProcessing = false;

                    //if (translationUnit.NumDiagnostics != 0)
                    //{
                    //    for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
                    //    {
                    //        using (var diagnostic = translationUnit.GetDiagnostic(i))
                    //        {
                    //            var message = GetMessageAndLocation(rootFileContent, diagnostic, out var location);

                    //            switch (diagnostic.Severity)
                    //            {
                    //                case CXDiagnosticSeverity.CXDiagnostic_Ignored:
                    //                case CXDiagnosticSeverity.CXDiagnostic_Note:
                    //                    compilation.Diagnostics.Info(message, location);
                    //                    break;
                    //                case CXDiagnosticSeverity.CXDiagnostic_Warning:
                    //                    compilation.Diagnostics.Warning(message, location);
                    //                    break;
                    //                case CXDiagnosticSeverity.CXDiagnostic_Error:
                    //                case CXDiagnosticSeverity.CXDiagnostic_Fatal:
                    //                    compilation.Diagnostics.Error(message, location);
                    //                    skipProcessing = true;
                    //                    break;
                    //            }
                    //        }
                    //    }
                    //}

                    //if (skipProcessing)
                    //{
                    //    compilation.Diagnostics.Warning($"Compilation aborted due to one or more errors listed above.", new CppSourceLocation(rootFileName, 0, 1, 1));
                    //}
                    //else
                    //{
                    using (translationUnit)
                    {
                        translationUnit.Cursor.VisitChildren(builder.VisitTranslationUnit, clientData: default);
                    }
                    //}
                }

                return(compilation);
            }
        }