提交 972bac30 编写于 作者: B Balaji Krishnan

Handle auto brace completion inside conditional access expressions. The...

Handle auto brace completion inside conditional access expressions.  The proper usage of GetSymbolInfo requires that we examine conditional access expressions and analyze their WhenNotNull Expression to determine if we're in a possible type argument scenario.
上级 f78e3f39
......@@ -3,6 +3,7 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editor.Implementation.AutomaticCompletion;
using Microsoft.CodeAnalysis.Editor.Implementation.AutomaticCompletion.Sessions;
......@@ -58,8 +59,21 @@ private bool PossibleTypeArgument(ITextSnapshot snapshot, SyntaxToken token, Can
}
var model = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var info = model.GetSymbolInfo(node.Left, cancellationToken);
// Analyze node on the left of < operator to verify if it is a generic type or method.
var leftNode = node.Left;
if (leftNode is ConditionalAccessExpressionSyntax)
{
// If node on the left is a conditional access expression, get the member binding expression
// from the innermost conditional acccess expression, which is the left of < operator.
// e.g: Case a?.b?.c< : we need to get the conditional access expression .b?.c and analyze its
// member binding expression (the .c) to see if it is a generic type/method.
// Case a?.b?.c.d< : we need to analyze .c.d
// Case a?.M(x => x?.P)?.M2< : We need to analyze .M2
leftNode = leftNode.GetInnerMostConditionalAccessExpression().WhenNotNull;
}
var info = model.GetSymbolInfo(leftNode, cancellationToken);
return info.CandidateSymbols.Any(IsGenericTypeOrMethod);
}
......
......@@ -138,23 +138,6 @@ public void Multiple_Nested()
public void TypeArgument_Invalid()
{
var code = @"class C
{
void Method()
{
List$$
}
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session, expectValidSession: false);
}
}
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgument_Invalid2()
{
var code = @"class C
{
void Method()
{
......@@ -170,7 +153,7 @@ void Method()
}
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgument2()
public void TypeArgument1()
{
var code = @"class C
{
......@@ -187,7 +170,7 @@ void Method()
}
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgument3()
public void TypeArgument2()
{
var code = @"class C
{
......@@ -294,6 +277,169 @@ void Test()
}
}
[WorkItem(1628, "https://github.com/dotnet/roslyn/issues/1628")]
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void NotInLessThanComparisonOperation()
{
var code = @"using System.Linq;
class C
{
void Test(int[] args)
{
var a = args[0]$$
}
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session, expectValidSession: false);
}
}
[WorkItem(1628, "https://github.com/dotnet/roslyn/issues/1628")]
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void NotInLessThanComparisonOperationAfterConditionalAccessExpression()
{
var code = @"using System.Linq;
class C
{
void Test(object[] args, object[] other)
{
var a = args?.First()$$
}
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session, expectValidSession: false);
}
}
[WorkItem(1628, "https://github.com/dotnet/roslyn/issues/1628")]
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgumentInConditionalAccessExpressionSimple()
{
var code = @"using System.Linq;
class C
{
void Test(object[] args)
{
args?.OfType$$
}
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session);
}
}
[WorkItem(1628, "https://github.com/dotnet/roslyn/issues/1628")]
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgumentInConditionalAccessExpressionNested()
{
var code = @"class C
{
void Test()
{
Outer<int> t = new Outer<int>();
t?.GetInner<int>()?.Method$$
}
}
class Outer<T>
{
public Inner<U> GetInner<U>()
{
return new Inner<U>();
}
}
class Inner<V>
{
public void Method<X>() { }
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session);
Type(session.Session, "int");
CheckOverType(session.Session);
}
}
[WorkItem(1628, "https://github.com/dotnet/roslyn/issues/1628")]
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgumentInConditionalAccessExpressionDeeplyNested()
{
var code = @"class C
{
void Test()
{
new Outer1<int>()?.GetInner<int>()?.GetInner().DoSomething$$
}
}
internal class Outer1<T>
{
public Outer2<U> GetInner<U>()
{
return new Outer2<U>();
}
}
internal class Outer2<U>
{
public Outer2() { }
public Inner GetInner()
{
return new Inner();
}
}
internal class Inner
{
public Inner() { }
public void DoSomething<V>() { }
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session);
}
}
[WorkItem(1628, "https://github.com/dotnet/roslyn/issues/1628")]
[Fact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void TypeArgumentInConditionalAccessExpressionWithLambdas()
{
var code = @"using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
void Foo(object[] args)
{
var a = new Outer();
a?.M(x => x?.ToString())?.Method$$
}
}
public class Outer
{
internal Inner M(Func<object, object> p)
{
throw new NotImplementedException();
}
}
public class Inner
{
public void Method<U>() { }
}";
using (var session = CreateSession(code))
{
Assert.NotNull(session);
CheckStart(session.Session);
}
}
internal Holder CreateSession(string code)
{
return CreateSession(
......
......@@ -1201,5 +1201,21 @@ public static ConditionalAccessExpressionSyntax GetParentConditionalAccessExpres
return null;
}
public static ConditionalAccessExpressionSyntax GetInnerMostConditionalAccessExpression(this SyntaxNode node)
{
if (!(node is ConditionalAccessExpressionSyntax))
{
return null;
}
var result = (ConditionalAccessExpressionSyntax)node;
while (result.WhenNotNull is ConditionalAccessExpressionSyntax)
{
result = (ConditionalAccessExpressionSyntax)result.WhenNotNull;
}
return result;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册