Skip to content

Commit 3c06eba

Browse files
committed
Add support for C/C++ attribute annotate and emit custom attribute type if encountered.
1 parent 549da90 commit 3c06eba

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public sealed partial class PInvokeGenerator : IDisposable
6565
private readonly HashSet<string> _usedRemappings;
6666
private readonly string _placeholderMacroType;
6767

68+
private bool _hasAnnotateAttr;
69+
6870
private string _filePath;
6971
private string[] _clangCommandLineArgs;
7072
private CXTranslationUnit_Flags _translationFlags;
@@ -435,6 +437,7 @@ public void Close()
435437
GenerateNativeBitfieldAttribute(this, stream, leaveStreamOpen);
436438
GenerateNativeInheritanceAttribute(this, stream, leaveStreamOpen);
437439
GenerateNativeTypeNameAttribute(this, stream, leaveStreamOpen);
440+
GenerateNativeAnnotationAttribute(this, stream, leaveStreamOpen);
438441
GenerateSetsLastSystemErrorAttribute(this, stream, leaveStreamOpen);
439442
GenerateVtblIndexAttribute(this, stream, leaveStreamOpen);
440443
GenerateTransparentStructs(this, stream, leaveStreamOpen);
@@ -795,6 +798,94 @@ static void GenerateNativeTypeNameAttribute(PInvokeGenerator generator, Stream?
795798
}
796799
}
797800

801+
static void GenerateNativeAnnotationAttribute(PInvokeGenerator generator, Stream? stream, bool leaveStreamOpen)
802+
{
803+
var config = generator.Config;
804+
805+
if (!generator._hasAnnotateAttr)
806+
{
807+
return;
808+
}
809+
810+
if (stream is null)
811+
{
812+
var outputPath = Path.Combine(config.OutputLocation, "NativeAnnotationAttribute.cs");
813+
stream = generator._outputStreamFactory(outputPath);
814+
}
815+
816+
using var sw = new StreamWriter(stream, s_defaultStreamWriterEncoding, DefaultStreamWriterBufferSize, leaveStreamOpen);
817+
sw.NewLine = "\n";
818+
819+
if (!string.IsNullOrEmpty(config.HeaderText))
820+
{
821+
sw.WriteLine(config.HeaderText);
822+
}
823+
824+
var indentString = " ";
825+
826+
sw.WriteLine("using System;");
827+
sw.WriteLine("using System.Diagnostics;");
828+
sw.WriteLine();
829+
830+
sw.Write("namespace ");
831+
sw.Write(generator.GetNamespace("NativeAnnotationAttribute"));
832+
833+
if (generator.Config.GenerateFileScopedNamespaces)
834+
{
835+
sw.WriteLine(';');
836+
sw.WriteLine();
837+
indentString = "";
838+
}
839+
else
840+
{
841+
sw.WriteLine();
842+
sw.WriteLine('{');
843+
}
844+
845+
sw.Write(indentString);
846+
sw.WriteLine("/// <summary>Defines the annotation found in a native declaration.</summary>");
847+
sw.Write(indentString);
848+
sw.WriteLine("[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]");
849+
sw.Write(indentString);
850+
sw.WriteLine("[Conditional(\"DEBUG\")]");
851+
sw.Write(indentString);
852+
sw.WriteLine("internal sealed partial class NativeAnnotationAttribute : Attribute");
853+
sw.Write(indentString);
854+
sw.WriteLine('{');
855+
sw.Write(indentString);
856+
sw.WriteLine(" private readonly string _annotation;");
857+
sw.WriteLine();
858+
sw.Write(indentString);
859+
sw.WriteLine(" /// <summary>Initializes a new instance of the <see cref=\"NativeAnnotationAttribute\" /> class.</summary>");
860+
sw.Write(indentString);
861+
sw.WriteLine(" /// <param name=\"annotation\">The annotation that was used in the native declaration.</param>");
862+
sw.Write(indentString);
863+
sw.WriteLine(" public NativeAnnotationAttribute(string annotation)");
864+
sw.Write(indentString);
865+
sw.WriteLine(" {");
866+
sw.Write(indentString);
867+
sw.WriteLine(" _annotation = annotation;");
868+
sw.Write(indentString);
869+
sw.WriteLine(" }");
870+
sw.WriteLine();
871+
sw.Write(indentString);
872+
sw.WriteLine(" /// <summary>Gets the annotation that was used in the native declaration.</summary>");
873+
sw.Write(indentString);
874+
sw.WriteLine(" public string Annotation => _annotation;");
875+
sw.Write(indentString);
876+
sw.WriteLine('}');
877+
878+
if (!generator.Config.GenerateFileScopedNamespaces)
879+
{
880+
sw.WriteLine('}');
881+
}
882+
883+
if (!leaveStreamOpen)
884+
{
885+
stream = null;
886+
}
887+
}
888+
798889
static void GenerateSetsLastSystemErrorAttribute(PInvokeGenerator generator, Stream? stream, bool leaveStreamOpen)
799890
{
800891
var config = generator.Config;
@@ -6724,6 +6815,14 @@ private void WithAttributes(NamedDecl namedDecl, bool onlySupportedOSPlatform =
67246815
break;
67256816
}
67266817

6818+
case CX_AttrKind_Annotate:
6819+
{
6820+
_hasAnnotateAttr = true;
6821+
var annotationText = attr.Spelling;
6822+
outputBuilder.WriteCustomAttribute($"""NativeAnnotation("{annotationText}")""");
6823+
break;
6824+
}
6825+
67276826
case CX_AttrKind_Format:
67286827
case CX_AttrKind_FormatArg:
67296828
case CX_AttrKind_MSNoVTable:

0 commit comments

Comments
 (0)