Skip to content

Commit b99876e

Browse files
Have inline hints display aliases if appropriate
1 parent 395d298 commit b99876e

File tree

3 files changed

+78
-31
lines changed

3 files changed

+78
-31
lines changed

src/EditorFeatures/Test2/InlineHints/CSharpInlineTypeHintsTests.vb

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.InlineHints
66
<Trait(Traits.Feature, Traits.Features.InlineHints)>
7-
Public Class CSharpInlineTypeHintsTests
7+
Public NotInheritable Class CSharpInlineTypeHintsTests
88
Inherits AbstractInlineHintsTests
99

1010
<WpfFact>
@@ -766,7 +766,7 @@ class A
766766
<Document>
767767
class A
768768
{
769-
void M(System.Threading.CancellationToken ct = new CancellationToken()) { }
769+
void M(System.Threading.CancellationToken ct = new System.Threading.CancellationToken()) { }
770770
}
771771
</Document>
772772
</Project>
@@ -889,5 +889,50 @@ class A
889889

890890
Await VerifyTypeHints(input, output)
891891
End Function
892+
893+
<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72219")>
894+
Public Async Function TestAlias() As Task
895+
Dim input =
896+
<Workspace>
897+
<Project Language="C#" CommonReferences="true">
898+
<Document>
899+
using System.Collections.Generic;
900+
using TestFile = (string Path, string Content);
901+
902+
class C
903+
{
904+
void M()
905+
{
906+
var {|List&lt;TestFile&gt; :|}testFiles = GetTestFiles();
907+
}
908+
909+
List&lt;TestFile&gt; GetTestFiles() => default;
910+
}
911+
</Document>
912+
</Project>
913+
</Workspace>
914+
915+
Dim output =
916+
<Workspace>
917+
<Project Language="C#" CommonReferences="true">
918+
<Document>
919+
using System.Collections.Generic;
920+
using TestFile = (string Path, string Content);
921+
922+
class C
923+
{
924+
void M()
925+
{
926+
List&lt;TestFile&gt; testFiles = GetTestFiles();
927+
}
928+
929+
List&lt;TestFile&gt; GetTestFiles() => default;
930+
}
931+
</Document>
932+
</Project>
933+
</Workspace>
934+
935+
Await VerifyTypeHints(input, output)
936+
End Function
892937
End Class
893938
End Namespace

src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,10 @@
1515
namespace Microsoft.CodeAnalysis.CSharp.InlineHints;
1616

1717
[ExportLanguageService(typeof(IInlineTypeHintsService), LanguageNames.CSharp), Shared]
18-
internal sealed class CSharpInlineTypeHintsService : AbstractInlineTypeHintsService
18+
[method: ImportingConstructor]
19+
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
20+
internal sealed class CSharpInlineTypeHintsService() : AbstractInlineTypeHintsService
1921
{
20-
[ImportingConstructor]
21-
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
22-
public CSharpInlineTypeHintsService()
23-
{
24-
}
25-
2622
protected override TypeHint? TryGetTypeHint(
2723
SemanticModel semanticModel,
2824
SyntaxNode node,
@@ -41,7 +37,7 @@ public CSharpInlineTypeHintsService()
4137
{
4238
var type = semanticModel.GetTypeInfo(variableDeclaration.Type, cancellationToken).Type;
4339
if (IsValidType(type))
44-
return CreateTypeHint(type, displayAllOverride, forImplicitVariableTypes, variableDeclaration.Type, variableDeclaration.Variables[0].Identifier);
40+
return CreateTypeHint(type, variableDeclaration.Type, variableDeclaration.Variables[0].Identifier);
4541
}
4642

4743
// We handle individual variables of ParenthesizedVariableDesignationSyntax separately.
@@ -51,7 +47,7 @@ public CSharpInlineTypeHintsService()
5147
{
5248
var type = semanticModel.GetTypeInfo(declarationExpression.Type, cancellationToken).Type;
5349
if (IsValidType(type))
54-
return CreateTypeHint(type, displayAllOverride, forImplicitVariableTypes, declarationExpression.Type, declarationExpression.Designation);
50+
return CreateTypeHint(type, declarationExpression.Type, declarationExpression.Designation);
5551
}
5652
else if (node is SingleVariableDesignationSyntax { Parent: not DeclarationPatternSyntax and not DeclarationExpressionSyntax } variableDesignation)
5753
{
@@ -60,7 +56,7 @@ public CSharpInlineTypeHintsService()
6056
if (IsValidType(type))
6157
{
6258
return node.Parent is VarPatternSyntax varPattern
63-
? CreateTypeHint(type, displayAllOverride, forImplicitVariableTypes, varPattern.VarKeyword, variableDesignation.Identifier)
59+
? CreateTypeHint(type, varPattern.VarKeyword, variableDesignation.Identifier)
6460
: new(type, new TextSpan(variableDesignation.Identifier.SpanStart, 0), textChange: null, trailingSpace: true);
6561
}
6662
}
@@ -69,7 +65,7 @@ public CSharpInlineTypeHintsService()
6965
var info = semanticModel.GetForEachStatementInfo(forEachStatement);
7066
var type = info.ElementType;
7167
if (IsValidType(type))
72-
return CreateTypeHint(type, displayAllOverride, forImplicitVariableTypes, forEachStatement.Type, forEachStatement.Identifier);
68+
return CreateTypeHint(type, forEachStatement.Type, forEachStatement.Identifier);
7369
}
7470
}
7571

@@ -83,7 +79,7 @@ public CSharpInlineTypeHintsService()
8379
IsValidType(parameter?.Type))
8480
{
8581
return parameterNode.Parent?.Parent?.Kind() is SyntaxKind.ParenthesizedLambdaExpression
86-
? new TypeHint(parameter.Type, span, textChange: new TextChange(span, parameter.Type.ToDisplayString(s_minimalTypeStyle) + " "), trailingSpace: true)
82+
? new TypeHint(parameter.Type, span, textChange: new TextChange(span, GetTypeDisplayString(parameter.Type) + " "), trailingSpace: true)
8783
: new TypeHint(parameter.Type, span, textChange: null, trailingSpace: true);
8884
}
8985
}
@@ -97,7 +93,7 @@ public CSharpInlineTypeHintsService()
9793
if (IsValidType(type))
9894
{
9995
var span = new TextSpan(implicitNew.NewKeyword.Span.End, 0);
100-
return new(type, span, new TextChange(span, " " + type.ToDisplayString(s_minimalTypeStyle)), leadingSpace: true);
96+
return new(type, span, new TextChange(span, " " + GetTypeDisplayString(type)), leadingSpace: true);
10197
}
10298
}
10399
}
@@ -110,26 +106,27 @@ public CSharpInlineTypeHintsService()
110106
if (IsValidType(type))
111107
{
112108
var span = new TextSpan(collectionExpression.OpenBracketToken.SpanStart, 0);
113-
return new(type, span, new TextChange(span, type.ToDisplayString(s_minimalTypeStyle)), leadingSpace: true);
109+
return new(type, span, new TextChange(span, GetTypeDisplayString(type)), leadingSpace: true);
114110
}
115111
}
116112
}
117113

118114
return null;
119-
}
120115

121-
private static TypeHint CreateTypeHint(
122-
ITypeSymbol type,
123-
bool displayAllOverride,
124-
bool normalOption,
125-
SyntaxNodeOrToken displayAllSpan,
126-
SyntaxNodeOrToken normalSpan)
127-
{
128-
var span = GetSpan(displayAllOverride, normalOption, displayAllSpan, normalSpan);
129-
// if this is a hint that is placed in-situ (i.e. it's not overwriting text like 'var'), then place
130-
// a space after it to make things feel less cramped.
131-
var trailingSpace = span.Length == 0;
132-
return new TypeHint(type, span, new TextChange(displayAllSpan.Span, type.ToDisplayString(s_minimalTypeStyle)), trailingSpace: trailingSpace);
116+
string GetTypeDisplayString(ITypeSymbol type)
117+
=> type.ToMinimalDisplayString(semanticModel, node.SpanStart, s_minimalTypeStyle);
118+
119+
TypeHint CreateTypeHint(
120+
ITypeSymbol type,
121+
SyntaxNodeOrToken displayAllSpan,
122+
SyntaxNodeOrToken normalSpan)
123+
{
124+
var span = GetSpan(displayAllOverride, forImplicitVariableTypes, displayAllSpan, normalSpan);
125+
// if this is a hint that is placed in-situ (i.e. it's not overwriting text like 'var'), then place
126+
// a space after it to make things feel less cramped.
127+
var trailingSpace = span.Length == 0;
128+
return new TypeHint(type, span, new TextChange(displayAllSpan.Span, GetTypeDisplayString(type)), trailingSpace: trailingSpace);
129+
}
133130
}
134131

135132
private static TextSpan GetSpan(

src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,13 @@ public async Task<ImmutableArray<InlineHint>> GetInlineHintsAsync(
7878
using var _2 = ArrayBuilder<SymbolDisplayPart>.GetInstance(out var finalParts);
7979
finalParts.AddRange(prefix);
8080

81-
var parts = type.ToDisplayParts(s_minimalTypeStyle);
82-
AddParts(anonymousTypeService, finalParts, parts, semanticModel, spanStart);
81+
// Try to get the minimal display string for the type. Try to use it if it's actually shorter (it may not
82+
// be as we've setup ToDisplayParts to only show the type name, while ToMinimalDisplayParts may show the
83+
// full name of the type if the short name doesn't bind. This will also help us use aliases if present.
84+
var minimalDisplayParts = type.ToMinimalDisplayParts(semanticModel, spanStart, s_minimalTypeStyle);
85+
var displayParts = type.ToDisplayParts(s_minimalTypeStyle);
86+
var preferredParts = minimalDisplayParts.Length <= displayParts.Length ? minimalDisplayParts : displayParts;
87+
AddParts(anonymousTypeService, finalParts, preferredParts, semanticModel, spanStart);
8388

8489
// If we have nothing to show, then don't bother adding this hint.
8590
if (finalParts.All(p => string.IsNullOrWhiteSpace(p.ToString())))

0 commit comments

Comments
 (0)