Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.

using ClangSharp.Interop;

namespace ClangSharp.Abstractions;

internal partial interface IOutputBuilder
{
void WriteDocComment(in CXComment comment);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.

using System;
using System.Collections.Generic;
using System.Security;
using ClangSharp.Interop;

namespace ClangSharp.CSharp;

internal partial class CSharpOutputBuilder
{
public void WriteDocComment(in CXComment fullComment)
{
if (fullComment.Kind == CXCommentKind.CXComment_Null)
{
return;
}

var summaryParts = new List<string>();
var remarksParts = new List<string>();
string? returnText = null;
var paramParts = new List<(string Name, string Text)>();

for (uint i = 0; i < fullComment.NumChildren; i++)
{
var child = fullComment.GetChild(i);
switch (child.Kind)
{
case CXCommentKind.CXComment_Paragraph:
var text = GetParagraphText(child).Trim();
if (!string.IsNullOrEmpty(text))
{
summaryParts.Add(text);
}

break;

case CXCommentKind.CXComment_ParamCommand:
var paramName = child.ParamCommandComment_ParamName.ToString();
var paramText = GetParagraphText(child.BlockCommandComment_Paragraph).Trim();
paramParts.Add((paramName, paramText));
break;

case CXCommentKind.CXComment_BlockCommand:
var cmd = child.BlockCommandComment_CommandName.ToString();
var body = GetParagraphText(child.BlockCommandComment_Paragraph).Trim();
if (cmd is "brief" or "summary")
{
summaryParts.Add(body);
}
else if (cmd is "return" or "returns")
{
returnText = body;
}
else
{
remarksParts.Add($"{cmd}: {body}");
}

break;
}
}

if (summaryParts.Count == 1)
{
WriteIndented("/// <summary>");
Write(summaryParts[0]);
WriteLine("</summary>");
}
else if (summaryParts.Count > 1)
{
WriteIndentedLine("/// <summary>");
foreach (var part in summaryParts)
{
WriteIndented("/// <para>");
Write(part);
WriteLine("</para>");
}

WriteIndentedLine("/// </summary>");
}

foreach (var (name, paramText) in paramParts)
{
WriteIndented("/// <param name=");
Write('"');
Write(name);
Write('"');
Write('>');
Write(paramText);
WriteLine("</param>");
}

if (returnText is not null)
{
WriteIndented("/// <returns>");
Write(returnText);
WriteLine("</returns>");
}

if (remarksParts.Count == 1)
{
WriteIndented("/// <remarks>");
Write(remarksParts[0]);
WriteLine("</remarks>");
}
else if (remarksParts.Count > 1)
{
WriteIndentedLine("/// <remarks>");
foreach (var part in remarksParts)
{
WriteIndented("/// <para>");
Write(part);
WriteLine("</para>");
}

WriteIndentedLine("/// </remarks>");
}
}

private static string GetParagraphText(CXComment para)
{
if (para.Kind is not CXCommentKind.CXComment_Paragraph)
{
throw new InvalidOperationException("Expected a paragraph comment");
}

var sb = new System.Text.StringBuilder();
for (uint i = 0; i < para.NumChildren; i++)
{
var child = para.GetChild(i);
if (child.Kind == CXCommentKind.CXComment_Text)
{
_ = sb.Append(child.TextComment_Text.ToString());
}
}

return SecurityElement.Escape(sb.ToString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.

using ClangSharp.Interop;

namespace ClangSharp;

public partial class PInvokeGenerator
{
private void WriteDocCommentXml(CXComment comment)
{
if (!_config.GenerateDocComments)
{
return;
}
_outputBuilder!.WriteDocComment(in comment);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ private void VisitEnumConstantDecl(EnumConstantDecl enumConstantDecl)
CustomAttrGeneratorData = (enumConstantDecl, this),
};

WriteDocCommentXml(enumConstantDecl.Handle.ParsedComment);
_outputBuilder.BeginValue(in desc);

if ((enumConstantDecl.InitExpr != null) && (!ShouldConstantFoldValue(enumConstantDecl) || IsEnumeratorAliasInitializer(enumConstantDecl)))
Expand Down Expand Up @@ -512,6 +513,7 @@ private void VisitEnumDecl(EnumDecl enumDecl)
CustomAttrGeneratorData = (enumDecl, this),
};

WriteDocCommentXml(enumDecl.Handle.ParsedComment);
_outputBuilder.BeginEnum(in desc);
}

Expand Down Expand Up @@ -573,6 +575,7 @@ private void VisitFieldDecl(FieldDecl fieldDecl)
CustomAttrGeneratorData = (fieldDecl, this),
};

WriteDocCommentXml(fieldDecl.Handle.ParsedComment);
_outputBuilder.BeginField(in desc);

if (IsTypeConstantOrIncompleteArray(fieldDecl, type, out var arrayType))
Expand Down Expand Up @@ -679,6 +682,8 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
TransformBoolType(ref returnTypeName, ref nativeTypeName);
}

WriteDocCommentXml(functionDecl.Handle.ParsedComment);

var type = functionDecl.Type;
var callingConventionName = GetCallingConvention(functionDecl, cxxRecordDecl, type);

Expand Down Expand Up @@ -1576,6 +1581,7 @@ void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionPro
};

var isUnsafe = desc.IsUnsafe;
WriteDocCommentXml(typedefDecl.Handle.ParsedComment);
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);

_outputBuilder.BeginFunctionInnerPrototype(in desc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ private void VisitRecordDecl(RecordDecl recordDecl)
};
Debug.Assert(_outputBuilder is not null);

WriteDocCommentXml(recordDecl.Handle.ParsedComment);

if (!isTopLevelStruct)
{
_outputBuilder.BeginStruct(in desc);
Expand Down Expand Up @@ -829,6 +831,7 @@ void OutputMarkerInterface(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethodD
};

var isUnsafe = true;
WriteDocCommentXml(cxxMethodDecl.Handle.ParsedComment);
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);

_outputBuilder.BeginFunctionInnerPrototype(in desc);
Expand Down Expand Up @@ -1000,6 +1003,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod
};

var isUnsafe = true;
WriteDocCommentXml(cxxMethodDecl.Handle.ParsedComment);
_outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe);

_outputBuilder.BeginFunctionInnerPrototype(in desc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ private void VisitVarDecl(VarDecl varDecl)

Debug.Assert(_outputBuilder is not null);

WriteDocCommentXml(varDecl.Handle.ParsedComment);
_outputBuilder.BeginValue(in desc);

var currentContext = _context.Last;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,8 @@ public GeneratedCodeAttributeMode GeneratedCodeAttributeMode

public bool DontUseUsingStaticsForGuidMember => (_options & PInvokeGeneratorConfigurationOptions.DontUseUsingStaticsForGuidMember) != 0;

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

public string HeaderText => _headerText;

[AllowNull]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,6 @@ public enum PInvokeGeneratorConfigurationOptions : long
GenerateObjectiveCBindings = 1L << 45,

GenerateNativeAlignmentAttribute = 1L << 46,

GenerateDocComments = 1L << 47,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.

using ClangSharp.Interop;

namespace ClangSharp.XML;

internal partial class XmlOutputBuilder
{
public void WriteDocComment(in CXComment comment)
{
// Not implemented for XML
}
}
1 change: 1 addition & 0 deletions sources/ClangSharpPInvokeGenerator/Program.Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ internal static partial class Program
new HelpRow("default-remappings", "Default remappings for well known types should be added. This currently includes intptr_t, ptrdiff_t, size_t, ssize_t, uintptr_t, and the exact-width stdint types (int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, and uint64_t). When targeting Windows, the pointer-width Windows types (INT_PTR, LONG_PTR, SSIZE_T, DWORD_PTR, SIZE_T, UINT_PTR, and ULONG_PTR) and _GUID are also included. On by default; use =false to opt out."),
new HelpRow("disable-runtime-marshalling", "[assembly: DisableRuntimeMarshalling] should be generated."),
new HelpRow("doc-includes", "<include> xml documentation tags should be generated for declarations."),
new HelpRow("doc-comments", "Xml doc comments should be generated from encountered doxygen comments."),
new HelpRow("empty-records", "Bindings for records that contain no members should be generated. These are commonly encountered for opaque handle like types such as HWND. On by default; use =false to opt out."),
new HelpRow("enum-member-type-name", "The enum type name should be kept at the beginning of its member names. On by default; use =false to strip it."),
new HelpRow("enum-operators", "Bindings for operators over enum types should be generated. These are largely unnecessary in C# as the operators are available by default. On by default; use =false to opt out."),
Expand Down
1 change: 1 addition & 0 deletions sources/ClangSharpPInvokeGenerator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ internal static partial class Program
["generate-cpp-attributes"] = (GenerateCppAttributes, false),
["generate-disable-runtime-marshalling"] = (GenerateDisableRuntimeMarshalling, false),
["generate-doc-includes"] = (GenerateDocIncludes, false),
["generate-doc-comments"] = (GenerateDocComments, false),
["generate-extern-variables"] = (GenerateExternVariables, false),
["generate-file-scoped-namespaces"] = (GenerateFileScopedNamespaces, false),
["generate-fixed-buffer-indexer-overloads"] = (GenerateFixedBufferIndexerOverloads, false),
Expand Down