From f89209c8e0c3456d9415bbf3a38278827965ce7d Mon Sep 17 00:00:00 2001 From: Jelle Date: Tue, 11 Mar 2025 12:38:45 +0000 Subject: [PATCH] Feat/improved clean comment pass (#1928) * Code cleanup * Improved XML style comment parsing * Fix test errors --- src/AST/Comment.cs | 52 +++-- src/CppParser/Comments.cpp | 4 +- src/Generator.Tests/Passes/TestPasses.cs | 23 +- .../Generators/CSharp/CSharpCommentPrinter.cs | 212 ++++++++++++++---- src/Generator/Generators/CodeGenerator.cs | 4 +- src/Generator/Passes/CleanCommentsPass.cs | 109 +++++++-- .../Passes/FixParameterUsageFromComments.cs | 2 +- src/Generator/Utils/HtmlEncoder.cs | 4 +- .../NamespacesDerived.Tests.cs | 2 +- tests/dotnet/Native/Passes.h | 37 +++ 10 files changed, 355 insertions(+), 94 deletions(-) diff --git a/src/AST/Comment.cs b/src/AST/Comment.cs index e45db3ee..dc70f20a 100644 --- a/src/AST/Comment.cs +++ b/src/AST/Comment.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace CppSharp.AST { @@ -109,7 +110,7 @@ namespace CppSharp.AST T VisitTParamCommand(TParamCommandComment comment); T VisitVerbatimBlock(VerbatimBlockComment comment); T VisitVerbatimLine(VerbatimLineComment comment); - T VisitParagraphCommand(ParagraphComment comment); + T VisitParagraph(ParagraphComment comment); T VisitFull(FullComment comment); T VisitHTMLStartTag(HTMLStartTagComment comment); T VisitHTMLEndTag(HTMLEndTagComment comment); @@ -129,20 +130,13 @@ namespace CppSharp.AST public static string GetMultiLineCommentPrologue(CommentKind kind) { - switch (kind) + return kind switch { - case CommentKind.BCPL: - case CommentKind.BCPLExcl: - return "//"; - case CommentKind.C: - case CommentKind.JavaDoc: - case CommentKind.Qt: - return " *"; - case CommentKind.BCPLSlash: - return "///"; - default: - throw new ArgumentOutOfRangeException(); - } + CommentKind.BCPL or CommentKind.BCPLExcl => "//", + CommentKind.C or CommentKind.JavaDoc or CommentKind.Qt => " *", + CommentKind.BCPLSlash => "///", + _ => throw new ArgumentOutOfRangeException() + }; } public static string GetLineCommentPrologue(CommentKind kind) @@ -375,7 +369,7 @@ namespace CppSharp.AST public override void Visit(ICommentVisitor visitor) { - visitor.VisitParagraphCommand(this); + visitor.VisitParagraph(this); } } @@ -416,10 +410,17 @@ namespace CppSharp.AST { public string Name; public string Value; + + public override string ToString() + { + return $"{Name}=\"{Value}\""; + } } public List Attributes; + public bool SelfClosing { get; set; } + public HTMLStartTagComment() { Kind = DocumentationCommentKind.HTMLStartTagComment; @@ -430,6 +431,15 @@ namespace CppSharp.AST { visitor.VisitHTMLStartTag(this); } + + public override string ToString() + { + var attrStr = string.Empty; + if (Attributes.Count != 0) + attrStr = " " + string.Join(' ', Attributes.Select(x => x.ToString())); + + return $"<{TagName}{attrStr}{(SelfClosing ? "/" : "")}>"; + } } /// @@ -446,6 +456,11 @@ namespace CppSharp.AST { visitor.VisitHTMLEndTag(this); } + + public override string ToString() + { + return $""; + } } /// @@ -464,6 +479,13 @@ namespace CppSharp.AST { visitor.VisitText(this); } + + public override string ToString() + { + return Text; + } + + public bool IsEmpty => string.IsNullOrEmpty(Text) && !HasTrailingNewline; } /// diff --git a/src/CppParser/Comments.cpp b/src/CppParser/Comments.cpp index 71e6a55e..799a0985 100644 --- a/src/CppParser/Comments.cpp +++ b/src/CppParser/Comments.cpp @@ -263,8 +263,8 @@ void Parser::HandleComments(const clang::Decl* D, Declaration* Decl) { using namespace clang; - const clang::RawComment* RC = 0; - if (!(RC = c->getASTContext().getRawCommentForAnyRedecl(D))) + const clang::RawComment* RC = c->getASTContext().getRawCommentForAnyRedecl(D); + if (!RC) return; auto RawComment = WalkRawComment(RC); diff --git a/src/Generator.Tests/Passes/TestPasses.cs b/src/Generator.Tests/Passes/TestPasses.cs index 2a72a628..faa385c0 100644 --- a/src/Generator.Tests/Passes/TestPasses.cs +++ b/src/Generator.Tests/Passes/TestPasses.cs @@ -123,10 +123,12 @@ namespace CppSharp.Generator.Tests.Passes [Test] public void TestCleanCommentsPass() { - var c = AstContext.FindClass("TestCommentsPass").FirstOrDefault(); + var c = AstContext.Class("TestCommentsPass"); + var c2 = AstContext.Class("TestCommentsPass2"); passBuilder.AddPass(new CleanCommentsPass()); passBuilder.RunPasses(pass => pass.VisitDeclaration(c)); + passBuilder.RunPasses(pass => pass.VisitClassDecl(c2)); var para = (ParagraphComment)c.Comment.FullComment.Blocks[0]; var textGenerator = new TextGenerator(); @@ -134,6 +136,25 @@ namespace CppSharp.Generator.Tests.Passes Assert.That(textGenerator.StringBuilder.ToString().Trim(), Is.EqualTo("/// A simple test.")); + + var textGenerator2 = new TextGenerator(); + textGenerator2.Print(c2.Methods[0].Comment.FullComment, CommentKind.BCPLSlash); + + Assert.That(textGenerator2.StringBuilder.ToString().Trim().Replace("\r\n", "\n"), + Is.EqualTo( + "/// Gets a value\n" + + "/// One" + )); + + var textGenerator3 = new TextGenerator(); + textGenerator3.Print(c2.Methods[1].Comment.FullComment, CommentKind.BCPLSlash); + + Assert.That(textGenerator3.StringBuilder.ToString().Trim().Replace("\r\n", "\n"), + Is.EqualTo( + "/// Sets a value. Get it with \n" + + "/// The value to set\n" + + "/// The parameter (typeof)" + )); } [Test] diff --git a/src/Generator/Generators/CSharp/CSharpCommentPrinter.cs b/src/Generator/Generators/CSharp/CSharpCommentPrinter.cs index 6f7fe7e2..3c0adbee 100644 --- a/src/Generator/Generators/CSharp/CSharpCommentPrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpCommentPrinter.cs @@ -11,7 +11,7 @@ namespace CppSharp.Generators.CSharp { public static void Print(this ITextGenerator textGenerator, Comment comment, CommentKind kind) { - var sections = new List
{ new Section(CommentElement.Summary) }; + var sections = new List
(); GetCommentSections(comment, sections); foreach (var section in sections) TrimSection(section); @@ -23,18 +23,23 @@ namespace CppSharp.Generators.CSharp switch (comment.Kind) { case DocumentationCommentKind.FullComment: - var fullComment = (FullComment)comment; - foreach (var block in fullComment.Blocks) + { + foreach (var block in ((FullComment)comment).Blocks) block.GetCommentSections(sections); break; + } case DocumentationCommentKind.BlockCommandComment: + { var blockCommandComment = (BlockCommandComment)comment; if (blockCommandComment.ParagraphComment == null) break; + switch (blockCommandComment.CommandKind) { case CommentCommandKind.Brief: + sections.Add(new Section(CommentElement.Summary)); blockCommandComment.ParagraphComment.GetCommentSections(sections); + sections.Add(new Section(CommentElement.Remarks)); break; case CommentCommandKind.Return: case CommentCommandKind.Returns: @@ -49,6 +54,7 @@ namespace CppSharp.Generators.CSharp if (inlineContentComment.HasTrailingNewline) lastBlockSection.NewLine(); } + break; default: sections.Add(new Section(CommentElement.Remarks)); @@ -56,67 +62,79 @@ namespace CppSharp.Generators.CSharp break; } - break; + } case DocumentationCommentKind.ParamCommandComment: + { var paramCommandComment = (ParamCommandComment)comment; var param = new Section(CommentElement.Param); sections.Add(param); if (paramCommandComment.Arguments.Count > 0) - param.Attributes.Add( - string.Format("name=\"{0}\"", paramCommandComment.Arguments[0].Text)); + param.Attributes.Add($"name=\"{paramCommandComment.Arguments[0].Text}\""); + if (paramCommandComment.ParagraphComment != null) + { foreach (var inlineContentComment in paramCommandComment.ParagraphComment.Content) { inlineContentComment.GetCommentSections(sections); if (inlineContentComment.HasTrailingNewline) sections.Last().NewLine(); } + } + if (!string.IsNullOrEmpty(sections.Last().CurrentLine.ToString())) sections.Add(new Section(CommentElement.Remarks)); break; - case DocumentationCommentKind.TParamCommandComment: - break; - case DocumentationCommentKind.VerbatimBlockComment: - break; - case DocumentationCommentKind.VerbatimLineComment: - break; + } case DocumentationCommentKind.ParagraphComment: - var summaryParagraph = sections.Count == 1; - var paragraphComment = (ParagraphComment)comment; + { + bool assumeSummary = false; + + if (sections.Count == 0) + { + assumeSummary = true; + sections.Add(new Section(CommentElement.Summary)); + } + var lastParagraphSection = sections.Last(); + var paragraphComment = (ParagraphComment)comment; foreach (var inlineContentComment in paragraphComment.Content) { inlineContentComment.GetCommentSections(sections); if (inlineContentComment.HasTrailingNewline) lastParagraphSection.NewLine(); + + var newSection = sections.Last(); + if (lastParagraphSection == newSection) + continue; + + if (!string.IsNullOrEmpty(lastParagraphSection.CurrentLine.ToString())) + lastParagraphSection.NewLine(); + + lastParagraphSection = newSection; } if (!string.IsNullOrEmpty(lastParagraphSection.CurrentLine.ToString())) lastParagraphSection.NewLine(); - if (sections[0].GetLines().Count > 0 && summaryParagraph) - { - sections[0].GetLines().AddRange(sections.Skip(1).SelectMany(s => s.GetLines())); - sections.RemoveRange(1, sections.Count - 1); + // The next paragraph should be a remarks section + if (assumeSummary) sections.Add(new Section(CommentElement.Remarks)); - } - break; - case DocumentationCommentKind.HTMLTagComment: - break; - case DocumentationCommentKind.HTMLStartTagComment: - break; - case DocumentationCommentKind.HTMLEndTagComment: + break; + } case DocumentationCommentKind.TextComment: - var lastTextsection = sections.Last(); - lastTextsection.CurrentLine.Append(GetText(comment, - lastTextsection.Type == CommentElement.Returns || - lastTextsection.Type == CommentElement.Param).Trim()); - break; - case DocumentationCommentKind.InlineContentComment: + { + var lastTextSection = sections.Last(); + lastTextSection.CurrentLine + .Append( + GetText(comment, lastTextSection.Type is CommentElement.Returns or CommentElement.Param) + .TrimStart() + ); break; + } case DocumentationCommentKind.InlineCommandComment: + { var lastInlineSection = sections.Last(); var inlineCommand = (InlineCommandComment)comment; @@ -125,9 +143,50 @@ namespace CppSharp.Generators.CSharp var argText = $" {inlineCommand.Arguments[0].Text} "; lastInlineSection.CurrentLine.Append(argText); } + + break; + } + case DocumentationCommentKind.HTMLStartTagComment: + { + var startTag = (HTMLStartTagComment)comment; + var sectionType = CommentElementFromTag(startTag.TagName); + + if (IsInlineCommentElement(sectionType)) + { + var lastSection = sections.Last(); + lastSection.CurrentLine.Append(startTag); + break; + } + + sections.Add(new Section(sectionType) + { + Attributes = startTag.Attributes.Select(a => a.ToString()).ToList() + }); + break; + } + case DocumentationCommentKind.HTMLEndTagComment: + { + var endTag = (HTMLEndTagComment)comment; + var sectionType = CommentElementFromTag(endTag.TagName); + + if (IsInlineCommentElement(sectionType)) + { + var lastSection = sections.Last(); + lastSection.CurrentLine.Append(endTag); + } + break; + } + case DocumentationCommentKind.HTMLTagComment: + case DocumentationCommentKind.TParamCommandComment: + case DocumentationCommentKind.VerbatimBlockComment: + case DocumentationCommentKind.VerbatimLineComment: + case DocumentationCommentKind.InlineContentComment: case DocumentationCommentKind.VerbatimBlockLineComment: + case DocumentationCommentKind.BlockContentComment: break; + default: + throw new ArgumentOutOfRangeException(); } } @@ -139,10 +198,10 @@ namespace CppSharp.Generators.CSharp text = text.Trim(); if (Helpers.RegexTag.IsMatch(text)) - return String.Empty; + return string.Empty; return HtmlEncoder.HtmlEncode( - text.Length > 1 && text[0] == ' ' && text[1] != ' ' ? text.Substring(1) : text); + text.Length > 1 && text[0] == ' ' && text[1] != ' ' ? text[1..] : text); } private static void TrimSection(Section section) @@ -166,22 +225,25 @@ namespace CppSharp.Generators.CSharp private static void FormatComment(ITextGenerator textGenerator, List
sections, CommentKind kind) { - var commentPrefix = Comment.GetMultiLineCommentPrologue(kind); - sections.Sort((x, y) => x.Type.CompareTo(y.Type)); + var remarks = sections.Where(s => s.Type == CommentElement.Remarks).ToList(); - if (remarks.Any()) + if (remarks.Count != 0) remarks.First().GetLines().AddRange(remarks.Skip(1).SelectMany(s => s.GetLines())); + if (remarks.Count > 1) sections.RemoveRange(sections.IndexOf(remarks.First()) + 1, remarks.Count - 1); + var commentPrefix = Comment.GetMultiLineCommentPrologue(kind); foreach (var section in sections.Where(s => s.HasLines)) { var lines = section.GetLines(); var tag = section.Type.ToString().ToLowerInvariant(); + var attributes = string.Empty; - if (section.Attributes.Any()) + if (section.Attributes.Count != 0) attributes = ' ' + string.Join(" ", section.Attributes); + textGenerator.Write($"{commentPrefix} <{tag}{attributes}>"); if (lines.Count == 1) { @@ -205,13 +267,13 @@ namespace CppSharp.Generators.CSharp Type = type; } - public StringBuilder CurrentLine { get; set; } = new StringBuilder(); + public StringBuilder CurrentLine { get; set; } = new(); public CommentElement Type { get; set; } - public List Attributes { get; } = new List(); + public List Attributes { get; init; } = new(); - private List lines { get; } = new List(); + private List lines { get; } = new(); public bool HasLines => lines.Any(); @@ -229,15 +291,71 @@ namespace CppSharp.Generators.CSharp } } + private static CommentElement CommentElementFromTag(string tag) + { + return tag.ToLowerInvariant() switch + { + "c" => CommentElement.C, + "code" => CommentElement.Code, + "example" => CommentElement.Example, + "exception" => CommentElement.Exception, + "include" => CommentElement.Include, + "list" => CommentElement.List, + "para" => CommentElement.Para, + "param" => CommentElement.Param, + "paramref" => CommentElement.ParamRef, + "permission" => CommentElement.Permission, + "remarks" => CommentElement.Remarks, + "return" or "returns" => CommentElement.Returns, + "summary" => CommentElement.Summary, + "typeparam" => CommentElement.TypeParam, + "typeparamref" => CommentElement.TypeParamRef, + "value" => CommentElement.Value, + "seealso" => CommentElement.SeeAlso, + "see" => CommentElement.See, + "inheritdoc" => CommentElement.InheritDoc, + _ => CommentElement.Unknown + }; + } + + /// From https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/documentation-comments#d3-recommended-tags + /// Enum value is equal to sorting priority private enum CommentElement { - Summary, - Typeparam, - Param, - Returns, - Exception, - Remarks, - Example + C = 1000, // Set text in a code-like font + Code = 1001, // Set one or more lines of source code or program output + Example = 11, // Indicate an example + Exception = 8, // Identifies the exceptions a method can throw + Include = 1, // Includes XML from an external file + List = 1002, // Create a list or table + Para = 1003, // Permit structure to be added to text + Param = 5, // Describe a parameter for a method or constructor + ParamRef = 1004, // Identify that a word is a parameter name + Permission = 7, // Document the security accessibility of a member + Remarks = 9, // Describe additional information about a type + Returns = 6, // Describe the return value of a method + See = 1005, // Specify a link + SeeAlso = 10, // Generate a See Also entry + Summary = 2, // Describe a type or a member of a type + TypeParam = 4, // Describe a type parameter for a generic type or method + TypeParamRef = 1006, // Identify that a word is a type parameter name + Value = 3, // Describe a property + InheritDoc = 0, // Inherit documentation from a base class + Unknown = 9999, // Unknown tag } + + private static bool IsInlineCommentElement(CommentElement element) => + element switch + { + CommentElement.C => true, + CommentElement.Code => true, + CommentElement.List => true, + CommentElement.Para => true, + CommentElement.ParamRef => true, + CommentElement.See => true, + CommentElement.TypeParamRef => true, + CommentElement.Unknown => true, // Print unknown tags as inline + _ => ((int)element) >= 1000 + }; } } diff --git a/src/Generator/Generators/CodeGenerator.cs b/src/Generator/Generators/CodeGenerator.cs index 793b9873..baede2ae 100644 --- a/src/Generator/Generators/CodeGenerator.cs +++ b/src/Generator/Generators/CodeGenerator.cs @@ -1333,8 +1333,8 @@ namespace CppSharp.Generators public static class Helpers { - public static Regex RegexTag = new Regex(@"^(<|?$"); - public static Regex RegexCommentCommandLeftover = new Regex(@"^\S*"); + public static Regex RegexTag = new(@"^(<|?$"); + public static Regex RegexCommentCommandLeftover = new(@"^\S*"); public static readonly string InternalStruct = Generator.GeneratedIdentifier("Internal"); public static readonly string InstanceField = Generator.GeneratedIdentifier("instance"); public static readonly string InstanceIdentifier = Generator.GeneratedIdentifier("Instance"); diff --git a/src/Generator/Passes/CleanCommentsPass.cs b/src/Generator/Passes/CleanCommentsPass.cs index 79039549..71ddb8e1 100644 --- a/src/Generator/Passes/CleanCommentsPass.cs +++ b/src/Generator/Passes/CleanCommentsPass.cs @@ -7,10 +7,6 @@ namespace CppSharp.Passes { public class CleanCommentsPass : TranslationUnitPass, ICommentVisitor { - public CleanCommentsPass() => VisitOptions.ResetFlags( - VisitFlags.ClassBases | VisitFlags.FunctionReturnType | - VisitFlags.TemplateArguments); - public bool VisitBlockCommand(BlockCommandComment comment) => true; public override bool VisitParameterDecl(Parameter parameter) => @@ -21,12 +17,11 @@ namespace CppSharp.Passes if (!base.VisitDeclaration(decl)) return false; - if (decl.Comment != null) - { - var fullComment = decl.Comment.FullComment; - VisitFull(fullComment); + if (decl.Comment == null) + return true; - } + var fullComment = decl.Comment.FullComment; + VisitFull(fullComment); return true; } @@ -37,6 +32,7 @@ namespace CppSharp.Passes return true; } + #region Comments Visit public bool VisitHTMLEndTag(HTMLEndTagComment comment) => true; @@ -44,27 +40,94 @@ namespace CppSharp.Passes public bool VisitInlineCommand(InlineCommandComment comment) => true; - public bool VisitParagraphCommand(ParagraphComment comment) + public bool VisitParagraph(ParagraphComment comment) { - for (int i = 0; i < comment.Content.Count; i++) + // Fix clang parsing html tags as TextComment's + var textComments = comment.Content + .Where(c => c.Kind == DocumentationCommentKind.TextComment) + .Cast() + .ToArray(); + + for (var i = 0; i < textComments.Length; ++i) { - if (comment.Content[i].Kind == DocumentationCommentKind.InlineCommandComment && - i + 1 < comment.Content.Count && - comment.Content[i + 1].Kind == DocumentationCommentKind.TextComment) + TextComment textComment = textComments[i]; + if (textComment.IsEmpty) + { + comment.Content.Remove(textComment); + continue; + } + + if (!textComment.Text.StartsWith('<')) + continue; + + if (textComment.Text.Length < 2 || i + 1 >= textComments.Length) + continue; + + bool isEndTag = textComment.Text[1] == '/'; + + // Replace the TextComment node with a HTMLTagComment node + HTMLTagComment htmlTag = isEndTag ? new HTMLEndTagComment() : new HTMLStartTagComment(); + htmlTag.TagName = textComment.Text[(1 + (isEndTag ? 1 : 0))..]; + + // Cleanup next element + TextComment next = textComments[i + 1]; + int tagEnd = next.Text.IndexOf('>'); + if (tagEnd == -1) + continue; + + if (!isEndTag) + { + var startTag = (htmlTag as HTMLStartTagComment)!; + var tagRemains = next.Text[..tagEnd]; + + if (tagRemains.EndsWith('/')) + { + startTag.SelfClosing = true; + tagRemains = tagRemains[..^1]; + } + + var attributes = tagRemains.Split(' ', StringSplitOptions.RemoveEmptyEntries); + foreach (var attribute in attributes) + { + var args = attribute.Split('='); + startTag.Attributes.Add(new HTMLStartTagComment.Attribute + { + Name = args[0].Trim(), + Value = args.ElementAtOrDefault(1)?.Trim(' ', '"'), + }); + } + } + + // Strip tagRemains from next element + next.Text = next.Text[(tagEnd + 1)..]; + + if (string.IsNullOrEmpty(next.Text)) { - var textComment = (TextComment)comment.Content[i + 1]; - textComment.Text = Helpers.RegexCommentCommandLeftover.Replace( - textComment.Text, string.Empty); + htmlTag.HasTrailingNewline = next.HasTrailingNewline; + comment.Content.Remove(next); } + + // Replace element + var insertPos = comment.Content.IndexOf(textComment); + comment.Content.RemoveAt(insertPos); + comment.Content.Insert(insertPos, htmlTag); } - foreach (var item in comment.Content.Where(c => c.Kind == DocumentationCommentKind.TextComment)) + + for (int i = 0; i < comment.Content.Count; i++) { - var textComment = (TextComment)item; + if (comment.Content[i].Kind != DocumentationCommentKind.InlineCommandComment) + continue; + + if (i + 1 >= comment.Content.Count) + continue; + + if (comment.Content[i + 1].Kind != DocumentationCommentKind.TextComment) + continue; + - if (textComment.Text.StartsWith("<", StringComparison.Ordinal)) - textComment.Text = $"{textComment.Text}>"; - else if (textComment.Text.StartsWith(">", StringComparison.Ordinal)) - textComment.Text = textComment.Text.Substring(1); + var textComment = (TextComment)comment.Content[i + 1]; + textComment.Text = Helpers.RegexCommentCommandLeftover.Replace( + textComment.Text, string.Empty); } return true; } diff --git a/src/Generator/Passes/FixParameterUsageFromComments.cs b/src/Generator/Passes/FixParameterUsageFromComments.cs index afe36fa1..a68167e6 100644 --- a/src/Generator/Passes/FixParameterUsageFromComments.cs +++ b/src/Generator/Passes/FixParameterUsageFromComments.cs @@ -71,7 +71,7 @@ namespace CppSharp.Passes return true; } - public bool VisitParagraphCommand(ParagraphComment comment) + public bool VisitParagraph(ParagraphComment comment) { return true; } diff --git a/src/Generator/Utils/HtmlEncoder.cs b/src/Generator/Utils/HtmlEncoder.cs index 4c332101..4f557ca8 100644 --- a/src/Generator/Utils/HtmlEncoder.cs +++ b/src/Generator/Utils/HtmlEncoder.cs @@ -53,7 +53,7 @@ namespace System.Web.Util return null; if (s.Length == 0) - return String.Empty; + return string.Empty; bool needEncode = s.Any(c => c == '&' || c == '"' || c == '<' || c == '>' || c > 159); @@ -93,7 +93,7 @@ namespace System.Web.Util { output.Append("&#"); output.Append(((int)ch).ToString(CultureInfo.InvariantCulture)); - output.Append(";"); + output.Append(';'); } else output.Append(ch); diff --git a/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.cs b/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.cs index 6c486bc5..acfb9dda 100644 --- a/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.cs +++ b/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.cs @@ -157,7 +157,7 @@ public class NamespaceDerivedTests "The context of the specified window must not be current on any other", "thread when this function is called.", "This function must not be called from a callback.", - "_safety This function must only be called from the main thread.", + "This function must only be called from the main thread.", "Added in version 3.0. Replaces `glfwCloseWindow`." })); XElement window = method.Element("param"); diff --git a/tests/dotnet/Native/Passes.h b/tests/dotnet/Native/Passes.h index ee3c8c7a..fb2962c0 100644 --- a/tests/dotnet/Native/Passes.h +++ b/tests/dotnet/Native/Passes.h @@ -45,6 +45,43 @@ class TestCommentsPass { }; +/// A more complex test. +class TestCommentsPass2 +{ +public: + /// Gets a value + /// One + float GetValueWithComment() + { + return 1.0f; + } + + /// Sets a value. Get it with + /// The value to set + /// The parameter (typeof) + float SetValueWithParamComment(float value) + { + return value; + } + + /// + /// This method changes the point's location by + /// the given x- and y-offsets. + /// For example: + /// + /// Point p = new Point(3, 5); + /// p.Translate(-1, 3); + /// + /// results in p's having the value (2, 8). + /// + /// + /// The relative x-offset. + /// The relative y-offset. + void Translate(int dx, int dy) + { + } +}; + struct TestReadOnlyProperties { int readOnlyProperty;