From d86866cc7d92696720456be7b075aab309699faa Mon Sep 17 00:00:00 2001
From: Charles Stoner <chucks@microsoft.com>
Date: Thu, 20 Oct 2016 10:42:02 -0700
Subject: [PATCH] Add SymbolDisplayMemberOptions.IncludeRef option to include
 `ref` keyword for ref-returning members

---
 .../SymbolDisplayVisitor.Members.cs           |  19 +-
 .../SymbolDisplayVisitor.Types.cs             |   5 +-
 .../SymbolDisplay/SymbolDisplayTests.cs       | 230 +++++++++++++++++-
 .../Core/Portable/PublicAPI.Unshipped.txt     |   1 +
 .../SymbolDisplay/SymbolDisplayFormat.cs      |   3 +-
 .../SymbolDisplayMemberOptions.cs             |   5 +
 .../SymbolDisplay/SymbolDisplayTests.vb       | 196 ++++++++++++++-
 7 files changed, 436 insertions(+), 23 deletions(-)

diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs
index e24c737043a7c..a68c0f89c6215 100644
--- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs
+++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs
@@ -60,10 +60,9 @@ public override void VisitProperty(IPropertySymbol symbol)
 
             if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeType))
             {
-                var property = symbol as PropertySymbol;
-                if (property != null)
+                if (symbol.ReturnsByRef)
                 {
-                    AddRefKindIfRequired(property.RefKind);
+                    AddRefIfRequired();
                 }
 
                 symbol.Type.Accept(this.NotFirstVisitor);
@@ -232,10 +231,9 @@ public override void VisitMethod(IMethodSymbol symbol)
                             // to visualize a symbol *during its construction*, the parameters and return type might 
                             // still be null. 
 
-                            var method = symbol as MethodSymbol;
-                            if (method != null)
+                            if (symbol.ReturnsByRef)
                             {
-                                AddRefKindIfRequired(method.RefKind);
+                                AddRefIfRequired();
                             }
 
                             if (symbol.ReturnsVoid)
@@ -718,6 +716,15 @@ private void AddCustomModifiersIfRequired(ImmutableArray<CustomModifier> customM
             }
         }
 
+        private void AddRefIfRequired()
+        {
+            if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeRef))
+            {
+                AddKeyword(SyntaxKind.RefKeyword);
+                AddSpace();
+            }
+        }
+
         private void AddRefKindIfRequired(RefKind refKind)
         {
             if (format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeParamsRefOut))
diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs
index 3fcf374e7402b..c1901b84b019e 100644
--- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs
+++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs
@@ -178,10 +178,9 @@ public override void VisitNamedType(INamedTypeSymbol symbol)
                 if (format.DelegateStyle == SymbolDisplayDelegateStyle.NameAndSignature)
                 {
                     var invokeMethod = symbol.DelegateInvokeMethod;
-                    var invokeMethodSymbol = invokeMethod as MethodSymbol;
-                    if (invokeMethodSymbol != null)
+                    if (invokeMethod.ReturnsByRef)
                     {
-                        AddRefKindIfRequired(invokeMethodSymbol.RefKind);
+                        AddRefIfRequired();
                     }
 
                     if (invokeMethod.ReturnsVoid)
diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs
index 68daf63c361e2..e297472439a4d 100644
--- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs
@@ -2115,6 +2115,49 @@ void M(ref short s, int i, params string[] args) { } }
                 SymbolDisplayPartKind.Space,
                 SymbolDisplayPartKind.ParameterName, //args
                 SymbolDisplayPartKind.Punctuation);
+
+            // Without SymbolDisplayParameterOptions.IncludeParamsRefOut.
+            TestSymbolDescription(
+                text,
+                findSymbol,
+                format.WithParameterOptions(SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeName),
+                "M(Int16 s, Int32 i, String[] args)",
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.StructName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.StructName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ClassName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Without SymbolDisplayParameterOptions.IncludeType, drops
+            // ref/out/params modifiers. (VB retains ByRef/ParamArray.)
+            TestSymbolDescription(
+                text,
+                findSymbol,
+                format.WithParameterOptions(SymbolDisplayParameterOptions.IncludeParamsRefOut | SymbolDisplayParameterOptions.IncludeName),
+                "M(s, i, args)",
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation);
         }
 
         [Fact()]
@@ -2887,12 +2930,7 @@ private static void Verify(ImmutableArray<SymbolDisplayPart> actualParts, string
             Assert.Equal(expectedText, actualParts.ToDisplayString());
             if (expectedKinds.Length > 0)
             {
-                for (int i = 0; i < Math.Min(expectedKinds.Length, actualParts.Length); i++)
-                {
-                    Assert.Equal(expectedKinds[i], actualParts[i].Kind);
-                }
-
-                Assert.Equal(expectedKinds.Length, actualParts.Length);
+                AssertEx.Equal(expectedKinds, actualParts.Select(p => p.Kind), itemInspector: p => $"SymbolDisplayPartKind.{p}");
             }
         }
 
@@ -4157,7 +4195,6 @@ class C
                 SymbolDisplayPartKind.EventName);
         }
 
-
         [WorkItem(765287, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/765287")]
         [Fact]
         public void TestVbSymbols()
@@ -5184,6 +5221,185 @@ public void DisplayFakeTupleTypeSymbol()
                 SymbolDisplayPartKind.Punctuation);
         }
 
+        [WorkItem(11356, "https://github.com/dotnet/roslyn/issues/11356")]
+        [Fact]
+        public void RefReturn()
+        {
+            var sourceA =
+@"public delegate ref int D();
+public class C
+{
+    public ref int F(ref int i) => ref i;
+    int _p;
+    public ref int P => ref _p;
+    public ref int this[int i] => ref _p;
+}";
+            var compA = CreateCompilationWithMscorlib(sourceA);
+            compA.VerifyDiagnostics();
+            var refA = compA.EmitToImageReference();
+            // From C# symbols.
+            RefReturnInternal(compA);
+
+            var compB = CreateVisualBasicCompilation(GetUniqueName(), "", referencedAssemblies: new[] { MscorlibRef, refA });
+            compB.VerifyDiagnostics();
+            // From VB symbols.
+            RefReturnInternal(compB);
+        }
+
+        private static void RefReturnInternal(Compilation comp)
+        {
+            var formatBase = new SymbolDisplayFormat(
+                memberOptions: SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType,
+                parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut,
+                propertyStyle: SymbolDisplayPropertyStyle.ShowReadWriteDescriptor,
+                delegateStyle: SymbolDisplayDelegateStyle.NameAndSignature,
+                miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
+            var formatWithoutRef = formatBase.WithMemberOptions(
+                SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType);
+            var formatWithRef = formatBase.WithMemberOptions(
+                SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeRef);
+            var formatWithoutTypeWithRef = formatBase.WithMemberOptions(
+                SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeRef);
+
+            var global = comp.GlobalNamespace;
+            var type = global.GetTypeMembers("C").Single();
+            var method = type.GetMembers("F").Single();
+            var property = type.GetMembers("P").Single();
+            var indexer = type.GetMembers().Where(m => m.Kind == SymbolKind.Property && ((IPropertySymbol)m).IsIndexer).Single();
+            var @delegate = global.GetTypeMembers("D").Single();
+
+            // Method without IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(method, formatWithoutRef),
+                "int F(ref int)",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Property without IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(property, formatWithoutRef),
+                "int P { get; }",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.PropertyName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Indexer without IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(indexer, formatWithoutRef),
+                "int this[int] { get; }",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Delegate without IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(@delegate, formatWithoutRef),
+                "int D()",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.DelegateName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Method with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(method, formatWithRef),
+                "ref int F(ref int)",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Property with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(property, formatWithRef),
+                "ref int P { get; }",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.PropertyName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Indexer with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(indexer, formatWithRef),
+                "ref int this[int] { get; }",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Delegate with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(@delegate, formatWithRef),
+                "ref int D()",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.DelegateName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Punctuation);
+
+            // Method without IncludeType, with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts(method, formatWithoutTypeWithRef),
+                "F(ref int)",
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Punctuation);
+        }
+
         [WorkItem(5002, "https://github.com/dotnet/roslyn/issues/5002")]
         [Fact]
         public void AliasInSpeculativeSemanticModel()
diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
index 7a613be26136a..27ec7f201e4a8 100644
--- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
+++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
@@ -710,6 +710,7 @@ Microsoft.CodeAnalysis.Semantics.UnaryOperationKind.UnsignedPrefixIncrement = 77
 Microsoft.CodeAnalysis.SymbolDisplayFormat.RemoveGenericsOptions(Microsoft.CodeAnalysis.SymbolDisplayGenericsOptions options) -> Microsoft.CodeAnalysis.SymbolDisplayFormat
 Microsoft.CodeAnalysis.SymbolDisplayFormat.RemoveLocalOptions(Microsoft.CodeAnalysis.SymbolDisplayLocalOptions options) -> Microsoft.CodeAnalysis.SymbolDisplayFormat
 Microsoft.CodeAnalysis.SymbolDisplayFormat.RemoveMiscellaneousOptions(Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions options) -> Microsoft.CodeAnalysis.SymbolDisplayFormat
+Microsoft.CodeAnalysis.SymbolDisplayMemberOptions.IncludeRef = 128 -> Microsoft.CodeAnalysis.SymbolDisplayMemberOptions
 Microsoft.CodeAnalysis.Text.SourceText.CanBeEmbedded.get -> bool
 Microsoft.CodeAnalysis.Text.SourceText.GetChecksum() -> System.Collections.Immutable.ImmutableArray<byte>
 abstract Microsoft.CodeAnalysis.CompilationOptions.Language.get -> string
diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs
index 5244ef770c356..983677590b321 100644
--- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs
+++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs
@@ -168,6 +168,7 @@ public class SymbolDisplayFormat
                     SymbolDisplayMemberOptions.IncludeParameters |
                     SymbolDisplayMemberOptions.IncludeContainingType |
                     SymbolDisplayMemberOptions.IncludeType |
+                    SymbolDisplayMemberOptions.IncludeRef |
                     SymbolDisplayMemberOptions.IncludeExplicitInterface,
                 kindOptions:
                     SymbolDisplayKindOptions.IncludeMemberKeyword,
@@ -224,7 +225,7 @@ public class SymbolDisplayFormat
             new SymbolDisplayFormat(
                 globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
                 typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
-                memberOptions: SymbolDisplayMemberOptions.IncludeContainingType | SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType,
+                memberOptions: SymbolDisplayMemberOptions.IncludeContainingType | SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeRef,
                 kindOptions: SymbolDisplayKindOptions.IncludeMemberKeyword,
                 genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
                 parameterOptions: SymbolDisplayParameterOptions.IncludeParamsRefOut | SymbolDisplayParameterOptions.IncludeType,
diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs
index 6843a4f112d98..176567a0b864d 100644
--- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs
+++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayMemberOptions.cs
@@ -65,5 +65,10 @@ public enum SymbolDisplayMemberOptions
         /// Includes the value of the member if is a constant.
         /// </summary>
         IncludeConstantValue = 1 << 6,
+
+        /// <summary>
+        /// Includes the <c>ref</c> keyword for ref-returning methods and properties/indexers. C# only.
+        /// </summary>
+        IncludeRef = 1 << 7,
     }
 }
diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb
index 0b455250baf65..be29af2bb8e63 100644
--- a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb
+++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb
@@ -6,7 +6,6 @@ Imports System.Threading
 Imports System.Xml.Linq
 Imports Microsoft.CodeAnalysis
 Imports Microsoft.CodeAnalysis.Test.Utilities
-Imports Microsoft.CodeAnalysis.Text
 Imports Microsoft.CodeAnalysis.VisualBasic
 Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
 Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
@@ -3092,7 +3091,6 @@ End Class
                 findSymbol,
                 format,
                 "M(ByRef s As Int16, i As Int32, ParamArray args As String())",
-                {
                 SymbolDisplayPartKind.MethodName,
                 SymbolDisplayPartKind.Punctuation,
                 SymbolDisplayPartKind.Keyword,
@@ -3120,7 +3118,59 @@ End Class
                 SymbolDisplayPartKind.ClassName,
                 SymbolDisplayPartKind.Punctuation,
                 SymbolDisplayPartKind.Punctuation,
-                SymbolDisplayPartKind.Punctuation})
+                SymbolDisplayPartKind.Punctuation)
+
+            ' Without SymbolDisplayParameterOptions.IncludeParamsRefOut.
+            TestSymbolDescription(
+                text,
+                findSymbol,
+                format.WithParameterOptions(SymbolDisplayParameterOptions.IncludeType Or SymbolDisplayParameterOptions.IncludeName),
+                "M(s As Int16, i As Int32, args As String())",
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.StructName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.StructName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ClassName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Punctuation)
+
+            ' Without SymbolDisplayParameterOptions.IncludeType.
+            TestSymbolDescription(
+                text,
+                findSymbol,
+                format.WithParameterOptions(SymbolDisplayParameterOptions.IncludeParamsRefOut Or SymbolDisplayParameterOptions.IncludeName),
+                "M(ByRef s, i, ParamArray args)",
+                SymbolDisplayPartKind.MethodName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.ParameterName,
+                SymbolDisplayPartKind.Punctuation)
         End Sub
 
         ' "Public" and "MustOverride" should not be included for interface members.
@@ -4603,6 +4653,140 @@ class Outer
             Assert.Equal(Nothing, SymbolDisplay.FormatPrimitive(New Object(), quoteStrings:=False, useHexadecimalNumbers:=False))
         End Sub
 
+        ' SymbolDisplayMemberOptions.IncludeRef is ignored in VB.
+        <WorkItem(11356, "https://github.com/dotnet/roslyn/issues/11356")>
+        <Fact()>
+        Public Sub RefReturn()
+            Dim sourceA =
+"public delegate ref int D();
+public class C
+{
+    public ref int F(ref int i) => ref i;
+    int _p;
+    public ref int P => ref _p;
+    public ref int this[int i] => ref _p;
+}"
+            Dim compA = CreateCSharpCompilation(GetUniqueName(), sourceA)
+            compA.VerifyDiagnostics()
+            Dim refA = compA.EmitToImageReference()
+            ' From C# symbols.
+            RefReturnInternal(compA)
+
+            Dim sourceB =
+        <compilation>
+            <file name="b.vb">
+            </file>
+        </compilation>
+            Dim compB = CompilationUtils.CreateCompilationWithMscorlib(sourceB, references:={refA})
+            compB.VerifyDiagnostics()
+            ' From VB symbols.
+            RefReturnInternal(compB)
+        End Sub
+
+        Private Shared Sub RefReturnInternal(comp As Compilation)
+            Dim formatWithRef = New SymbolDisplayFormat(
+                memberOptions:=SymbolDisplayMemberOptions.IncludeParameters Or SymbolDisplayMemberOptions.IncludeType Or SymbolDisplayMemberOptions.IncludeRef,
+                parameterOptions:=SymbolDisplayParameterOptions.IncludeType Or SymbolDisplayParameterOptions.IncludeParamsRefOut,
+                propertyStyle:=SymbolDisplayPropertyStyle.ShowReadWriteDescriptor,
+                delegateStyle:=SymbolDisplayDelegateStyle.NameAndSignature,
+                miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.UseSpecialTypes)
+
+            Dim [global] = comp.GlobalNamespace
+            Dim type = [global].GetTypeMembers("C").Single()
+            Dim method = type.GetMembers("F").Single()
+            Dim [property] = type.GetMembers("P").Single()
+            Dim indexer = type.GetMembers().Where(Function(m) m.Kind = SymbolKind.Property AndAlso DirectCast(m, IPropertySymbol).IsIndexer).Single()
+            Dim [delegate] = [global].GetTypeMembers("D").Single()
+
+            ' Method with IncludeRef.
+            ' https://github.com/dotnet/roslyn/issues/14683: missing ByRef for C# parameters.
+            If comp.Language = "C#" Then
+                Verify(
+                    SymbolDisplay.ToDisplayParts(method, formatWithRef),
+                    "F(Integer) As Integer",
+                    SymbolDisplayPartKind.MethodName,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword)
+            Else
+                Verify(
+                    SymbolDisplay.ToDisplayParts(method, formatWithRef),
+                    "F(ByRef Integer) As Integer",
+                    SymbolDisplayPartKind.MethodName,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword)
+            End If
+
+            ' Property with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts([property], formatWithRef),
+                "ReadOnly P As Integer",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.PropertyName,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword)
+
+            ' Indexer with IncludeRef.
+            ' https://github.com/dotnet/roslyn/issues/14684: "this[]" for C# indexer.
+            If comp.Language = "C#" Then
+                Verify(
+                    SymbolDisplay.ToDisplayParts(indexer, formatWithRef),
+                    "ReadOnly this[](Integer) As Integer",
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.PropertyName,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword)
+            Else
+                Verify(
+                    SymbolDisplay.ToDisplayParts(indexer, formatWithRef),
+                    "ReadOnly Item(Integer) As Integer",
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.PropertyName,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Punctuation,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword,
+                    SymbolDisplayPartKind.Space,
+                    SymbolDisplayPartKind.Keyword)
+            End If
+
+            ' Delegate with IncludeRef.
+            Verify(
+                SymbolDisplay.ToDisplayParts([delegate], formatWithRef),
+                "Function D() As Integer",
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.DelegateName,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Punctuation,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword,
+                SymbolDisplayPartKind.Space,
+                SymbolDisplayPartKind.Keyword)
+        End Sub
+
         <Fact>
         Public Sub AliasInSpeculativeSemanticModel()
             Dim text =
@@ -4641,7 +4825,7 @@ End Class")
 
 #Region "Helpers"
 
-        Private Sub TestSymbolDescription(
+        Private Shared Sub TestSymbolDescription(
             text As XElement,
             findSymbol As Func(Of NamespaceSymbol, Symbol),
             format As SymbolDisplayFormat,
@@ -4685,7 +4869,7 @@ End Class")
             Verify(description, expectedText, kinds)
         End Sub
 
-        Private Sub TestSymbolDescription(
+        Private Shared Sub TestSymbolDescription(
             text As XElement,
             findSymbol As Func(Of NamespaceSymbol, Symbol),
             format As SymbolDisplayFormat,
@@ -4712,7 +4896,7 @@ End Class")
             Assert.Equal(expectedText, parts.ToDisplayString())
 
             If (kinds.Length > 0) Then
-                AssertEx.Equal(kinds, parts.Select(Function(d) d.Kind))
+                AssertEx.Equal(kinds, parts.Select(Function(p) p.Kind), itemInspector:=Function(p) $"SymbolDisplayPartKind.{p}")
             End If
 
             Return parts