From 6d51dbf4f9aad9334d933b66b0186946dc012555 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 13 Nov 2021 02:18:34 -0800 Subject: [PATCH] Adding support for explicitly including members to bind --- .../PInvokeGenerator.cs | 32 +++++++++++++++++-- .../PInvokeGeneratorConfiguration.cs | 10 +++++- sources/ClangSharpPInvokeGenerator/Program.cs | 17 +++++++++- .../PInvokeGeneratorTest.cs | 2 +- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 5dcf30fc..d9261e52 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -362,7 +362,7 @@ static void GenerateNativeTypeNameAttribute(PInvokeGenerator generator) sw.WriteLine(); sw.Write("namespace "); - sw.WriteLine(generator.GetNamespace("NativeTypeName")); + sw.WriteLine(generator.GetNamespace("NativeTypeNameAttribute")); sw.WriteLine('{'); sw.WriteLine(" /// Defines the type of a member as it was used in the native signature."); @@ -449,11 +449,26 @@ static void GenerateTransparentStructs(PInvokeGenerator generator) sw.WriteLine(config.HeaderText); } + var targetNamespace = generator.GetNamespace(name); + sw.WriteLine("using System;"); + + if (kind == PInvokeGeneratorTransparentStructKind.HandleWin32) + { + var handleNamespace = generator.GetNamespace("HANDLE"); + + if (targetNamespace != handleNamespace) + { + sw.Write("using "); + sw.Write(handleNamespace); + sw.WriteLine(';'); + } + } + sw.WriteLine(); sw.Write("namespace "); - sw.WriteLine(generator.GetNamespace(name)); + sw.WriteLine(targetNamespace); sw.WriteLine('{'); sw.Write(" public "); @@ -3577,7 +3592,9 @@ bool IsExcludedByName(Cursor cursor, ref uint isExcludedValue) } } - if (_config.ExcludedNames.Contains(qualifiedName) || _config.ExcludedNames.Contains(qualifiedName.Replace("::", "."))) + var dottedQualifiedName = qualifiedName.Replace("::", "."); + + if (_config.ExcludedNames.Contains(qualifiedName) || _config.ExcludedNames.Contains(dottedQualifiedName)) { if (_config.LogExclusions) { @@ -3626,6 +3643,15 @@ bool IsExcludedByName(Cursor cursor, ref uint isExcludedValue) return true; } + if ((_config.IncludedNames.Length != 0) && !_config.IncludedNames.Contains(qualifiedName) && !_config.IncludedNames.Contains(dottedQualifiedName) && !_config.IncludedNames.Contains(name)) + { + if (_config.LogExclusions) + { + AddDiagnostic(DiagnosticLevel.Info, $"Excluded {kind} '{qualifiedName}' as it was not in the include list"); + } + return true; + } + if ((isExcludedValue & 0b10) != 0) { if (_config.LogExclusions) diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs index a97b2460..ad61527f 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs @@ -25,13 +25,18 @@ public sealed class PInvokeGeneratorConfiguration private PInvokeGeneratorConfigurationOptions _options; - public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, string testOutputLocation, PInvokeGeneratorOutputMode outputMode = PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, IReadOnlyDictionary withNamespaces = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null) + public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, string testOutputLocation, PInvokeGeneratorOutputMode outputMode = PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, string[] includedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, IReadOnlyDictionary withNamespaces = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null) { if (excludedNames is null) { excludedNames = Array.Empty(); } + if (includedNames is null) + { + includedNames = Array.Empty(); + } + if (string.IsNullOrWhiteSpace(libraryPath)) { libraryPath = string.Empty; @@ -101,6 +106,7 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s ExcludedNames = excludedNames; HeaderText = string.IsNullOrWhiteSpace(headerFile) ? string.Empty : File.ReadAllText(headerFile); + IncludedNames = includedNames; LibraryPath = $@"""{libraryPath}"""; MethodClassName = methodClassName; MethodPrefixToStrip = methodPrefixToStrip; @@ -153,6 +159,8 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s public string[] ExcludedNames { get; } + public string[] IncludedNames { get; } + public bool GenerateAggressiveInlining => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateAggressiveInlining); public bool GenerateCompatibleCode => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode); diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs index dafe167b..c2a038c1 100644 --- a/sources/ClangSharpPInvokeGenerator/Program.cs +++ b/sources/ClangSharpPInvokeGenerator/Program.cs @@ -97,6 +97,7 @@ public static async Task Main(params string[] args) AddFileOption(s_rootCommand); AddFileDirectoryOption(s_rootCommand); AddHeaderOption(s_rootCommand); + AddIncludeOption(s_rootCommand); AddIncludeDirectoryOption(s_rootCommand); AddLanguageOption(s_rootCommand); AddLibraryOption(s_rootCommand); @@ -133,6 +134,7 @@ public static int Run(InvocationContext context) var files = context.ParseResult.ValueForOption("--file"); var fileDirectory = context.ParseResult.ValueForOption("--file-directory"); var headerFile = context.ParseResult.ValueForOption("--headerFile"); + var includedNames = context.ParseResult.ValueForOption("--include"); var includeDirectories = context.ParseResult.ValueForOption("--include-directory"); var language = context.ParseResult.ValueForOption("--language"); var libraryPath = context.ParseResult.ValueForOption("--libraryPath"); @@ -530,7 +532,7 @@ public static int Run(InvocationContext context) translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes; // Include attributed types in CXType translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes; // Implicit attributes should be visited - var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, testOutputLocation, outputMode, configOptions, excludedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPath, withNamespaces, withSetLastErrors, withTransparentStructs, withTypes, withUsings); + var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, testOutputLocation, outputMode, configOptions, excludedNames, includedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPath, withNamespaces, withSetLastErrors, withTransparentStructs, withTypes, withUsings); if (config.GenerateMacroBindings) { @@ -810,6 +812,19 @@ private static void AddHeaderOption(RootCommand rootCommand) rootCommand.AddOption(option); } + private static void AddIncludeOption(RootCommand rootCommand) + { + var option = new Option( + aliases: new string[] { "--include", "-i" }, + description: "A declaration name to include in binding generation.", + argumentType: typeof(string), + getDefaultValue: Array.Empty, + arity: ArgumentArity.OneOrMore + ); + + rootCommand.AddOption(option); + } + private static void AddIncludeDirectoryOption(RootCommand rootCommand) { var option = new Option( diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs index ec6fdada..518c572b 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs @@ -64,7 +64,7 @@ private static async Task ValidateGeneratedBindingsAsync(string inputContents, s using var unsavedFile = CXUnsavedFile.Create(DefaultInputFileName, inputContents); var unsavedFiles = new CXUnsavedFile[] { unsavedFile }; - var config = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, outputMode, configOptions, excludedNames, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withNamespaces, withSetLastErrors, withTransparentStructs, withTypes, withUsings); + var config = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, outputMode, configOptions, excludedNames, includedNames: null, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withNamespaces, withSetLastErrors, withTransparentStructs, withTypes, withUsings); using (var pinvokeGenerator = new PInvokeGenerator(config, (path) => outputStream)) {