Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -714,9 +714,95 @@ internal static string EscapeString(string value) => value.Replace("\\", "\\\\")
.Replace("\t", "\\t")
.Replace("\"", "\\\"");

private bool GetConfigAccessSpecifier(NamedDecl namedDecl, out AccessSpecifier name)
{
name = AccessSpecifier.Public;
string access;

// Top level declarations only
if(namedDecl is FieldDecl)
{
return false;
}

if(namedDecl is FunctionDecl)
{
if (TryGetValue($"{_config.Namespace}.{_config.MethodClassName}.{namedDecl.Name}", out access) || TryGetValue($"{_config.MethodClassName}.{namedDecl.Name}", out access))
{
return GetAccess(access, out name, namedDecl);
}
}

if (TryGetValue($"{_config.Namespace}.{namedDecl.Name}", out access) || TryGetValue(namedDecl.Name, out access) || TryGetValue("*", out access))
{
return GetAccess(access, out name, namedDecl);
}

return false;

bool TryGetValue(string key, out string value)
{
return _config.AccessValues.TryGetValue(key, out value);
}

bool GetAccess(string access, out AccessSpecifier name, NamedDecl namedDecl)
{
string lowerAccess = access.ToLower();
switch(lowerAccess)
{
case "public":
{
name = AccessSpecifier.Public;
return true;
}

case "protected":
{
name = AccessSpecifier.Protected;
return true;
}

case "protectedinternal":
{
name = AccessSpecifier.ProtectedInternal;
return true;
}

case "internal":
{
name = AccessSpecifier.Internal;
return true;
}

case "privateprotected":
{
name = AccessSpecifier.PrivateProtected;
return true;
}

case "private":
{
name = AccessSpecifier.Private;
return true;
}

default:
{
name = AccessSpecifier.Internal;
AddDiagnostic(DiagnosticLevel.Warning, $"Unknown access specifier: '{access}' for '{namedDecl}'. Ignoring specifier.", namedDecl);
return false;
}
}
}
}

private AccessSpecifier GetAccessSpecifier(NamedDecl namedDecl)
{
AccessSpecifier name;
if(GetConfigAccessSpecifier(namedDecl, out name))
{
return name;
}

switch (namedDecl.Access)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public sealed class PInvokeGeneratorConfiguration
{
private const string DefaultMethodClassName = "Methods";

private readonly Dictionary<string, string> _accessValues;
private readonly Dictionary<string, string> _remappedNames;
private readonly Dictionary<string, IReadOnlyList<string>> _withAttributes;
private readonly Dictionary<string, string> _withCallConvs;
Expand All @@ -20,7 +21,7 @@ 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<string, string> remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, IReadOnlyDictionary<string, string> withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null)
public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, string testOutputLocation, PInvokeGeneratorOutputMode outputMode = PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, IReadOnlyDictionary<string, string> accessValues = null, string[] excludedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary<string, string> remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, IReadOnlyDictionary<string, string> withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null)
{
if (excludedNames is null)
{
Expand Down Expand Up @@ -83,6 +84,7 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s
}

_options = options;
_accessValues = new Dictionary<string, string>();
_remappedNames = new Dictionary<string, string>();
_withAttributes = new Dictionary<string, IReadOnlyList<string>>();
_withCallConvs = new Dictionary<string, string>();
Expand Down Expand Up @@ -122,6 +124,7 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s
}
}

AddRange(_accessValues, accessValues);
AddRange(_remappedNames, remappedNames);
AddRange(_withAttributes, withAttributes);
AddRange(_withCallConvs, withCallConvs);
Expand Down Expand Up @@ -204,6 +207,8 @@ public bool ExcludeFnptrCodegen

public bool GenerateSourceLocationAttribute => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);

public IReadOnlyDictionary<string, string> AccessValues => _accessValues;

public string MethodClassName { get; }

public string MethodPrefixToStrip { get;}
Expand Down
18 changes: 17 additions & 1 deletion sources/ClangSharpPInvokeGenerator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public static async Task<int> Main(params string[] args)
Handler = CommandHandler.Create(typeof(Program).GetMethod(nameof(Run)))
};

AddAccessOption(s_rootCommand);
AddAdditionalOption(s_rootCommand);
AddConfigOption(s_rootCommand);
AddDefineMacroOption(s_rootCommand);
Expand Down Expand Up @@ -118,6 +119,7 @@ public static async Task<int> Main(params string[] args)

public static int Run(InvocationContext context)
{
var accessValuePairs = context.ParseResult.ValueForOption<string[]>("--access");
var additionalArgs = context.ParseResult.ValueForOption<string[]>("--additional");
var configSwitches = context.ParseResult.ValueForOption<string[]>("--config");
var defineMacros = context.ParseResult.ValueForOption<string[]>("--define-macro");
Expand Down Expand Up @@ -161,6 +163,7 @@ public static int Run(InvocationContext context)
errorList.Add("Error: No output file location provided. Use --output or -o");
}

ParseKeyValuePairs(accessValuePairs, errorList, out Dictionary<string, string> accessValues);
ParseKeyValuePairs(remappedNameValuePairs, errorList, out Dictionary<string, string> remappedNames);
ParseKeyValuePairs(withAttributeNameValuePairs, errorList, out Dictionary<string, IReadOnlyList<string>> withAttributes);
ParseKeyValuePairs(withCallConvNameValuePairs, errorList, out Dictionary<string, string> withCallConvs);
Expand Down Expand Up @@ -474,7 +477,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, withAttributes, withCallConvs, withLibraryPath, withSetLastErrors, withTypes, withUsings);
var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, testOutputLocation, outputMode, configOptions, accessValues, excludedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAttributes, withCallConvs, withLibraryPath, withSetLastErrors, withTypes, withUsings);

if (config.GenerateMacroBindings)
{
Expand Down Expand Up @@ -621,6 +624,19 @@ private static void ParseKeyValuePairs(string[] keyValuePairs, List<string> erro
}
}

private static void AddAccessOption(RootCommand rootCommand)
{
var option = new Option(
aliases: new string[] { "--access", "-ac" },
description: "Type visibility to use during binding generation.",
argumentType: typeof(string),
getDefaultValue: Array.Empty<string>,
arity: ArgumentArity.OneOrMore
);

rootCommand.AddOption(option);
}

private static void AddAdditionalOption(RootCommand rootCommand)
{
var option = new Option(
Expand Down