From a4bac6586d25cf1b2b1b8df6b6a7ff3cd956949e Mon Sep 17 00:00:00 2001 From: Nick Walker Date: Wed, 11 Sep 2024 09:47:50 -0700 Subject: [PATCH] #945509 Support ref readonly parameters Add support for correct rendering of "ref readonly" parameter in C# method signature documentation. --- mdoc/Consts.cs | 1 + .../Updater/Formatters/CSharpFullMemberFormatter.cs | 8 ++++++-- mdoc/mdoc.Test/FormatterTests.cs | 8 ++++++++ mdoc/mdoc.Test/SampleClasses/SomeClass.cs | 4 ++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/mdoc/Consts.cs b/mdoc/Consts.cs index a3aca853c..4a497c810 100644 --- a/mdoc/Consts.cs +++ b/mdoc/Consts.cs @@ -49,6 +49,7 @@ public static class Consts public const string CompilerGeneratedAttribute = "System.Runtime.CompilerServices.CompilerGeneratedAttribute"; public const string IsByRefLikeAttribute = "System.Runtime.CompilerServices.IsByRefLikeAttribute"; public const string IsReadOnlyAttribute = "System.Runtime.CompilerServices.IsReadOnlyAttribute"; + public const string RequiresLocationAttribute = "System.Runtime.CompilerServices.RequiresLocationAttribute"; public const string InAttribute = "System.Runtime.InteropServices.InAttribute"; public const string OutAttribute = "System.Runtime.InteropServices.OutAttribute"; public const string TupleElementNamesAttribute = "System.Runtime.CompilerServices.TupleElementNamesAttribute"; diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs index ec0f20573..37e1b8140 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs @@ -610,7 +610,7 @@ private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition meth protected override StringBuilder AppendParameter(StringBuilder buf, ParameterDefinition parameter) { TypeReference parameterType = parameter.ParameterType; - var refType = new BitArray(3); + var refType = new BitArray(4); if (parameter.HasCustomAttributes) { @@ -641,6 +641,10 @@ protected override StringBuilder AppendParameter(StringBuilder buf, ParameterDef { refType.Set(0, true); } + else if (parameter.IsIn && DocUtils.HasCustomAttribute(parameter, Consts.RequiresLocationAttribute)) + { + refType.Set(3, true); + } else { refType.Set(2, true); @@ -648,7 +652,7 @@ protected override StringBuilder AppendParameter(StringBuilder buf, ParameterDef parameterType = byReferenceType.ElementType; } - buf.Append(refType.Get(0) ? "in " : (refType.Get(1) ? "out " : (refType.Get(2) ? "ref ": ""))); + buf.Append(refType.Get(0) ? "in " : (refType.Get(1) ? "out " : (refType.Get(2) ? "ref ": (refType.Get(3) ? "ref readonly " : "")))); if (parameter.HasCustomAttributes) { diff --git a/mdoc/mdoc.Test/FormatterTests.cs b/mdoc/mdoc.Test/FormatterTests.cs index 187c7fa27..29e2373f8 100644 --- a/mdoc/mdoc.Test/FormatterTests.cs +++ b/mdoc/mdoc.Test/FormatterTests.cs @@ -601,6 +601,14 @@ public void CSharpStaticEventImplementation(string typeFullName, string eventNam TestEventSignature(staticVirtualMemberDllPath, typeFullName, eventName, expectedSignature); } + [TestCase("MethodWithRefReadonlyParam", "public void MethodWithRefReadonlyParam (ref readonly int i);")] + public void CSharpRefReadonlyTest(string methodName, string expectedSignature) + { + var method = GetMethod(typeof(SampleClasses.SomeClass), m => m.Name == methodName); + var methodSignature = formatter.GetDeclaration(method); + Assert.AreEqual(expectedSignature, methodSignature); + } + #region Helper Methods string RealTypeName(string name){ switch (name) { diff --git a/mdoc/mdoc.Test/SampleClasses/SomeClass.cs b/mdoc/mdoc.Test/SampleClasses/SomeClass.cs index 7e7d2dae1..7ddadfbd7 100644 --- a/mdoc/mdoc.Test/SampleClasses/SomeClass.cs +++ b/mdoc/mdoc.Test/SampleClasses/SomeClass.cs @@ -104,6 +104,10 @@ public ref T TestScopedParams(scoped in T p1, scoped out T p2, scoped ref T p throw new PlatformNotSupportedException(); } + public void MethodWithRefReadonlyParam(ref readonly int i) + { + } + public event EventHandler AppMemoryUsageIncreased; public static event EventHandler StaticEvent; private static event EventHandler PrivateEvent;