Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quick info tests for patterns #43395

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6955,5 +6955,86 @@ class Program
Documentation("Summary text"),
Value($"\r\n{FeaturesResources.Value_colon}\r\n Value text"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
[WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
public async Task QuickInfoNotPattern1()
{
await TestAsync(@"
class Person
{
void Goo(object o)
{
if (o is not $$Person p)
{
}
}
}",
MainDescription("class Person"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
[WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
public async Task QuickInfoNotPattern2()
{
await TestAsync(@"
class Person
{
void Goo(object o)
{
if (o is $$not Person p)
{
}
}
}");
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
[WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
public async Task QuickInfoOrPattern1()
{
await TestAsync(@"
class Person
{
void Goo(object o)
{
if (o is $$Person or int)
{
}
}
}", MainDescription("class Person"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
[WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
public async Task QuickInfoOrPattern2()
{
await TestAsync(@"
class Person
{
void Goo(object o)
{
if (o is Person or $$int)
{
}
}
}", MainDescription("struct System.Int32"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
[WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
public async Task QuickInfoOrPattern3()
{
await TestAsync(@"
class Person
{
void Goo(object o)
{
if (o is Person $$or int)
{
}
}
}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ protected override ImmutableArray<TaggedText> TryGetNullabilityAnalysis(Workspac
}

var syntaxFacts = workspace.Services.GetLanguageServices(semanticModel.Language).GetRequiredService<ISyntaxFactsService>();
var bindableParent = syntaxFacts.GetBindableParent(token);
var symbolInfo = semanticModel.GetSymbolInfo(bindableParent, cancellationToken);
var bindableParent = syntaxFacts.TryGetBindableParent(token);
var symbolInfo = bindableParent != null ? semanticModel.GetSymbolInfo(bindableParent, cancellationToken) : default;

if (symbolInfo.Symbol == null || string.IsNullOrEmpty(symbolInfo.Symbol.Name))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,10 @@ private ImmutableArray<TaggedText> GetValueDocumentationContent(

var symbols = GetSymbolsFromToken(token, document.Project.Solution.Workspace, semanticModel, cancellationToken);

var bindableParent = syntaxFacts.GetBindableParent(token);
var overloads = semanticModel.GetMemberGroup(bindableParent, cancellationToken);
var bindableParent = syntaxFacts.TryGetBindableParent(token);
var overloads = bindableParent != null
? semanticModel.GetMemberGroup(bindableParent, cancellationToken)
: ImmutableArray<ISymbol>.Empty;

symbols = symbols.Where(IsOk)
.Where(s => IsAccessible(s, enclosingType))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable

using System;
using System.Collections.Immutable;
using System.Linq;
Expand Down Expand Up @@ -70,7 +72,7 @@ internal async Task<ImmutableArray<FinderLocation>> FindAllReferencesInDocumentA
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
var findParentNode = GetFindParentNodeFunction(syntaxFacts);

var normalReferences = await FindReferencesInDocumentWorkerAsync(methodSymbol, document, semanticModel, findParentNode, cancellationToken).ConfigureAwait(false);
Expand All @@ -82,7 +84,7 @@ internal async Task<ImmutableArray<FinderLocation>> FindAllReferencesInDocumentA
}

private static Func<SyntaxToken, SyntaxNode> GetFindParentNodeFunction(ISyntaxFactsService syntaxFacts)
=> t => syntaxFacts.GetBindableParent(t);
=> t => syntaxFacts.TryGetBindableParent(t) ?? t.Parent!;

private async Task<ImmutableArray<FinderLocation>> FindReferencesInDocumentWorkerAsync(
IMethodSymbol symbol,
Expand Down Expand Up @@ -122,7 +124,7 @@ private Task<ImmutableArray<FinderLocation>> FindPredefinedTypeReferencesAsync(
return SpecializedTasks.EmptyImmutableArray<FinderLocation>();
}

var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
return FindReferencesInDocumentAsync(symbol, document,
semanticModel,
t => IsPotentialReference(predefinedType, syntaxFacts, t),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ public static TokenSemanticInfo GetSemanticInfo(
else
{
aliasSymbol = semanticModel.GetAliasInfo(token.Parent!, cancellationToken);
var bindableParent = syntaxFacts.GetBindableParent(token);
var typeInfo = semanticModel.GetTypeInfo(bindableParent, cancellationToken);
var bindableParent = syntaxFacts.TryGetBindableParent(token);
var typeInfo = bindableParent != null ? semanticModel.GetTypeInfo(bindableParent, cancellationToken) : default;
type = typeInfo.Type;
convertedType = typeInfo.ConvertedType;
declaredSymbol = MapSymbol(semanticFacts.GetDeclaredSymbol(semanticModel, token, cancellationToken), type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,9 @@ private void CheckMemberId(SyntaxNode root, SyntaxNode node, int memberId)
Contract.ThrowIfFalse(index == memberId);
}

public SyntaxNode GetBindableParent(SyntaxToken token)
#nullable enable

public SyntaxNode? TryGetBindableParent(SyntaxToken token)
{
var node = token.Parent;
while (node != null)
Expand Down Expand Up @@ -1084,9 +1086,12 @@ public SyntaxNode GetBindableParent(SyntaxToken token)
node = parent;
}

return node;
// Patterns are never bindable (though their constituent types/exprs may be).
return node is PatternSyntax ? null : node;
}

#nullable disable

public IEnumerable<SyntaxNode> GetConstructors(SyntaxNode root, CancellationToken cancellationToken)
{
if (!(root is CompilationUnitSyntax compilationUnit))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,13 +373,14 @@ void GetPartsOfTupleExpression<TArgumentSyntax>(SyntaxNode node,
/// </summary>
TextSpan GetMemberBodySpanForSpeculativeBinding(SyntaxNode node);

#nullable enable
/// <summary>
/// Returns the parent node that binds to the symbols that the IDE prefers for features like
/// Quick Info and Find All References. For example, if the token is part of the type of
/// an object creation, the parenting object creation expression is returned so that binding
/// will return constructor symbols.
/// Returns the parent node that binds to the symbols that the IDE prefers for features like Quick Info and Find
/// All References. For example, if the token is part of the type of an object creation, the parenting object
/// creation expression is returned so that binding will return constructor symbols.
/// </summary>
SyntaxNode GetBindableParent(SyntaxToken token);
SyntaxNode? TryGetBindableParent(SyntaxToken token);
#nullable disable

IEnumerable<SyntaxNode> GetConstructors(SyntaxNode root, CancellationToken cancellationToken);
bool TryGetCorrespondingOpenBrace(SyntaxToken token, out SyntaxToken openBrace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageServices
Contract.ThrowIfFalse(index = memberId)
End Sub

Public Function GetBindableParent(token As SyntaxToken) As SyntaxNode Implements ISyntaxFacts.GetBindableParent
Public Function TryGetBindableParent(token As SyntaxToken) As SyntaxNode Implements ISyntaxFacts.TryGetBindableParent
Dim node = token.Parent
While node IsNot Nothing
Dim parent = node.Parent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,16 +329,15 @@ public IParameterSymbol FindParameterForArgument(SemanticModel semanticModel, Sy

public ImmutableArray<ISymbol> GetBestOrAllSymbols(SemanticModel semanticModel, SyntaxNode node, SyntaxToken token, CancellationToken cancellationToken)
{
switch (node)
{
case AssignmentExpressionSyntax assignment when token.Kind() == SyntaxKind.EqualsToken:
return GetDeconstructionAssignmentMethods(semanticModel, node).As<ISymbol>();
if (node == null)
return ImmutableArray<ISymbol>.Empty;

case ForEachVariableStatementSyntax deconstructionForeach when token.Kind() == SyntaxKind.InKeyword:
return GetDeconstructionForEachMethods(semanticModel, node).As<ISymbol>();
}

return GetSymbolInfo(semanticModel, node, token, cancellationToken).GetBestOrAllSymbols();
return node switch
{
AssignmentExpressionSyntax _ when token.Kind() == SyntaxKind.EqualsToken => GetDeconstructionAssignmentMethods(semanticModel, node).As<ISymbol>(),
ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => GetDeconstructionForEachMethods(semanticModel, node).As<ISymbol>(),
_ => GetSymbolInfo(semanticModel, node, token, cancellationToken).GetBestOrAllSymbols(),
};
}

private SymbolInfo GetSymbolInfo(SemanticModel semanticModel, SyntaxNode node, SyntaxToken token, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ internal interface ISemanticFactsService : ILanguageService

IParameterSymbol FindParameterForArgument(SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken);

ImmutableArray<ISymbol> GetBestOrAllSymbols(SemanticModel semanticModel, SyntaxNode node, SyntaxToken token, CancellationToken cancellationToken);
#nullable enable
ImmutableArray<ISymbol> GetBestOrAllSymbols(SemanticModel semanticModel, SyntaxNode? node, SyntaxToken token, CancellationToken cancellationToken);
#nullable disable

SyntaxToken GenerateUniqueName(
SemanticModel semanticModel, SyntaxNode location,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Function

Public Function GetBestOrAllSymbols(semanticModel As SemanticModel, node As SyntaxNode, token As SyntaxToken, cancellationToken As CancellationToken) As ImmutableArray(Of ISymbol) Implements ISemanticFactsService.GetBestOrAllSymbols
Return semanticModel.GetSymbolInfo(node, cancellationToken).GetBestOrAllSymbols()
Return If(node Is Nothing,
ImmutableArray(Of ISymbol).Empty,
semanticModel.GetSymbolInfo(node, cancellationToken).GetBestOrAllSymbols())
End Function

Private Function ISemanticFactsService_GenerateUniqueName(
Expand Down