未验证 提交 f38ba3ab 编写于 作者: I Ivan Basov 提交者: GitHub

Completion missing members of lambda parameter in fault tolerance case (#34312)

上级 009fc006
......@@ -4651,6 +4651,239 @@ class C
End Using
End Function
Private Shared Function CreateThenIncludeTestCode(lambdaExpressionString As String, methodsDeclarationString As String) As XElement
Dim template = "<Document><![CDATA[
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace ThenIncludeIntellisenseBug
{
class Program
{
static void Main(string[] args)
{
var registrations = new List<Registration>().AsQueryable();
var reg = registrations.Include(r => r.Activities).ThenInclude([1]);
}
}
internal class Registration
{
public ICollection<Activity> Activities { get; set; }
}
public class Activity
{
public Task Task { get; set; }
}
public class Task
{
public string Name { get; set; }
}
public interface IIncludableQueryable<out TEntity, out TProperty> : IQueryable<TEntity>
{
}
public static class EntityFrameworkQuerybleExtensions
{
public static IIncludableQueryable<TEntity, TProperty> Include<TEntity, TProperty>(
this IQueryable<TEntity> source,
Expression<Func<TEntity, TProperty>> navigationPropertyPath)
where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
[2]
}
}]]></Document>"
Return XElement.Parse(template.Replace("[1]", lambdaExpressionString).Replace("[2]", methodsDeclarationString))
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenInclude(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(
completionImplementation,
CreateThenIncludeTestCode(
"b => b$$",
"
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, ICollection<TPreviousProperty>> source,
Expression<Func<TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, TPreviousProperty> source,
Expression<Func<TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeNoExpression(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(
completionImplementation,
CreateThenIncludeTestCode(
"b => b$$",
"
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, ICollection<TPreviousProperty>> source,
Func<TPreviousProperty, TProperty> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, TPreviousProperty> source,
Func<TPreviousProperty, TProperty> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgument(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(
completionImplementation,
CreateThenIncludeTestCode(
"0, b => b$$",
"
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, ICollection<TPreviousProperty>> source,
int a,
Expression<Func<TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, TPreviousProperty> source,
int a,
Expression<Func<TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgumentAndMultiArgumentLambda(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(
completionImplementation,
CreateThenIncludeTestCode(
"0, (a,b,c) => c$$)",
"
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, ICollection<TPreviousProperty>> source,
int a,
Expression<Func<string, string, TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, TPreviousProperty> source,
int a,
Expression<Func<string, string, TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgumentNoOverlap(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(
completionImplementation,
CreateThenIncludeTestCode(
"b => b.Task, b =>b$$",
"
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, ICollection<TPreviousProperty>> source,
Expression<Func<TPreviousProperty, TProperty>> navigationPropertyPath,
Expression<Func<TPreviousProperty, TProperty>> anotherNavigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, TPreviousProperty> source,
Expression<Func<TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsDoNotContainAny({"FirstOrDefault"})
state.AssertCompletionItemsContainAll({"Task"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgumentAndMultiArgumentLambdaWithNoLambdaOverlap(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(
completionImplementation,
CreateThenIncludeTestCode(
"0, (a,b,c) => c$$",
"
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, ICollection<TPreviousProperty>> source,
int a,
Expression<Func<string, TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
public static IIncludableQueryable<TEntity, TProperty> ThenInclude<TEntity, TPreviousProperty, TProperty>(
this IIncludableQueryable<TEntity, TPreviousProperty> source,
int a,
Expression<Func<string, string, TPreviousProperty, TProperty>> navigationPropertyPath) where TEntity : class
{
return default(IIncludableQueryable<TEntity, TProperty>);
}
"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"FirstOrDefault"})
state.AssertCompletionItemsDoNotContainAny({"Task"})
End Using
End Function
Private Class MultipleChangeCompletionProvider
Inherits CompletionProvider
......
......@@ -3143,6 +3143,231 @@ End Class
End Using
End Function
Private Shared Function CreateThenIncludeTestCode(lambdaExpressionString As String, methodsDeclarationString As String) As XElement
Dim template = "<Document><![CDATA[
Imports System.Linq.Expressions
Namespace ThenIncludeIntellisenseBug
Class Program
Shared Sub Main(args As String())
Dim registrations = New List(Of Registration)().AsQueryable()
Dim reg = registrations.Include(Function(r) r.Activities).ThenInclude([1])
End Sub
End Class
Friend Class Registration
Public Property Activities As ICollection(Of Activity)
End Class
Public Class Activity
Public Property Task As Task
End Class
Public Class Task
Public Property Name As String
End Class
Public Interface IIncludableQueryable(Of Out TEntity, Out TProperty)
Inherits IQueryable(Of TEntity)
End Interface
Public Module EntityFrameworkQuerybleExtensions
<System.Runtime.CompilerServices.Extension>
Public Function Include(Of TEntity, TProperty)(
source As IQueryable(Of TEntity),
navigationPropertyPath As Expression(Of Func(Of TEntity, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
[2]
End Module
End Namespace
]]></Document>"
Return XElement.Parse(template.Replace("[1]", lambdaExpressionString).Replace("[2]", methodsDeclarationString))
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenInclude(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
completionImplementation,
CreateThenIncludeTestCode(
"Function(b) b$$",
"
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, ICollection(Of TPreviousProperty)),
navigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, TPreviousProperty),
navigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeNoExpression(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
completionImplementation,
CreateThenIncludeTestCode(
"Function(b) b$$",
"
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, ICollection(Of TPreviousProperty)),
navigationPropertyPath As Func(Of TPreviousProperty, TProperty)) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, TPreviousProperty),
navigationPropertyPath As Func(Of TPreviousProperty, TProperty)) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgument(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
completionImplementation,
CreateThenIncludeTestCode(
"0, Function(b) b$$",
"
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, ICollection(Of TPreviousProperty)),
a as Integer,
navigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, TPreviousProperty),
a as Integer,
navigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgumentAndMultiArgumentLambda(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
completionImplementation,
CreateThenIncludeTestCode(
"0, Function(a, b, c) c$$",
"<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, ICollection(Of TPreviousProperty)),
a as Integer,
navigationPropertyPath As Expression(Of Func(Of string, string, TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, TPreviousProperty),
a as Integer,
navigationPropertyPath As Expression(Of Func(Of string, string, TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"Task", "FirstOrDefault"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgumentNoOverlap(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
completionImplementation,
CreateThenIncludeTestCode(
"Function(b) b.Task, Function(b) b$$",
"
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, ICollection(Of TPreviousProperty)),
navigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty)),
anotherNavigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, TPreviousProperty),
navigationPropertyPath As Expression(Of Func(Of TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsDoNotContainAny({"FirstOrDefault"})
state.AssertCompletionItemsContainAll({"Task"})
End Using
End Function
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestThenIncludeSecondArgumentAndMultiArgumentLambdaWithNoLambdaOverlap(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
completionImplementation,
CreateThenIncludeTestCode(
"0, Function(a, b, c) c$$",
"
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, ICollection(Of TPreviousProperty)),
a as Integer,
navigationPropertyPath As Expression(Of Func(Of string, TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ThenInclude(Of TEntity, TPreviousProperty, TProperty)(
source As IIncludableQueryable(Of TEntity, TPreviousProperty),
a as Integer,
navigationPropertyPath As Expression(Of Func(Of string, string, TPreviousProperty, TProperty))) As IIncludableQueryable(Of TEntity, TProperty)
Return Nothing
End Function
"))
state.SendTypeChars(".")
Await state.AssertCompletionSession()
state.AssertCompletionItemsContainAll({"FirstOrDefault"})
state.AssertCompletionItemsDoNotContainAny({"Task"})
End Using
End Function
<ExportLanguageService(GetType(ISnippetInfoService), LanguageNames.VisualBasic), System.Composition.Shared>
Friend Class MockSnippetInfoService
Implements ISnippetInfoService
......
......@@ -1431,8 +1431,8 @@ public bool IsCharacterLiteral(SyntaxToken token)
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfInvocationExpression(SyntaxNode invocationExpression)
=> GetArgumentsOfArgumentList((invocationExpression as InvocationExpressionSyntax)?.ArgumentList);
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfObjectCreationExpression(SyntaxNode invocationExpression)
=> GetArgumentsOfArgumentList((invocationExpression as ObjectCreationExpressionSyntax)?.ArgumentList);
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfObjectCreationExpression(SyntaxNode objectCreationExpression)
=> GetArgumentsOfArgumentList((objectCreationExpression as ObjectCreationExpressionSyntax)?.ArgumentList);
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfArgumentList(SyntaxNode argumentList)
=> (argumentList as BaseArgumentListSyntax)?.Arguments ?? default(SeparatedSyntaxList<SyntaxNode>);
......
......@@ -386,6 +386,7 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn
var excludeInstance = false;
var excludeStatic = false;
var symbol = leftHandBinding.GetAnySymbol();
ImmutableArray<ISymbol> symbols = default;
if (symbol != null)
{
......@@ -448,6 +449,8 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn
excludeStatic = true;
symbols = GetSymbols(parameter, originalExpression.SpanStart);
// case:
// base.|
if (parameter.IsThis && !object.Equals(parameter.Type, container))
......@@ -482,11 +485,14 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn
excludeStatic = false;
}
var symbols = GetSymbols(
container,
position: originalExpression.SpanStart,
excludeInstance: excludeInstance,
useBaseReferenceAccessibility: useBaseReferenceAccessibility);
if (symbols.IsDefault)
{
symbols = GetSymbols(
container,
position: originalExpression.SpanStart,
excludeInstance: excludeInstance,
useBaseReferenceAccessibility: useBaseReferenceAccessibility);
}
// If we're showing instance members, don't include nested types
return excludeStatic
......
......@@ -6,6 +6,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
......@@ -16,8 +20,8 @@ internal abstract class AbstractRecommendationServiceRunner<TSyntaxContext>
protected readonly CancellationToken _cancellationToken;
public AbstractRecommendationServiceRunner(
TSyntaxContext context,
bool filterOutOfScopeLocals,
TSyntaxContext context,
bool filterOutOfScopeLocals,
CancellationToken cancellationToken)
{
_context = context;
......@@ -27,6 +31,121 @@ internal abstract class AbstractRecommendationServiceRunner<TSyntaxContext>
public abstract ImmutableArray<ISymbol> GetSymbols();
// This code is to help give intellisense in the following case:
// query.Include(a => a.SomeProperty).ThenInclude(a => a.
// where there are more than one overloads of ThenInclude accepting different types of parameters.
protected ImmutableArray<ISymbol> GetSymbols(IParameterSymbol parameter, int position)
{
// Starting from a. in the example, looking for a => a.
if (!(parameter.ContainingSymbol is IMethodSymbol containingMethod &&
containingMethod.MethodKind == MethodKind.AnonymousFunction))
{
return default;
}
// Cannot proceed without DeclaringSyntaxReferences.
// We expect that there is a single DeclaringSyntaxReferences in the scenario.
// If anything changes on the compiler side, the approach should be revised.
if (containingMethod.DeclaringSyntaxReferences.Length != 1)
{
return default;
}
var syntaxFactsService = _context.Workspace.Services.GetLanguageServices(_context.SemanticModel.Language).GetService<ISyntaxFactsService>();
// Check that a => a. belongs to an invocation.
// Find its' ordinal in the invocation, e.g. ThenInclude(a => a.Something, a=> a.
var lambdaSyntax = containingMethod.DeclaringSyntaxReferences.Single().GetSyntax(_cancellationToken);
if (!(syntaxFactsService.IsAnonymousFunction(lambdaSyntax) &&
syntaxFactsService.IsArgument(lambdaSyntax.Parent) &&
syntaxFactsService.IsInvocationExpression(lambdaSyntax.Parent.Parent.Parent)))
{
return default;
}
var invocationExpression = lambdaSyntax.Parent.Parent.Parent;
var arguments = syntaxFactsService.GetArgumentsOfInvocationExpression(invocationExpression);
var ordinalInInvocation = arguments.IndexOf(lambdaSyntax.Parent);
var invocation = _context.SemanticModel.GetSymbolInfo(invocationExpression, _cancellationToken);
var candidateSymbols = invocation.GetAllSymbols();
// parameter.Ordinal is the ordinal within (a,b,c) => b.
// For candidate symbols of (a,b,c) => b., get types of all possible b.
var parameterTypeSymbols = GetTypeSymbols(candidateSymbols, ordinalInInvocation: ordinalInInvocation, ordinalInLambda: parameter.Ordinal);
// For each type of b., return all suitable members.
return parameterTypeSymbols
.SelectMany(parameterTypeSymbol => GetSymbols(parameterTypeSymbol, position, excludeInstance: false, useBaseReferenceAccessibility: false))
.ToImmutableArray();
}
/// <summary>
/// Tries to get a type of its' <paramref name="ordinalInLambda"/> lambda parameter of <paramref name="ordinalInInvocation"/> argument for each candidate symbol.
/// </summary>
/// <param name="candidateSymbols">symbols corresponding to <see cref="Expression{Func}"/> or <see cref="Func{some_args, TResult}"/>
/// Here, some_args can be multi-variables lambdas as well, e.g. f((a,b) => a+b, (a,b,c)=>a*b*c.Length)
/// </param>
/// <param name="ordinalInInvocation">ordinal of the arguments of function: (a,b) or (a,b,c) in the example above</param>
/// <param name="ordinalInLambda">ordinal of the lambda parameters, e.g. a, b or c.</param>
/// <returns></returns>
private ImmutableArray<ITypeSymbol> GetTypeSymbols(ImmutableArray<ISymbol> candidateSymbols, int ordinalInInvocation, int ordinalInLambda)
{
var expressionSymbol = _context.SemanticModel.Compilation.GetTypeByMetadataName(typeof(Expression<>).FullName);
var funcSymbol = _context.SemanticModel.Compilation.GetTypeByMetadataName(typeof(Func<>).FullName);
// We cannot help if semantic model is corrupted or incomplete (e.g. during solution loading) and those symbols are not loaded.
// Just bail out.
if (expressionSymbol == null || funcSymbol == null)
{
return default;
}
var builder = ArrayBuilder<ITypeSymbol>.GetInstance();
foreach (var candidateSymbol in candidateSymbols)
{
if (candidateSymbol is IMethodSymbol method)
{
if (method.Parameters.Length > ordinalInInvocation)
{
var methodParameterSymbool = method.Parameters[ordinalInInvocation];
var type = methodParameterSymbool.Type;
// If type is <see cref="Expression{TDelegate}"/>, ignore <see cref="Expression"/> and use TDelegate.
if (type is INamedTypeSymbol expressionSymbolNamedTypeCandidate &&
Equals(expressionSymbolNamedTypeCandidate.OriginalDefinition, expressionSymbol))
{
var allTypeArguments = type.GetAllTypeArguments();
if (allTypeArguments.Length != 1)
{
continue;
}
type = allTypeArguments[0];
}
// If type is <see cref="Func{TSomeArguments, TResult}"/>, extract TSomeArguments
// and find the type of thee argument corresponding to the ordinal.
if (type is INamedTypeSymbol funcSymbolNamedTypeCandidate &&
Equals(funcSymbolNamedTypeCandidate.Name, funcSymbol.Name) &&
Equals(funcSymbolNamedTypeCandidate.ContainingNamespace, funcSymbol.ContainingNamespace))
{
var allTypeArguments = type.GetAllTypeArguments();
if (allTypeArguments.Length < ordinalInLambda)
{
continue;
}
type = allTypeArguments[ordinalInLambda];
}
builder.Add(type);
}
}
}
return builder.ToImmutableAndFree().Distinct();
}
protected ImmutableArray<ISymbol> GetSymbolsForNamespaceDeclarationNameContext<TNamespaceDeclarationSyntax>()
where TNamespaceDeclarationSyntax : SyntaxNode
{
......
......@@ -12,7 +12,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
Inherits AbstractRecommendationServiceRunner(Of VisualBasicSyntaxContext)
Public Sub New(context As VisualBasicSyntaxContext, filterOutOfScopeLocals As Boolean, cancellationToken As CancellationToken)
MyBase.New(context, filterOutOfScopeLocals, cancellationToken)
End Sub
......@@ -54,7 +53,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function IsWritableFieldOrLocal(symbol As ISymbol) As Boolean
If symbol.Kind() = SymbolKind.Field Then
Dim field = DirectCast(symbol, IFieldSymbol)
Return Not field.IsReadOnly AndAlso Not field.IsConst
......@@ -69,12 +67,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function GetSymbolsForGlobalStatementContext() As ImmutableArray(Of ISymbol)
Return _context.SemanticModel.LookupSymbols(_context.TargetToken.Span.End)
End Function
Private Function GetUnqualifiedSymbolsForQueryIntoContext() As ImmutableArray(Of ISymbol)
Dim symbols = _context.SemanticModel _
.LookupSymbols(_context.TargetToken.SpanStart, includeReducedExtensionMethods:=True)
......@@ -89,7 +85,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function GetUnqualifiedSymbolsForRaiseEvent() As ImmutableArray(Of ISymbol)
Dim containingType = _context.SemanticModel.GetEnclosingSymbol(_context.Position, _cancellationToken).ContainingType
Return _context.SemanticModel _
......@@ -98,13 +93,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function GetUnqualifiedSymbolsForType() As ImmutableArray(Of ISymbol)
Dim symbols = _context.SemanticModel.LookupNamespacesAndTypes(_context.TargetToken.SpanStart)
Return FilterToValidAccessibleSymbols(symbols)
End Function
Private Function GetUnqualifiedSymbolsForExpressionOrStatementContext() As ImmutableArray(Of ISymbol)
Dim lookupPosition = _context.TargetToken.SpanStart
If _context.FollowsEndOfStatement Then
lookupPosition = _context.Position
......@@ -124,7 +117,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
' contexts, except within GetType
If Not _context.TargetToken.IsKind(SyntaxKind.OpenParenToken) OrElse
Not _context.TargetToken.Parent.IsKind(SyntaxKind.GetTypeExpression) Then
symbols = symbols.WhereAsArray(Function(s) Not IsInEligibleDelegate(s))
End If
......@@ -133,7 +125,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function IsInEligibleDelegate(s As ISymbol) As Boolean
If s.IsDelegateType() Then
Dim typeSymbol = DirectCast(s, ITypeSymbol)
Return typeSymbol.SpecialType <> SpecialType.System_Delegate
......@@ -143,7 +134,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function GetSymbolsForQualifiedNameSyntax(node As QualifiedNameSyntax) As ImmutableArray(Of ISymbol)
' We're in a name-only context, since if we were an expression we'd be a
' MemberAccessExpressionSyntax. Thus, let's do other namespaces and types.
Dim leftHandSymbolInfo = _context.SemanticModel.GetSymbolInfo(node.Left, _cancellationToken)
......@@ -173,7 +163,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function GetSymbolsForMemberAccessExpression(node As MemberAccessExpressionSyntax) As ImmutableArray(Of ISymbol)
Dim leftExpression = node.GetExpressionOfMemberAccessExpression(allowImplicitTarget:=True)
If leftExpression Is Nothing Then
Return ImmutableArray(Of ISymbol).Empty
......@@ -207,6 +196,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End If
Dim couldBeMergedNamespace = False
Dim symbols As ImmutableArray(Of ISymbol) = Nothing
If leftHandSymbolInfo.Symbol IsNot Nothing Then
......@@ -231,6 +221,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
excludeShared = False
End If
symbols = GetSymbols(parameter, node.SpanStart)
' case:
' MyBase.
If parameter.IsMe AndAlso parameter.Type IsNot container Then
......@@ -281,15 +273,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End If
Dim position = node.SpanStart
Dim symbols As ImmutableArray(Of ISymbol)
If couldBeMergedNamespace Then
symbols = leftHandSymbolInfo.CandidateSymbols _
If symbols.IsDefault Then
If couldBeMergedNamespace Then
symbols = leftHandSymbolInfo.CandidateSymbols _
.OfType(Of INamespaceSymbol) _
.SelectMany(Function(n) LookupSymbolsInContainer(n, position, excludeInstance)) _
.ToImmutableArray()
Else
symbols = GetSymbols(
container, position:=position, excludeInstance:=excludeInstance, useBaseReferenceAccessibility:=useBaseReferenceAccessibility)
Else
symbols = GetSymbols(
container, position:=position, excludeInstance:=excludeInstance, useBaseReferenceAccessibility:=useBaseReferenceAccessibility)
End If
End If
If excludeShared Then
......@@ -349,7 +342,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function GetEnclosingCtor(node As MemberAccessExpressionSyntax) As IMethodSymbol
Dim symbol = _context.SemanticModel.GetEnclosingSymbol(node.SpanStart, _cancellationToken)
While symbol IsNot Nothing
......@@ -363,7 +355,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function
Private Function FilterToValidAccessibleSymbols(symbols As ImmutableArray(Of ISymbol)) As ImmutableArray(Of ISymbol)
' If this is an Inherits or Implements statement, we filter out symbols which do not recursively contain accessible, valid types.
Dim inheritsContext = IsInheritsStatementContext(_context.TargetToken)
Dim implementsContext = IsImplementsStatementContext(_context.TargetToken)
......@@ -372,7 +363,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
Dim typeBlock = _context.TargetToken.Parent?.FirstAncestorOrSelf(Of TypeBlockSyntax)()
If typeBlock IsNot Nothing Then
Dim typeOrAssemblySymbol As ISymbol = _context.SemanticModel.GetDeclaredSymbol(typeBlock)
Dim typeOrAssemblySymbol As ISymbol = _context.SemanticModel.GetDeclaredSymbol(typeBlock, _cancellationToken)
If typeOrAssemblySymbol Is Nothing Then
typeOrAssemblySymbol = _context.SemanticModel.Compilation.Assembly
End If
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册