提交 1338adc8 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #15885 from CyrusNajmabadi/awaitCompletion2

Parse incomplete code differently to better reflect user intent.

Fixes #15881
......@@ -610,7 +610,6 @@ public static TypeInfo GetTypeInfo(this SemanticModel semanticModel, Constructor
}
}
public static TypeInfo GetTypeInfo(this SemanticModel semanticModel, SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken))
{
var csmodel = semanticModel as CSharpSemanticModel;
......@@ -1339,4 +1338,4 @@ public static IRangeVariableSymbol GetDeclaredSymbol(this SemanticModel semantic
}
#endregion
}
}
}
\ No newline at end of file
......@@ -7010,6 +7010,56 @@ private bool IsPossibleLocalDeclarationStatement(bool allowAnyExpression)
return typedIdentifier.Value;
}
// It's common to have code like the following:
//
// Task.
// await Task.Delay()
//
// In this case we don't want to parse this as as a local declaration like:
//
// Task.await Task
//
// This does not represent user intent, and it causes all sorts of problems to higher
// layers. This is because both the parse tree is strage, and the symbol tables have
// entries that throw things off (like a bogus 'Task' local).
//
// Note that we explicitly do this check when we see that the code spreads over multiple
// lines. We don't want this if the user has actually written "X.Y z"
if (tk == SyntaxKind.IdentifierToken)
{
var token1 = PeekToken(1);
if (token1.Kind == SyntaxKind.DotToken &&
token1.TrailingTrivia.Any((int)SyntaxKind.EndOfLineTrivia))
{
if (PeekToken(2).Kind == SyntaxKind.IdentifierToken &&
PeekToken(3).Kind == SyntaxKind.IdentifierToken)
{
// We have something like:
//
// X.
// Y z
//
// This is only a local declaration if we have:
//
// X.Y z;
// X.Y z = ...
// X.Y z, ...
// X.Y z( ... (local function)
// X.Y z<W... (local function)
//
var token4Kind = PeekToken(4).Kind;
if (token4Kind != SyntaxKind.SemicolonToken &&
token4Kind != SyntaxKind.EqualsToken &&
token4Kind != SyntaxKind.CommaToken &&
token4Kind != SyntaxKind.OpenParenToken &&
token4Kind != SyntaxKind.LessThanToken)
{
return false;
}
}
}
}
var resetPoint = this.GetResetPoint();
try
{
......@@ -9631,6 +9681,26 @@ private ExpressionSyntax ParsePostFixExpression(ExpressionSyntax expr)
expr = _syntaxFactory.MemberAccessExpression(SyntaxKind.PointerMemberAccessExpression, expr, this.EatToken(), this.ParseSimpleName(NameOptions.InExpression));
break;
case SyntaxKind.DotToken:
// if we have the error situation:
//
// expr.
// X Y
//
// Then we don't want to parse this out as "Expr.X"
//
// It's far more likely the member access expression is simply incomplete and
// there is a new declaration on the next line.
if (this.CurrentToken.TrailingTrivia.Any((int)SyntaxKind.EndOfLineTrivia) &&
this.PeekToken(1).Kind == SyntaxKind.IdentifierToken &&
this.PeekToken(2).Kind == SyntaxKind.IdentifierToken)
{
expr = _syntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, expr, this.EatToken(),
this.AddError(this.CreateMissingIdentifierName(), ErrorCode.ERR_IdentifierExpected));
return expr;
}
expr = _syntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expr, this.EatToken(), this.ParseSimpleName(NameOptions.InExpression));
break;
......
......@@ -2730,6 +2730,7 @@ class C
End Function
End Class
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function Filters_EmptyList1() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
......@@ -2762,6 +2763,7 @@ class C
End Using
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function Filters_EmptyList2() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
......@@ -2796,6 +2798,7 @@ class C
End Using
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function Filters_EmptyList3() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
......@@ -2830,6 +2833,7 @@ class C
End Using
End Function
' <WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function Filters_EmptyList4() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
......@@ -2860,9 +2864,29 @@ class C
Assert.Null(state.CurrentCompletionPresenterSession.SelectedItem)
state.SendTypeChars(".")
Await state.AssertNoCompletionSession()
End Using
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
<WorkItem(15881, "https://github.com/dotnet/roslyn/issues/15881")>
Public Async Function CompletionAfterDotBeforeAwaitTask() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
using System.Threading.Tasks;
class C
{
async Task Moo()
{
Task.$$
await Task.Delay(50);
}
}
]]></Document>)
state.SendInvokeCompletionList()
Await state.AssertCompletionSession()
End Using
End Function
End Class
End Namespace
......@@ -305,9 +305,16 @@ private static ImmutableArray<ISymbol> GetSymbolsForNamespaceDeclarationNameCont
if (name.IsFoundUnder<LocalDeclarationStatementSyntax>(d => d.Declaration.Type) ||
name.IsFoundUnder<FieldDeclarationSyntax>(d => d.Declaration.Type))
{
var speculativeBinding = context.SemanticModel.GetSpeculativeSymbolInfo(name.SpanStart, name, SpeculativeBindingOption.BindAsExpression);
var container = context.SemanticModel.GetSpeculativeTypeInfo(name.SpanStart, name, SpeculativeBindingOption.BindAsExpression).Type;
return GetSymbolsOffOfBoundExpression(context, name, name, speculativeBinding, container, cancellationToken);
var speculativeBinding = context.SemanticModel.GetSpeculativeSymbolInfo(
name.SpanStart, name, SpeculativeBindingOption.BindAsExpression);
var container = context.SemanticModel.GetSpeculativeTypeInfo(
name.SpanStart, name, SpeculativeBindingOption.BindAsExpression).Type;
var speculativeResult = GetSymbolsOffOfBoundExpression(
context, name, name, speculativeBinding, container, cancellationToken);
return speculativeResult;
}
// We're in a name-only context, since if we were an expression we'd be a
......@@ -436,7 +443,7 @@ private static ImmutableArray<ISymbol> GetSymbolsForNamespaceDeclarationNameCont
var useBaseReferenceAccessibility = false;
var excludeInstance = false;
var excludeStatic = false;
var symbol = leftHandBinding.GetBestOrAllSymbols().FirstOrDefault();
var symbol = leftHandBinding.GetAnySymbol();
if (symbol != null)
{
......@@ -540,4 +547,4 @@ private static ImmutableArray<ISymbol> GetSymbolsForNamespaceDeclarationNameCont
: symbols;
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册