dotnet / dotnet/roslyn

VB SymbolDisplay.ToDisplayString doesn't use `Optional` keyword when `IncludeDefaultValue` and not `IncludeOptionalBrackets`

Open
#77,458 0 comments 0 reactions 0 assignees View on GitHub
Area-Compilers
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

I use `Microsoft.CodeAnalysis.VisualBasic.SymbolDisplay.ToDisplayString` to generate VB declarations from dll files and xml files in my API docs. I found that the `Optional` keyword is missing when generating optional parameters in method declarations when the `SymbolDisplayParameterOptions.IncludeDefaultValue` flag is set and `SymbolDisplayParameterOptions.IncludeOptionalBrackets` is not set.
I need to display VB declarations with the exactly the same format as Microsoft Learn. To work around this bug, I have to use `ToDisplayParts` and adjust the return value, which is very inconvenient.

**Version Used**:
4.13.0

**Steps to Reproduce**:

Create a VB console project

**VbSymbolDisplayCsOptional.vbproj**
```xml


Exe
VbSymbolDisplayCsOptional
net9.0




```

Edit `Program.vb`

**Program.vb**
```vbnet
Imports System.IO
Imports Microsoft.CodeAnalysis
Imports CS = Microsoft.CodeAnalysis.CSharp
Imports VB = Microsoft.CodeAnalysis.VisualBasic

Module Program

Sub Main()
' Create C# code with optional parameter
Dim csharpCode As String = "
using System;

public class Example
{
public void MethodWithOptional(string required, string str1 = ""default"", int number = 42)
{
Console.WriteLine($""{required}, {str1}, {number}"");
}
}"

' Compile the C# code
Dim compilation = CreateCompilationFromCSharpCode(csharpCode, "OptionalParamExample")

' Get the symbol for the method with optional parameters
Dim exampleClass = compilation.GetTypeByMetadataName("Example")
Dim methodSymbol = exampleClass.GetMembers().OfType(Of IMethodSymbol)().First(Function(m) m.Name = "MethodWithOptional")

' Create a VB symbol display format
Dim format = SymbolDisplayFormat.FullyQualifiedFormat.
WithMemberOptions(
SymbolDisplayMemberOptions.IncludeParameters).
WithParameterOptions(
SymbolDisplayParameterOptions.IncludeName Or
SymbolDisplayParameterOptions.IncludeType Or
SymbolDisplayParameterOptions.IncludeDefaultValue Or
SymbolDisplayParameterOptions.IncludeModifiers)

' Display the symbol using VB SymbolDisplay
Dim formattedSymbol = VB.SymbolDisplay.ToDisplayString(methodSymbol, format)
Console.WriteLine("Method signature in VB format:")
Console.WriteLine(formattedSymbol)

' Also display the parameter info separately for clarity
Console.WriteLine("Parameters:")
For Each parameter In methodSymbol.Parameters
Dim paramStr = VB.SymbolDisplay.ToDisplayString(parameter, format)
Dim hasDefaultValue = parameter.HasExplicitDefaultValue
Console.WriteLine($"- {paramStr} (Optional: {parameter.IsOptional}, Has Default: {hasDefaultValue})")
Next
End Sub

Public Function CreateCompilationFromCSharpCode(
code As String,
name As String,
ParamArray references As MetadataReference()) As Compilation

Dim parserOption As New CS.CSharpParseOptions
Dim syntaxTree = CS.CSharpSyntaxTree.ParseText(code, parserOption)

Return CS.CSharpCompilation.Create(
name,
options:=New CS.CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
xmlReferenceResolver:=XmlFileResolver.Default),
syntaxTrees:={syntaxTree},
references:=GetDefaultMetadataReferences().
Concat(If(references, Array.Empty(Of MetadataReference))))
End Function

Private Function GetDefaultMetadataReferences() As IEnumerable(Of MetadataReference)
Dim dirPath = Path.GetDirectoryName(GetType(Object).Assembly.Location)

Return From dll In Directory.EnumerateFiles(dirPath, "*.dll", SearchOption.TopDirectoryOnly)
Select MetadataReference.CreateFromFile(dll)
End Function

End Module
```

Run the project.

**Diagnostic Id**:

N/A

**Expected Behavior**:
The program produces the following output:
```console
Method signature in VB format:
MethodWithOptional(required As String, Optional str1 As String = "default", Optional number As Integer = 42)
Parameters:
- required As String (Optional: False, Has Default: False)
- Optional str1 As String = "default" (Optional: True, Has Default: True)
- Optional number As Integer = 42 (Optional: True, Has Default: True)
```

**Actual Behavior**:
The program produces the following output:
```console
Method signature in VB format:
MethodWithOptional(required As String, str1 As String = "default", number As Integer = 42)
Parameters:
- required As String (Optional: False, Has Default: False)
- str1 As String = "default" (Optional: True, Has Default: True)
- number As Integer = 42 (Optional: True, Has Default: True)
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.