diff --git a/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb index 0bcf0d758f3bd..43399ee20fe33 100644 --- a/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/CSharpInlineParameterNameHintsTests.vb @@ -2,11 +2,74 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Threading +Imports Microsoft.CodeAnalysis.InlineHints +Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Text + Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints Public Class CSharpInlineParameterNameHintsTests Inherits AbstractInlineHintsTests + Private Async Function VerifyParamHintsWithOptions(test As XElement, output As XElement, options As InlineParameterHintsOptions) As Task + Using workspace = EditorTestWorkspace.Create(test) + WpfTestRunner.RequireWpfFact($"{NameOf(CSharpInlineParameterNameHintsTests)}.{NameOf(Me.VerifyParamHintsWithOptions)} creates asynchronous taggers") + + Dim displayOptions = New SymbolDescriptionOptions() + + Dim hostDocument = workspace.Documents.Single() + Dim snapshot = hostDocument.GetTextBuffer().CurrentSnapshot + Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) + Dim tagService = document.GetRequiredLanguageService(Of IInlineParameterNameHintsService) + + Dim span = If(hostDocument.SelectedSpans.Any(), hostDocument.SelectedSpans.Single(), New TextSpan(0, snapshot.Length)) + Dim inlineHints = ArrayBuilder(Of InlineHint).GetInstance() + + Await tagService.AddInlineHintsAsync( + document, span, options, displayOptions, displayAllOverride:=False, inlineHints, CancellationToken.None) + + Dim producedTags = From hint In inlineHints + Select hint.DisplayParts.GetFullText().TrimEnd() + hint.Span.ToString + + ValidateSpans(hostDocument, producedTags) + + Dim outWorkspace = EditorTestWorkspace.Create(output) + Dim expectedDocument = outWorkspace.CurrentSolution.GetDocument(outWorkspace.Documents.Single().Id) + Await ValidateDoubleClick(document, expectedDocument, inlineHints) + End Using + End Function + + Private Shared Sub ValidateSpans(hostDocument As TestHostDocument, producedTags As IEnumerable(Of String)) + Dim expectedTags As New List(Of String) + + Dim nameAndSpansList = hostDocument.AnnotatedSpans.SelectMany( + Function(name) name.Value, + Function(name, span) New With {.Name = name.Key, span}) + + For Each nameAndSpan In nameAndSpansList.OrderBy(Function(x) x.span.Start) + expectedTags.Add(nameAndSpan.Name + ":" + nameAndSpan.span.ToString()) + Next + + AssertEx.Equal(expectedTags, producedTags) + End Sub + + Private Shared Async Function ValidateDoubleClick(document As Document, expectedDocument As Document, inlineHints As ArrayBuilder(Of InlineHint)) As Task + Dim textChanges = New List(Of TextChange) + For Each inlineHint In inlineHints + If inlineHint.ReplacementTextChange IsNot Nothing Then + textChanges.Add(inlineHint.ReplacementTextChange.Value) + End If + Next + + Dim value = Await document.GetTextAsync().ConfigureAwait(False) + Dim newText = value.WithChanges(textChanges).ToString() + Dim expectedText = Await expectedDocument.GetTextAsync().ConfigureAwait(False) + + AssertEx.Equal(expectedText.ToString(), newText) + End Function + Public Async Function TestNoParameterSimpleCase() As Task Dim input = @@ -1388,5 +1451,216 @@ class C Await VerifyParamHints(input, output) End Function + + + Public Async Function TestSuppressForCaseInsensitiveMatch() As Task + Dim input = + + + +class A +{ + void fn(int fooBar) + { + } + + void Main() + { + int FooBar = 5; + fn(FooBar); + } +} + + + + + Await VerifyParamHints(input, input) + End Function + + + Public Async Function TestSuppressForUnderscorePrefixMatch() As Task + Dim input = + + + +class A +{ + void fn(int fooBar) + { + } + + void Main() + { + int _fooBar = 5; + fn(_fooBar); + } +} + + + + + Await VerifyParamHints(input, input) + End Function + + + Public Async Function TestSuppressForUnderscoreInNameMatch() As Task + Dim input = + + + +class A +{ + void fn(int fooBar) + { + } + + void Main() + { + int FOO_BAR = 5; + fn(FOO_BAR); + } +} + + + + + Await VerifyParamHints(input, input) + End Function + + + Public Async Function TestSuppressForParameterDifferingByTrailingUnderscore() As Task + Dim input = + + + +class A +{ + void fn(int fooBar) + { + } + + void Main() + { + int fooBar_ = 5; + fn(fooBar_); + } +} + + + + + Dim options = New InlineParameterHintsOptions() With + { + .EnabledForParameters = True, + .SuppressForParametersThatDifferOnlyBySuffix = True + } + + Await VerifyParamHintsWithOptions(input, input, options) + End Function + + + Public Async Function TestSuppressForArgumentDifferingByTrailingUnderscore() As Task + Dim input = + + + +class A +{ + void fn(int fooBar_) + { + } + + void Main() + { + int fooBar = 5; + fn(fooBar); + } +} + + + + + Dim options = New InlineParameterHintsOptions() With + { + .EnabledForParameters = True, + .SuppressForParametersThatDifferOnlyBySuffix = True + } + + Await VerifyParamHintsWithOptions(input, input, options) + End Function + + + Public Async Function TestSuppressForMemberAccessMatch() As Task + Dim input = + + + +class Vector2 +{ + public int X; + public int Y; +} + +class A +{ + void Create(int x, int y) + { + } + + void Main() + { + var foo = new Vector2(); + Create(foo.X, foo.Y); + } +} + + + + + Dim options = New InlineParameterHintsOptions() With + { + .EnabledForParameters = True, + .SuppressForParametersThatMatchMemberName = True + } + + Await VerifyParamHintsWithOptions(input, input, options) + End Function + + + Public Async Function TestSuppressForMemberAccessMatchCaseInsensitive() As Task + Dim input = + + + +class Vector2 +{ + public int x; + public int y; +} + +class A +{ + void Create(int X, int Y) + { + } + + void Main() + { + var foo = new Vector2(); + Create(foo.x, foo.y); + } +} + + + + + Dim options = New InlineParameterHintsOptions() With + { + .EnabledForParameters = True, + .SuppressForParametersThatMatchMemberName = True + } + + Await VerifyParamHintsWithOptions(input, input, options) + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb b/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb index e400a059e332a..25a2e4c512821 100644 --- a/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb +++ b/src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb @@ -2,11 +2,74 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Threading +Imports Microsoft.CodeAnalysis.InlineHints +Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Text + Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints Public NotInheritable Class CSharpInlineTypeHintsTests Inherits AbstractInlineHintsTests + Private Async Function VerifyTypeHintsWithOptions(test As XElement, output As XElement, options As InlineTypeHintsOptions) As Task + Using workspace = EditorTestWorkspace.Create(test) + WpfTestRunner.RequireWpfFact($"{NameOf(CSharpInlineTypeHintsTests)}.{NameOf(Me.VerifyTypeHintsWithOptions)} creates asynchronous taggers") + + Dim displayOptions = New SymbolDescriptionOptions() + + Dim hostDocument = workspace.Documents.Single() + Dim snapshot = hostDocument.GetTextBuffer().CurrentSnapshot + Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) + Dim tagService = document.GetRequiredLanguageService(Of IInlineTypeHintsService) + + Dim span = If(hostDocument.SelectedSpans.Any(), hostDocument.SelectedSpans.Single(), New TextSpan(0, snapshot.Length)) + Dim typeHints = ArrayBuilder(Of InlineHint).GetInstance() + + Await tagService.AddInlineHintsAsync( + document, span, options, displayOptions, displayAllOverride:=False, typeHints, CancellationToken.None) + + Dim producedTags = From hint In typeHints + Select hint.DisplayParts.GetFullText() + ":" + hint.Span.ToString() + + ValidateSpans(hostDocument, producedTags) + + Dim outWorkspace = EditorTestWorkspace.Create(output) + Dim expectedDocument = outWorkspace.CurrentSolution.GetDocument(outWorkspace.Documents.Single().Id) + Await ValidateDoubleClick(document, expectedDocument, typeHints) + End Using + End Function + + Private Shared Sub ValidateSpans(hostDocument As TestHostDocument, producedTags As IEnumerable(Of String)) + Dim expectedTags As New List(Of String) + + Dim nameAndSpansList = hostDocument.AnnotatedSpans.SelectMany( + Function(name) name.Value, + Function(name, span) New With {.Name = name.Key, span}) + + For Each nameAndSpan In nameAndSpansList.OrderBy(Function(x) x.span.Start) + expectedTags.Add(nameAndSpan.Name + ":" + nameAndSpan.span.ToString()) + Next + + AssertEx.Equal(expectedTags, producedTags) + End Sub + + Private Shared Async Function ValidateDoubleClick(document As Document, expectedDocument As Document, typeHints As ArrayBuilder(Of InlineHint)) As Task + Dim textChanges = New List(Of TextChange) + For Each inlineHint In typeHints + If inlineHint.ReplacementTextChange IsNot Nothing Then + textChanges.Add(inlineHint.ReplacementTextChange.Value) + End If + Next + + Dim value = Await document.GetTextAsync().ConfigureAwait(False) + Dim newText = value.WithChanges(textChanges).ToString() + Dim expectedText = Await expectedDocument.GetTextAsync().ConfigureAwait(False) + + AssertEx.Equal(expectedText.ToString(), newText) + End Function + Public Async Function TestNotOnLocalVariableWithType() As Task Dim input = @@ -965,5 +1028,113 @@ class A Await VerifyTypeHints(input, output) End Function + + + Public Async Function TestSuppressForTargetTypedNew() As Task + Dim input = + + + +class Vector2 +{ +} + +class A +{ + void Main() + { + Vector2 foo = new(); + } +} + + + + + Dim options = New InlineTypeHintsOptions() With + { + .EnabledForTypes = True, + .ForImplicitObjectCreation = True, + .SuppressForTargetTypedNew = True + } + + Await VerifyTypeHintsWithOptions(input, input, options) + End Function + + + Public Async Function TestSuppressForTargetTypedCollectionExpression() As Task + Dim input = + + + +class A +{ + void Main() + { + int[] arr = [1, 2, 3]; + } +} + + + + + Dim options = New InlineTypeHintsOptions() With + { + .EnabledForTypes = True, + .ForCollectionExpressions = True, + .SuppressForTargetTypedCollectionExpressions = True + } + + Await VerifyTypeHintsWithOptions(input, input, options) + End Function + + + Public Async Function TestShowForNonTargetTypedNew() As Task + Dim input = + + + +class Vector2 +{ +} + +class A +{ + void Main() + { + var foo = {|Vector2 :|}new(); + } +} + + + + + Dim output = + + + +class Vector2 +{ +} + +class A +{ + void Main() + { + var foo = new Vector2(); + } +} + + + + + Dim options = New InlineTypeHintsOptions() With + { + .EnabledForTypes = True, + .ForImplicitObjectCreation = True, + .SuppressForTargetTypedNew = True + } + + Await VerifyTypeHintsWithOptions(input, output, options) + End Function End Class End Namespace diff --git a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs index c9a62a7514ca0..badd9dd0068e6 100644 --- a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs +++ b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs @@ -26,6 +26,8 @@ internal sealed class CSharpInlineTypeHintsService() : AbstractInlineTypeHintsSe bool forLambdaParameterTypes, bool forImplicitObjectCreation, bool forCollectionExpressions, + bool suppressForTargetTypedNew, + bool suppressForTargetTypedCollectionExpressions, CancellationToken cancellationToken) { if (forImplicitVariableTypes || displayAllOverride) @@ -91,6 +93,10 @@ internal sealed class CSharpInlineTypeHintsService() : AbstractInlineTypeHintsSe var type = semanticModel.GetTypeInfo(implicitNew, cancellationToken).Type; if (IsValidType(type)) { + // Check if this is target-typed (i.e., the type is locally apparent from context) + if (suppressForTargetTypedNew && IsTargetTyped(implicitNew)) + return null; + var span = new TextSpan(implicitNew.NewKeyword.Span.End, 0); return new(type, span, new TextChange(span, " " + GetTypeDisplayString(type)), leadingSpace: true); } @@ -104,6 +110,10 @@ internal sealed class CSharpInlineTypeHintsService() : AbstractInlineTypeHintsSe var type = semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType; if (IsValidType(type)) { + // Check if this is target-typed (i.e., the type is locally apparent from context) + if (suppressForTargetTypedCollectionExpressions && IsTargetTyped(collectionExpression)) + return null; + var span = new TextSpan(collectionExpression.OpenBracketToken.SpanStart, 0); // We pass null for the TextChange in collection expressions because @@ -156,4 +166,45 @@ private static bool IsValidType([NotNullWhen(true)] ITypeSymbol? type) { return type is not null and not IErrorTypeSymbol && type.Name != "var"; } + + private static bool IsTargetTyped(SyntaxNode node) + { + // Check if the expression is in a context where the type is locally apparent + // from the surrounding code (target-typed context). + // Examples: + // - Variable declaration: Vector2 foo = new(...); + // - Assignment: typedVar = new(...); + // - Collection expression: int[] arr = [1, 2, 3]; + // - Return statement: return new(...); (when method has explicit return type) + // - Argument: Method(new(...)); (when parameter type is known) + + var parent = node.Parent; + + // Check for variable declaration: Type name = new(...) or Type name = [...] + if (parent is EqualsValueClauseSyntax equalsValue && + equalsValue.Parent is VariableDeclaratorSyntax variableDeclarator && + variableDeclarator.Parent is VariableDeclarationSyntax variableDeclaration && + !variableDeclaration.Type.IsVar) + { + return true; + } + + // Check for assignment: variable = new(...) or variable = [...] + // The assignment operator itself provides target typing context + if (parent is AssignmentExpressionSyntax) + { + return true; + } + + // Check for return statement + // The method's return type provides target typing context + if (parent is ReturnStatementSyntax) + { + return true; + } + + // Could also check for: argument expressions, array initializers, etc. + // but keeping it simple for now with the most common cases + return false; + } } diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs index e1719337135ac..2bbd00d1b14f2 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs @@ -55,6 +55,7 @@ public async Task AddInlineHintsAsync( var suppressForParametersThatDifferOnlyBySuffix = !displayAllOverride && options.SuppressForParametersThatDifferOnlyBySuffix; var suppressForParametersThatMatchMethodIntent = !displayAllOverride && options.SuppressForParametersThatMatchMethodIntent; var suppressForParametersThatMatchArgumentName = !displayAllOverride && options.SuppressForParametersThatMatchArgumentName; + var suppressForParametersThatMatchMemberName = !displayAllOverride && options.SuppressForParametersThatMatchMemberName; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -99,6 +100,12 @@ void AddHintsIfAppropriate(SyntaxNode node) if (suppressForParametersThatMatchArgumentName && ParameterMatchesArgumentName(argument, parameter, syntaxFacts)) continue; + if (suppressForParametersThatDifferOnlyBySuffix && ParameterDiffersOnlyBySuffix(argument, parameter, syntaxFacts)) + continue; + + if (suppressForParametersThatMatchMemberName && ParameterMatchesMemberAccessName(argument, parameter, syntaxFacts)) + continue; + if (!indexerParameters && IsIndexer(node, parameter)) continue; @@ -279,7 +286,91 @@ static bool SuffixMatchesParameterName(ReadOnlyMemory suffix, string param private static bool ParameterMatchesArgumentName(SyntaxNode argument, IParameterSymbol parameter, ISyntaxFactsService syntaxFacts) { var argumentName = GetIdentifierNameFromArgument(argument, syntaxFacts); - return syntaxFacts.StringComparer.Compare(parameter.Name, argumentName) == 0; + if (string.IsNullOrEmpty(argumentName)) + return false; + + // First, try exact match + if (syntaxFacts.StringComparer.Compare(parameter.Name, argumentName) == 0) + return true; + + // Try normalized comparison (case-insensitive and ignoring underscores) + return NormalizeIdentifier(parameter.Name).Equals(NormalizeIdentifier(argumentName), StringComparison.OrdinalIgnoreCase); + } + + private static bool ParameterDiffersOnlyBySuffix(SyntaxNode argument, IParameterSymbol parameter, ISyntaxFactsService syntaxFacts) + { + var argumentName = GetIdentifierNameFromArgument(argument, syntaxFacts); + if (string.IsNullOrEmpty(argumentName) || string.IsNullOrEmpty(parameter.Name)) + return false; + + // Check if parameter and argument differ only by a trailing underscore or single character suffix + // Cases to handle: + // 1. fooBar vs fooBar_ + // 2. fooBar_ vs fooBar + // 3. fooBar vs fooBarX (where X is A-Z) + // 4. fooBarX vs fooBar + + // Check if one is prefix of another with single character difference + if (argumentName.Length == parameter.Name.Length + 1) + { + // argument is longer (e.g., fooBar_ vs fooBar) + if (argumentName.StartsWith(parameter.Name, StringComparison.Ordinal)) + { + var suffix = argumentName[^1]; + return suffix == '_' || IsUpperAlpha(suffix) || IsNumeric(suffix); + } + } + else if (parameter.Name.Length == argumentName.Length + 1) + { + // parameter is longer (e.g., fooBar vs fooBar_) + if (parameter.Name.StartsWith(argumentName, StringComparison.Ordinal)) + { + var suffix = parameter.Name[^1]; + return suffix == '_' || IsUpperAlpha(suffix) || IsNumeric(suffix); + } + } + + return false; + + static bool IsUpperAlpha(char c) => char.IsUpper(c); + static bool IsNumeric(char c) => char.IsDigit(c); + } + + private static bool ParameterMatchesMemberAccessName(SyntaxNode argument, IParameterSymbol parameter, ISyntaxFactsService syntaxFacts) + { + var memberName = GetMemberNameFromArgument(argument, syntaxFacts); + if (string.IsNullOrEmpty(memberName)) + return false; + + // Check if member name matches parameter name (normalized, case-insensitive) + return NormalizeIdentifier(parameter.Name).Equals(NormalizeIdentifier(memberName), StringComparison.OrdinalIgnoreCase); + } + + private static string GetMemberNameFromArgument(SyntaxNode argument, ISyntaxFactsService syntaxFacts) + { + var expression = + syntaxFacts.IsArgument(argument) ? syntaxFacts.GetExpressionOfArgument(argument) : + syntaxFacts.IsAttributeArgument(argument) ? syntaxFacts.GetExpressionOfAttributeArgument(argument) : null; + + // Check if the expression is a member access (e.g., foo.X) + if (syntaxFacts.IsMemberAccessExpression(expression)) + { + var memberNameSyntax = syntaxFacts.GetNameOfMemberAccessExpression(expression); + if (syntaxFacts.IsIdentifierName(memberNameSyntax)) + { + var identifier = syntaxFacts.GetIdentifierOfIdentifierName(memberNameSyntax); + return identifier.ValueText; + } + } + + return string.Empty; + } + + private static string NormalizeIdentifier(string identifier) + { + // Remove leading underscores and @ prefixes for comparison + var normalized = identifier.TrimStart('_', '@'); + return normalized.Replace("_", ""); } protected static string GetIdentifierNameFromArgument(SyntaxNode argument, ISyntaxFactsService syntaxFacts) diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs index c184b2262612d..cc8e89e3a4bdc 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs @@ -26,6 +26,8 @@ internal abstract class AbstractInlineTypeHintsService : IInlineTypeHintsService bool forLambdaParameterTypes, bool forImplicitObjectCreation, bool forCollectionExpressions, + bool suppressForTargetTypedNew, + bool suppressForTargetTypedCollectionExpressions, CancellationToken cancellationToken); public async Task AddInlineHintsAsync( @@ -48,6 +50,9 @@ public async Task AddInlineHintsAsync( if (!forImplicitVariableTypes && !forLambdaParameterTypes && !forImplicitObjectCreation && !forCollectionExpressions && !displayAllOverride) return; + var suppressForTargetTypedNew = !displayAllOverride && options.SuppressForTargetTypedNew; + var suppressForTargetTypedCollectionExpressions = !displayAllOverride && options.SuppressForTargetTypedCollectionExpressions; + var anonymousTypeService = document.GetRequiredLanguageService(); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -61,6 +66,8 @@ public async Task AddInlineHintsAsync( forLambdaParameterTypes, forImplicitObjectCreation, forCollectionExpressions, + suppressForTargetTypedNew, + suppressForTargetTypedCollectionExpressions, cancellationToken); if (hint is not var (type, span, textChange, prefix, suffix)) continue; diff --git a/src/Features/Core/Portable/InlineHints/InlineParameterHintsOptions.cs b/src/Features/Core/Portable/InlineHints/InlineParameterHintsOptions.cs index 622f992a8808e..0156019d43c06 100644 --- a/src/Features/Core/Portable/InlineHints/InlineParameterHintsOptions.cs +++ b/src/Features/Core/Portable/InlineHints/InlineParameterHintsOptions.cs @@ -17,6 +17,7 @@ internal readonly record struct InlineParameterHintsOptions [DataMember] public bool SuppressForParametersThatDifferOnlyBySuffix { get; init; } = true; [DataMember] public bool SuppressForParametersThatMatchMethodIntent { get; init; } = true; [DataMember] public bool SuppressForParametersThatMatchArgumentName { get; init; } = true; + [DataMember] public bool SuppressForParametersThatMatchMemberName { get; init; } = true; public InlineParameterHintsOptions() { diff --git a/src/Features/Core/Portable/InlineHints/InlineTypeHintsOptions.cs b/src/Features/Core/Portable/InlineHints/InlineTypeHintsOptions.cs index 337eeb1cc5e4b..98f433bc1ee87 100644 --- a/src/Features/Core/Portable/InlineHints/InlineTypeHintsOptions.cs +++ b/src/Features/Core/Portable/InlineHints/InlineTypeHintsOptions.cs @@ -14,6 +14,8 @@ internal readonly record struct InlineTypeHintsOptions [DataMember] public bool ForLambdaParameterTypes { get; init; } = true; [DataMember] public bool ForImplicitObjectCreation { get; init; } = true; [DataMember] public bool ForCollectionExpressions { get; init; } = true; + [DataMember] public bool SuppressForTargetTypedNew { get; init; } = true; + [DataMember] public bool SuppressForTargetTypedCollectionExpressions { get; init; } = true; public InlineTypeHintsOptions() { diff --git a/src/LanguageServer/Protocol/Features/Options/InlineHintsOptionsStorage.cs b/src/LanguageServer/Protocol/Features/Options/InlineHintsOptionsStorage.cs index d927557243541..6abb43bfe2cc7 100644 --- a/src/LanguageServer/Protocol/Features/Options/InlineHintsOptionsStorage.cs +++ b/src/LanguageServer/Protocol/Features/Options/InlineHintsOptionsStorage.cs @@ -28,6 +28,7 @@ public static InlineParameterHintsOptions GetInlineParameterHintsOptions(this IG SuppressForParametersThatDifferOnlyBySuffix = globalOptions.GetOption(SuppressForParametersThatDifferOnlyBySuffix, language), SuppressForParametersThatMatchMethodIntent = globalOptions.GetOption(SuppressForParametersThatMatchMethodIntent, language), SuppressForParametersThatMatchArgumentName = globalOptions.GetOption(SuppressForParametersThatMatchArgumentName, language), + SuppressForParametersThatMatchMemberName = globalOptions.GetOption(SuppressForParametersThatMatchMemberName, language), }; public static InlineTypeHintsOptions GetInlineTypeHintsOptions(this IGlobalOptionService globalOptions, string language) @@ -38,6 +39,8 @@ public static InlineTypeHintsOptions GetInlineTypeHintsOptions(this IGlobalOptio ForLambdaParameterTypes = globalOptions.GetOption(ForLambdaParameterTypes, language), ForImplicitObjectCreation = globalOptions.GetOption(ForImplicitObjectCreation, language), ForCollectionExpressions = globalOptions.GetOption(ForCollectionExpressions, language), + SuppressForTargetTypedNew = globalOptions.GetOption(SuppressForTargetTypedNew, language), + SuppressForTargetTypedCollectionExpressions = globalOptions.GetOption(SuppressForTargetTypedCollectionExpressions, language), }; // Note: inlay hints is the term used in LSP, we Want to use the LSP name when communicate with the LSP client. @@ -85,6 +88,11 @@ public static InlineTypeHintsOptions GetInlineTypeHintsOptions(this IGlobalOptio InlineParameterHintsOptions.Default.SuppressForParametersThatMatchArgumentName, group: s_inlayHintOptionGroup); + public static readonly PerLanguageOption2 SuppressForParametersThatMatchMemberName = + new("dotnet_suppress_inlay_hints_for_parameters_that_match_member_name", + InlineParameterHintsOptions.Default.SuppressForParametersThatMatchMemberName, + group: s_inlayHintOptionGroup); + // Type Hints public static readonly PerLanguageOption2 EnabledForTypes = @@ -111,4 +119,14 @@ public static InlineTypeHintsOptions GetInlineTypeHintsOptions(this IGlobalOptio new("csharp_enable_inlay_hints_for_collection_expressions", defaultValue: InlineTypeHintsOptions.Default.ForCollectionExpressions, group: s_inlayHintOptionGroup); + + public static readonly PerLanguageOption2 SuppressForTargetTypedNew = + new("csharp_suppress_inlay_hints_for_target_typed_new", + defaultValue: InlineTypeHintsOptions.Default.SuppressForTargetTypedNew, + group: s_inlayHintOptionGroup); + + public static readonly PerLanguageOption2 SuppressForTargetTypedCollectionExpressions = + new("csharp_suppress_inlay_hints_for_target_typed_collection_expressions", + defaultValue: InlineTypeHintsOptions.Default.SuppressForTargetTypedCollectionExpressions, + group: s_inlayHintOptionGroup); }