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

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

上级 009fc006
...@@ -4651,6 +4651,239 @@ class C ...@@ -4651,6 +4651,239 @@ class C
End Using End Using
End Function 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 Private Class MultipleChangeCompletionProvider
Inherits CompletionProvider Inherits CompletionProvider
......
...@@ -3143,6 +3143,231 @@ End Class ...@@ -3143,6 +3143,231 @@ End Class
End Using End Using
End Function 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> <ExportLanguageService(GetType(ISnippetInfoService), LanguageNames.VisualBasic), System.Composition.Shared>
Friend Class MockSnippetInfoService Friend Class MockSnippetInfoService
Implements ISnippetInfoService Implements ISnippetInfoService
......
...@@ -1431,8 +1431,8 @@ public bool IsCharacterLiteral(SyntaxToken token) ...@@ -1431,8 +1431,8 @@ public bool IsCharacterLiteral(SyntaxToken token)
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfInvocationExpression(SyntaxNode invocationExpression) public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfInvocationExpression(SyntaxNode invocationExpression)
=> GetArgumentsOfArgumentList((invocationExpression as InvocationExpressionSyntax)?.ArgumentList); => GetArgumentsOfArgumentList((invocationExpression as InvocationExpressionSyntax)?.ArgumentList);
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfObjectCreationExpression(SyntaxNode invocationExpression) public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfObjectCreationExpression(SyntaxNode objectCreationExpression)
=> GetArgumentsOfArgumentList((invocationExpression as ObjectCreationExpressionSyntax)?.ArgumentList); => GetArgumentsOfArgumentList((objectCreationExpression as ObjectCreationExpressionSyntax)?.ArgumentList);
public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfArgumentList(SyntaxNode argumentList) public SeparatedSyntaxList<SyntaxNode> GetArgumentsOfArgumentList(SyntaxNode argumentList)
=> (argumentList as BaseArgumentListSyntax)?.Arguments ?? default(SeparatedSyntaxList<SyntaxNode>); => (argumentList as BaseArgumentListSyntax)?.Arguments ?? default(SeparatedSyntaxList<SyntaxNode>);
......
...@@ -386,6 +386,7 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn ...@@ -386,6 +386,7 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn
var excludeInstance = false; var excludeInstance = false;
var excludeStatic = false; var excludeStatic = false;
var symbol = leftHandBinding.GetAnySymbol(); var symbol = leftHandBinding.GetAnySymbol();
ImmutableArray<ISymbol> symbols = default;
if (symbol != null) if (symbol != null)
{ {
...@@ -448,6 +449,8 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn ...@@ -448,6 +449,8 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn
excludeStatic = true; excludeStatic = true;
symbols = GetSymbols(parameter, originalExpression.SpanStart);
// case: // case:
// base.| // base.|
if (parameter.IsThis && !object.Equals(parameter.Type, container)) if (parameter.IsThis && !object.Equals(parameter.Type, container))
...@@ -482,11 +485,14 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn ...@@ -482,11 +485,14 @@ private ImmutableArray<ISymbol> GetSymbolsOffOfConditionalReceiver(ExpressionSyn
excludeStatic = false; excludeStatic = false;
} }
var symbols = GetSymbols( if (symbols.IsDefault)
{
symbols = GetSymbols(
container, container,
position: originalExpression.SpanStart, position: originalExpression.SpanStart,
excludeInstance: excludeInstance, excludeInstance: excludeInstance,
useBaseReferenceAccessibility: useBaseReferenceAccessibility); useBaseReferenceAccessibility: useBaseReferenceAccessibility);
}
// If we're showing instance members, don't include nested types // If we're showing instance members, don't include nested types
return excludeStatic return excludeStatic
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; 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. // 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.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Threading; using System.Threading;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
...@@ -27,6 +31,121 @@ internal abstract class AbstractRecommendationServiceRunner<TSyntaxContext> ...@@ -27,6 +31,121 @@ internal abstract class AbstractRecommendationServiceRunner<TSyntaxContext>
public abstract ImmutableArray<ISymbol> GetSymbols(); 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>() protected ImmutableArray<ISymbol> GetSymbolsForNamespaceDeclarationNameContext<TNamespaceDeclarationSyntax>()
where TNamespaceDeclarationSyntax : SyntaxNode where TNamespaceDeclarationSyntax : SyntaxNode
{ {
......
...@@ -12,7 +12,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -12,7 +12,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
Inherits AbstractRecommendationServiceRunner(Of VisualBasicSyntaxContext) Inherits AbstractRecommendationServiceRunner(Of VisualBasicSyntaxContext)
Public Sub New(context As VisualBasicSyntaxContext, filterOutOfScopeLocals As Boolean, cancellationToken As CancellationToken) Public Sub New(context As VisualBasicSyntaxContext, filterOutOfScopeLocals As Boolean, cancellationToken As CancellationToken)
MyBase.New(context, filterOutOfScopeLocals, cancellationToken) MyBase.New(context, filterOutOfScopeLocals, cancellationToken)
End Sub End Sub
...@@ -54,7 +53,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -54,7 +53,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function IsWritableFieldOrLocal(symbol As ISymbol) As Boolean Private Function IsWritableFieldOrLocal(symbol As ISymbol) As Boolean
If symbol.Kind() = SymbolKind.Field Then If symbol.Kind() = SymbolKind.Field Then
Dim field = DirectCast(symbol, IFieldSymbol) Dim field = DirectCast(symbol, IFieldSymbol)
Return Not field.IsReadOnly AndAlso Not field.IsConst Return Not field.IsReadOnly AndAlso Not field.IsConst
...@@ -69,12 +67,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -69,12 +67,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function GetSymbolsForGlobalStatementContext() As ImmutableArray(Of ISymbol) Private Function GetSymbolsForGlobalStatementContext() As ImmutableArray(Of ISymbol)
Return _context.SemanticModel.LookupSymbols(_context.TargetToken.Span.End) Return _context.SemanticModel.LookupSymbols(_context.TargetToken.Span.End)
End Function End Function
Private Function GetUnqualifiedSymbolsForQueryIntoContext() As ImmutableArray(Of ISymbol) Private Function GetUnqualifiedSymbolsForQueryIntoContext() As ImmutableArray(Of ISymbol)
Dim symbols = _context.SemanticModel _ Dim symbols = _context.SemanticModel _
.LookupSymbols(_context.TargetToken.SpanStart, includeReducedExtensionMethods:=True) .LookupSymbols(_context.TargetToken.SpanStart, includeReducedExtensionMethods:=True)
...@@ -89,7 +85,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -89,7 +85,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function GetUnqualifiedSymbolsForRaiseEvent() As ImmutableArray(Of ISymbol) Private Function GetUnqualifiedSymbolsForRaiseEvent() As ImmutableArray(Of ISymbol)
Dim containingType = _context.SemanticModel.GetEnclosingSymbol(_context.Position, _cancellationToken).ContainingType Dim containingType = _context.SemanticModel.GetEnclosingSymbol(_context.Position, _cancellationToken).ContainingType
Return _context.SemanticModel _ Return _context.SemanticModel _
...@@ -98,13 +93,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -98,13 +93,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function GetUnqualifiedSymbolsForType() As ImmutableArray(Of ISymbol) Private Function GetUnqualifiedSymbolsForType() As ImmutableArray(Of ISymbol)
Dim symbols = _context.SemanticModel.LookupNamespacesAndTypes(_context.TargetToken.SpanStart) Dim symbols = _context.SemanticModel.LookupNamespacesAndTypes(_context.TargetToken.SpanStart)
Return FilterToValidAccessibleSymbols(symbols) Return FilterToValidAccessibleSymbols(symbols)
End Function End Function
Private Function GetUnqualifiedSymbolsForExpressionOrStatementContext() As ImmutableArray(Of ISymbol) Private Function GetUnqualifiedSymbolsForExpressionOrStatementContext() As ImmutableArray(Of ISymbol)
Dim lookupPosition = _context.TargetToken.SpanStart Dim lookupPosition = _context.TargetToken.SpanStart
If _context.FollowsEndOfStatement Then If _context.FollowsEndOfStatement Then
lookupPosition = _context.Position lookupPosition = _context.Position
...@@ -124,7 +117,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -124,7 +117,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
' contexts, except within GetType ' contexts, except within GetType
If Not _context.TargetToken.IsKind(SyntaxKind.OpenParenToken) OrElse If Not _context.TargetToken.IsKind(SyntaxKind.OpenParenToken) OrElse
Not _context.TargetToken.Parent.IsKind(SyntaxKind.GetTypeExpression) Then Not _context.TargetToken.Parent.IsKind(SyntaxKind.GetTypeExpression) Then
symbols = symbols.WhereAsArray(Function(s) Not IsInEligibleDelegate(s)) symbols = symbols.WhereAsArray(Function(s) Not IsInEligibleDelegate(s))
End If End If
...@@ -133,7 +125,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -133,7 +125,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function IsInEligibleDelegate(s As ISymbol) As Boolean Private Function IsInEligibleDelegate(s As ISymbol) As Boolean
If s.IsDelegateType() Then If s.IsDelegateType() Then
Dim typeSymbol = DirectCast(s, ITypeSymbol) Dim typeSymbol = DirectCast(s, ITypeSymbol)
Return typeSymbol.SpecialType <> SpecialType.System_Delegate Return typeSymbol.SpecialType <> SpecialType.System_Delegate
...@@ -143,7 +134,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -143,7 +134,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function GetSymbolsForQualifiedNameSyntax(node As QualifiedNameSyntax) As ImmutableArray(Of ISymbol) 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 ' 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. ' MemberAccessExpressionSyntax. Thus, let's do other namespaces and types.
Dim leftHandSymbolInfo = _context.SemanticModel.GetSymbolInfo(node.Left, _cancellationToken) Dim leftHandSymbolInfo = _context.SemanticModel.GetSymbolInfo(node.Left, _cancellationToken)
...@@ -173,7 +163,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -173,7 +163,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function GetSymbolsForMemberAccessExpression(node As MemberAccessExpressionSyntax) As ImmutableArray(Of ISymbol) Private Function GetSymbolsForMemberAccessExpression(node As MemberAccessExpressionSyntax) As ImmutableArray(Of ISymbol)
Dim leftExpression = node.GetExpressionOfMemberAccessExpression(allowImplicitTarget:=True) Dim leftExpression = node.GetExpressionOfMemberAccessExpression(allowImplicitTarget:=True)
If leftExpression Is Nothing Then If leftExpression Is Nothing Then
Return ImmutableArray(Of ISymbol).Empty Return ImmutableArray(Of ISymbol).Empty
...@@ -207,6 +196,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -207,6 +196,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End If End If
Dim couldBeMergedNamespace = False Dim couldBeMergedNamespace = False
Dim symbols As ImmutableArray(Of ISymbol) = Nothing
If leftHandSymbolInfo.Symbol IsNot Nothing Then If leftHandSymbolInfo.Symbol IsNot Nothing Then
...@@ -231,6 +221,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -231,6 +221,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
excludeShared = False excludeShared = False
End If End If
symbols = GetSymbols(parameter, node.SpanStart)
' case: ' case:
' MyBase. ' MyBase.
If parameter.IsMe AndAlso parameter.Type IsNot container Then If parameter.IsMe AndAlso parameter.Type IsNot container Then
...@@ -281,7 +273,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -281,7 +273,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End If End If
Dim position = node.SpanStart Dim position = node.SpanStart
Dim symbols As ImmutableArray(Of ISymbol) If symbols.IsDefault Then
If couldBeMergedNamespace Then If couldBeMergedNamespace Then
symbols = leftHandSymbolInfo.CandidateSymbols _ symbols = leftHandSymbolInfo.CandidateSymbols _
.OfType(Of INamespaceSymbol) _ .OfType(Of INamespaceSymbol) _
...@@ -291,6 +283,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -291,6 +283,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
symbols = GetSymbols( symbols = GetSymbols(
container, position:=position, excludeInstance:=excludeInstance, useBaseReferenceAccessibility:=useBaseReferenceAccessibility) container, position:=position, excludeInstance:=excludeInstance, useBaseReferenceAccessibility:=useBaseReferenceAccessibility)
End If End If
End If
If excludeShared Then If excludeShared Then
symbols = symbols.WhereAsArray(Function(s) Not s.IsShared) symbols = symbols.WhereAsArray(Function(s) Not s.IsShared)
...@@ -349,7 +342,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -349,7 +342,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function GetEnclosingCtor(node As MemberAccessExpressionSyntax) As IMethodSymbol Private Function GetEnclosingCtor(node As MemberAccessExpressionSyntax) As IMethodSymbol
Dim symbol = _context.SemanticModel.GetEnclosingSymbol(node.SpanStart, _cancellationToken) Dim symbol = _context.SemanticModel.GetEnclosingSymbol(node.SpanStart, _cancellationToken)
While symbol IsNot Nothing While symbol IsNot Nothing
...@@ -363,7 +355,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -363,7 +355,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
End Function End Function
Private Function FilterToValidAccessibleSymbols(symbols As ImmutableArray(Of ISymbol)) As ImmutableArray(Of ISymbol) 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. ' 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 inheritsContext = IsInheritsStatementContext(_context.TargetToken)
Dim implementsContext = IsImplementsStatementContext(_context.TargetToken) Dim implementsContext = IsImplementsStatementContext(_context.TargetToken)
...@@ -372,7 +363,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations ...@@ -372,7 +363,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
Dim typeBlock = _context.TargetToken.Parent?.FirstAncestorOrSelf(Of TypeBlockSyntax)() Dim typeBlock = _context.TargetToken.Parent?.FirstAncestorOrSelf(Of TypeBlockSyntax)()
If typeBlock IsNot Nothing Then 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 If typeOrAssemblySymbol Is Nothing Then
typeOrAssemblySymbol = _context.SemanticModel.Compilation.Assembly typeOrAssemblySymbol = _context.SemanticModel.Compilation.Assembly
End If End If
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册