Adding basic support for annotating manual imports

This commit is contained in:
Tanner Gooding 2021-12-18 16:44:58 -08:00
Родитель a43457f221
Коммит fe0a5b3c2f
10 изменённых файлов: 123 добавлений и 50 удалений

Просмотреть файл

@ -50,6 +50,21 @@ namespace ClangSharp.Abstractions
}
}
public bool IsManualImport
{
get
{
return (Flags & FunctionOrDelegateFlags.IsManualImport) != 0;
}
set
{
Flags = value
? Flags | FunctionOrDelegateFlags.IsManualImport
: Flags & ~FunctionOrDelegateFlags.IsManualImport;
}
}
public bool HasFnPtrCodeGen
{
get

Просмотреть файл

@ -30,13 +30,13 @@ namespace ClangSharp.Abstractions
void EndField(in FieldDesc desc);
void BeginFunctionOrDelegate(in FunctionOrDelegateDesc info, ref bool isMethodClassUnsafe);
void BeginFunctionInnerPrototype(string escapedName);
void BeginFunctionInnerPrototype(in FunctionOrDelegateDesc info);
void BeginParameter(in ParameterDesc info);
void BeginParameterDefault();
void EndParameterDefault();
void EndParameter(in ParameterDesc info);
void WriteParameterSeparator();
void EndFunctionInnerPrototype();
void EndFunctionInnerPrototype(in FunctionOrDelegateDesc info);
void BeginConstructorInitializer(string memberRefName, string memberInitName);
void EndConstructorInitializer();
void BeginBody(bool isExpressionBody = false);

Просмотреть файл

@ -15,5 +15,6 @@ namespace ClangSharp.Abstractions
public Action<object> WriteCustomAttrs { get; set; }
public object CustomAttrGeneratorData { get; set; }
public CXSourceLocation? Location { get; set; }
public bool IsForManualImport { get; set; }
}
}

Просмотреть файл

@ -373,7 +373,7 @@ namespace ClangSharp.CSharp
WriteLine(']');
}
else if (desc.IsDllImport)
else if (desc.IsDllImport && !desc.IsManualImport)
{
AddUsingDirective("System.Runtime.InteropServices");
@ -418,7 +418,6 @@ namespace ClangSharp.CSharp
{
WriteIndentedLine("[SetsLastSystemError]");
}
// GenerateSetsLastSystemErrorAttribute
if (desc.IsAggressivelyInlined)
{
@ -433,7 +432,7 @@ namespace ClangSharp.CSharp
AddVtblIndexAttribute(vtblIndex);
}
if (desc.NativeTypeName is not null)
if ((desc.NativeTypeName is not null) && !desc.IsManualImport)
{
AddNativeTypeNameAttribute(desc.NativeTypeName, attributePrefix: "return: ");
}
@ -460,7 +459,7 @@ namespace ClangSharp.CSharp
}
Write("delegate ");
}
else if (desc.IsStatic ?? (desc.IsDllImport || !desc.IsCxx))
else if ((desc.IsStatic ?? (desc.IsDllImport || !desc.IsCxx)) && !desc.IsManualImport)
{
Write("static ");
@ -473,7 +472,6 @@ namespace ClangSharp.CSharp
if (!desc.IsVirtual)
{
//if (NeedsNewKeyword(escapedName, functionDecl.Parameters))
if (desc.NeedsNewKeyword)
{
Write("new ");
@ -481,12 +479,10 @@ namespace ClangSharp.CSharp
if (desc.IsUnsafe)
{
//if (cxxRecordDecl is null)
if (!desc.IsCtxCxxRecord)
{
isMethodClassUnsafe = true;
}
//else if (!IsUnsafe(cxxRecordDecl))
else if (!desc.IsCxxRecordCtxUnsafe)
{
Write("unsafe ");
@ -494,7 +490,7 @@ namespace ClangSharp.CSharp
}
}
if (!desc.IsCxxConstructor)
if (!desc.IsCxxConstructor && !desc.IsManualImport)
{
Write(desc.ReturnType);
Write(' ');
@ -532,35 +528,59 @@ namespace ClangSharp.CSharp
}
}
public void BeginFunctionInnerPrototype(string escapedName)
public void BeginFunctionInnerPrototype(in FunctionOrDelegateDesc desc)
{
Write(escapedName);
Write('(');
if (desc.IsManualImport)
{
Write("delegate* unmanaged");
if (desc.CallingConvention != CallingConvention.Winapi)
{
Write('[');
Write(desc.CallingConvention);
Write(']');
}
Write('<');
}
else
{
Write(desc.EscapedName);
Write('(');
}
}
public void BeginParameter(in ParameterDesc info)
{
if (info.NativeTypeName is not null)
if (info.IsForManualImport)
{
AddNativeTypeNameAttribute(info.NativeTypeName, prefix: "", postfix: " ");
Write(info.Type);
}
if (info.CppAttributes is not null)
else
{
AddCppAttributes(info.CppAttributes, prefix: "", postfix: " ");
}
if (info.NativeTypeName is not null)
{
AddNativeTypeNameAttribute(info.NativeTypeName, prefix: "", postfix: " ");
}
if (info.Location is {} location)
{
WriteSourceLocation(location, true);
}
if (info.CppAttributes is not null)
{
AddCppAttributes(info.CppAttributes, prefix: "", postfix: " ");
}
_customAttrIsForParameter = true;
info.WriteCustomAttrs?.Invoke(info.CustomAttrGeneratorData);
_customAttrIsForParameter = false;
Write(info.Type);
Write(' ');
Write(info.Name);
if (info.Location is { } location)
{
WriteSourceLocation(location, true);
}
_customAttrIsForParameter = true;
info.WriteCustomAttrs?.Invoke(info.CustomAttrGeneratorData);
_customAttrIsForParameter = false;
Write(info.Type);
Write(' ');
Write(info.Name);
}
}
public void BeginParameterDefault() => Write(" = ");
@ -581,7 +601,18 @@ namespace ClangSharp.CSharp
Write(' ');
}
public void EndFunctionInnerPrototype() => Write(')');
public void EndFunctionInnerPrototype(in FunctionOrDelegateDesc desc)
{
if (desc.IsManualImport)
{
Write(desc.ReturnType);
Write('>');
}
else
{
Write(')');
}
}
public void BeginConstructorInitializer(string memberRefName, string memberInitName)
{
@ -646,6 +677,12 @@ namespace ClangSharp.CSharp
public void EndFunctionOrDelegate(in FunctionOrDelegateDesc desc)
{
if (desc.IsManualImport)
{
Write(' ');
Write(desc.EscapedName);
}
if (!desc.HasBody || desc.IsVirtual)
{
WriteSemicolon();

Просмотреть файл

@ -1,4 +1,4 @@
using System;
using System;
namespace ClangSharp
{
@ -20,5 +20,6 @@ namespace ClangSharp
IsNotStatic = 1 << 12,
NeedsReturnFixup = 1 << 13,
IsCxxConstructor = 1 << 14,
IsManualImport = 1 << 15,
}
}

Просмотреть файл

@ -462,6 +462,8 @@ namespace ClangSharp
}
var name = GetRemappedCursorName(functionDecl);
var isManualImport = _config.WithManualImports.Contains(name);
var className = name;
var parentName = "";
@ -491,6 +493,13 @@ namespace ClangSharp
var returnType = functionDecl.ReturnType;
var returnTypeName = GetRemappedTypeName(functionDecl, cxxRecordDecl, returnType, out var nativeTypeName);
if (isManualImport && !_config.WithClasses.ContainsKey(name))
{
var firstParameter = functionDecl.Parameters.FirstOrDefault();
var firstParameterTypeName = (firstParameter is not null) ? GetTargetTypeName(firstParameter, out var _) : "void";
AddDiagnostic(DiagnosticLevel.Warning, $"Found manual import for {name} with no class remapping. First Parameter Type: {firstParameterTypeName}; Return Type: {returnTypeName}", functionDecl);
}
if ((isVirtual || !hasBody) && (returnTypeName == "bool"))
{
// bool is not blittable, so we shouldn't use it for P/Invoke signatures
@ -521,6 +530,7 @@ namespace ClangSharp
LibraryPath = isDllImport ? GetLibraryPath(name).Unquote() : null,
IsVirtual = isVirtual,
IsDllImport = isDllImport,
IsManualImport = isManualImport,
HasFnPtrCodeGen = !_config.ExcludeFnptrCodegen,
SetLastError = GetSetLastError(functionDecl),
IsCxx = isCxxMethodDecl,
@ -552,7 +562,7 @@ namespace ClangSharp
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);
_isTopLevelClassUnsafe[className] = isUnsafe;
_outputBuilder.BeginFunctionInnerPrototype(escapedName);
_outputBuilder.BeginFunctionInnerPrototype(in desc);
if (isVirtual || (isCxxMethodDecl && !hasBody && cxxMethodDecl.IsInstance))
{
@ -593,7 +603,7 @@ namespace ClangSharp
Visit(functionDecl.Parameters);
_outputBuilder.EndFunctionInnerPrototype();
_outputBuilder.EndFunctionInnerPrototype(in desc);
if (hasBody && !isVirtual)
{
@ -983,9 +993,7 @@ namespace ClangSharp
else
{
_ = IsPrevContextDecl<Decl>(out var previousContext, out _);
AddDiagnostic(DiagnosticLevel.Error,
$"Unsupported parameter variable declaration parent: '{previousContext.CursorKindSpelling}'. Generated bindings may be incomplete.",
previousContext);
AddDiagnostic(DiagnosticLevel.Error, $"Unsupported parameter variable declaration parent: '{previousContext.CursorKindSpelling}'. Generated bindings may be incomplete.", previousContext);
}
void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl)
@ -996,6 +1004,9 @@ namespace ClangSharp
var name = GetRemappedCursorName(parmVarDecl);
var escapedName = EscapeName(name);
var functionName = GetRemappedCursorName(functionDecl);
var isForManualImport = _config.WithManualImports.Contains(functionName);
var parameters = functionDecl.Parameters;
var index = parameters.IndexOf(parmVarDecl);
var lastIndex = parameters.Count - 1;
@ -1032,6 +1043,7 @@ namespace ClangSharp
}
},
CustomAttrGeneratorData = (parmVarDecl, this, null as CSharp.CSharpOutputBuilder, null as Expr),
IsForManualImport = isForManualImport
};
var handledDefaultArg = false;
@ -1081,7 +1093,7 @@ namespace ClangSharp
_outputBuilder.EndParameter(in desc);
if (index != lastIndex)
if ((index != lastIndex) || isForManualImport)
{
_outputBuilder.WriteParameterSeparator();
}
@ -1792,11 +1804,11 @@ namespace ClangSharp
var isUnsafe = true;
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);
_outputBuilder.BeginFunctionInnerPrototype(desc.EscapedName);
_outputBuilder.BeginFunctionInnerPrototype(in desc);
Visit(cxxMethodDecl.Parameters);
_outputBuilder.EndFunctionInnerPrototype();
_outputBuilder.EndFunctionInnerPrototype(in desc);
_outputBuilder.EndFunctionOrDelegate(in desc);
Debug.Assert(_context.Last == currentContext);
@ -1950,11 +1962,11 @@ namespace ClangSharp
var isUnsafe = true;
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);
_outputBuilder.BeginFunctionInnerPrototype(desc.EscapedName);
_outputBuilder.BeginFunctionInnerPrototype(in desc);
Visit(cxxMethodDecl.Parameters);
_outputBuilder.EndFunctionInnerPrototype();
_outputBuilder.EndFunctionInnerPrototype(in desc);
_outputBuilder.BeginBody();
var escapedCXXRecordDeclName = EscapeName(cxxRecordDeclName);
@ -2764,7 +2776,7 @@ namespace ClangSharp
var isUnsafe = false;
_outputBuilder.BeginFunctionOrDelegate(in function, ref isUnsafe);
_outputBuilder.BeginFunctionInnerPrototype("AsSpan");
_outputBuilder.BeginFunctionInnerPrototype(in function);
if (type.Size == 1)
{
@ -2777,7 +2789,7 @@ namespace ClangSharp
_outputBuilder.EndParameter(in param);
}
_outputBuilder.EndFunctionInnerPrototype();
_outputBuilder.EndFunctionInnerPrototype(in function);
_outputBuilder.BeginBody(true);
code = _outputBuilder.BeginCSharpCode();
@ -2859,11 +2871,11 @@ namespace ClangSharp
var isUnsafe = desc.IsUnsafe;
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);
_outputBuilder.BeginFunctionInnerPrototype(escapedName);
_outputBuilder.BeginFunctionInnerPrototype(in desc);
Visit(typedefDecl.CursorChildren.OfType<ParmVarDecl>());
_outputBuilder.EndFunctionInnerPrototype();
_outputBuilder.EndFunctionInnerPrototype(in desc);
_outputBuilder.EndFunctionOrDelegate(in desc);
}
StopUsingOutputBuilder();

Просмотреть файл

@ -4960,6 +4960,13 @@ namespace ClangSharp
private bool IsUnsafe(FunctionDecl functionDecl)
{
var name = GetRemappedCursorName(functionDecl);
if (_config.WithManualImports.Contains(name))
{
return true;
}
if (IsUnsafe(functionDecl, functionDecl.ReturnType))
{
return true;

Просмотреть файл

@ -282,6 +282,7 @@ namespace ClangSharp
init
{
AddRange(_forceRemappedNames, value, ValueStartsWithAt);
AddRange(_remappedNames, value, RemoveAtPrefix);
}
}
@ -502,7 +503,6 @@ namespace ClangSharp
}
}
private static void AddRange<TValue>(SortedDictionary<string, TValue> dictionary, IEnumerable<KeyValuePair<string, TValue>> keyValuePairs)
{
if (keyValuePairs != null)

Просмотреть файл

@ -171,7 +171,7 @@ namespace ClangSharp.XML
_ = _sb.Append("</type>");
}
public void BeginFunctionInnerPrototype(string escapedName)
public void BeginFunctionInnerPrototype(in FunctionOrDelegateDesc info)
{
// nop, only used in C#
}
@ -196,7 +196,7 @@ namespace ClangSharp.XML
// nop, used only in C#
}
public void EndFunctionInnerPrototype()
public void EndFunctionInnerPrototype(in FunctionOrDelegateDesc info)
{
// nop, used only in C#
}

Просмотреть файл

@ -81,11 +81,11 @@ namespace ClangSharp.UnitTests
RemappedNames = remappedNames,
TraversalNames = null,
TestOutputLocation = null,
WithAccessSpecifiers = null,
WithAccessSpecifiers = withAccessSpecifiers,
WithAttributes = withAttributes,
WithCallConvs = withCallConvs,
WithClasses = withClasses,
WithLibraryPaths = null,
WithLibraryPaths = withLibraryPaths,
WithManualImports = null,
WithNamespaces = withNamespaces,
WithSetLastErrors = withSetLastErrors,