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);
        }
Example #2
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);
    }
Example #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));
        }
Example #4
0
        /// <summary>
        /// Build the Clang AST
        /// </summary>
        private TranslationUnit BuildClangAST(Configuration config, CXIndex index)
        {
            CXTranslationUnit tu = null;

            using (var section = CreateSection("Building Clang AST"))
            {
                // Assemble the arguments
                var clangArgs = new List <string>()
                {
                    "-Wno-pragma-once-outside-header"
                };

                switch (config.Clang.Language)
                {
                case LanguageEnum.C99:
                    clangArgs.Add("-xc");
                    clangArgs.Add("-std=c99");
                    break;

                case LanguageEnum.Cpp11:
                    clangArgs.Add("-xc++");
                    clangArgs.Add("-std=c++11");
                    break;

                case LanguageEnum.Cpp14:
                    clangArgs.Add("-xc++");
                    clangArgs.Add("-std=c++14");
                    break;

                case LanguageEnum.Cpp17:
                    clangArgs.Add("-xc++");
                    clangArgs.Add("-std=c++17");
                    break;

                default:
                    throw new Exception($"unknown language {config.Clang.Language}");
                }

                clangArgs.AddRange(GetWinSDKDIncludeArgs(config));
                clangArgs.AddRange(GetCxxSTLIncludeArgs(config));

                clangArgs.AddRange(config.Clang.Includes.Select(i => MakeIncludeArg(i)));
                clangArgs.AddRange(config.Clang.Defines.Select((m, v) => $"-D{m}=\"{v}\""));
                clangArgs.AddRange(config.Clang.Arguments.Split(" "));

                var tuFlags = CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;

                // Create the TU source file
                var sourceFiles = new HashSet <string>();
                config.Hook.Descriptions.Values.ToList().ForEach(hook => hook.Input.ForEach(source => sourceFiles.Add(source)));

                var tuFilename = Path.GetFileNameWithoutExtension(string.IsNullOrEmpty(config.Plugin.Name) ? Path.GetTempFileName() : config.Plugin.Name) + ".cpp";
                Logger.Debug($"Clang TU filename: {tuFilename}");

                var tuSource = "#include <" + string.Join(">\n#include <", sourceFiles) + ">";

                Logger.Debug($"Clang TU source:\n  {tuSource.Replace("\n", "\n  ")}");
                using (var tuSourceFile = CXUnsavedFile.Create(tuFilename, tuSource))
                {
                    // Invoke clang to get the TU
                    Logger.Debug($"Clang args: {string.Join(" ", clangArgs)}");
                    var tuError = CXTranslationUnit.TryParse(index, tuSourceFile.FilenameString, clangArgs.ToArray(), new CXUnsavedFile[] { tuSourceFile }, tuFlags, out tu);
                    if (tuError != CXErrorCode.CXError_Success)
                    {
                        throw new Exception($"clang error: failed to generate tanslation unit: {tuError}");
                    }
                }
                section.Done();
            }
            if (tu == null)
            {
                return(null);
            }
            return(TranslationUnit.GetOrCreate(tu));
        }