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

Reparse type after async (#32983)

上级 530518c2
......@@ -2276,6 +2276,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
// indexers, and non-conversion operators -- starts with a type
// (possibly void). Parse that.
TypeSyntax type = ParseReturnType();
var afterTypeResetPoint = this.GetResetPoint();
try
{
var sawRef = type.Kind == SyntaxKind.RefType;
// Check for misplaced modifiers. if we see any, then consider this member
......@@ -2371,8 +2376,13 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
identifierOrThisOpt != null &&
(typeParameterListOpt != null && typeParameterListOpt.ContainsDiagnostics
|| this.CurrentToken.Kind != SyntaxKind.OpenParenToken && this.CurrentToken.Kind != SyntaxKind.OpenBraceToken && this.CurrentToken.Kind != SyntaxKind.EqualsGreaterThanToken) &&
ReconsiderTypeAsAsyncModifier(ref modifiers, ref type, ref explicitInterfaceOpt, identifierOrThisOpt, typeParameterListOpt))
ReconsiderTypeAsAsyncModifier(ref modifiers, type, identifierOrThisOpt))
{
this.Reset(ref afterTypeResetPoint);
explicitInterfaceOpt = null;
identifierOrThisOpt = default;
typeParameterListOpt = null;
type = ParseReturnType();
goto parse_member_name;
}
......@@ -2397,6 +2407,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
}
}
finally
{
this.Release(ref afterTypeResetPoint);
}
}
finally
{
_pool.Free(modifiers);
_pool.Free(attributes);
......@@ -2409,10 +2424,8 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
// type parameter list
private bool ReconsiderTypeAsAsyncModifier(
ref SyntaxListBuilder modifiers,
ref TypeSyntax type,
ref ExplicitInterfaceSpecifierSyntax explicitInterfaceOpt,
SyntaxToken identifierOrThisOpt,
TypeParameterListSyntax typeParameterListOpt)
TypeSyntax type,
SyntaxToken identifierOrThisOpt)
{
if (type.Kind != SyntaxKind.IdentifierName) return false;
if (identifierOrThisOpt.Kind != SyntaxKind.IdentifierToken) return false;
......@@ -2426,61 +2439,9 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
}
modifiers.Add(ConvertToKeyword(identifier));
SimpleNameSyntax newType = typeParameterListOpt == null
? (SimpleNameSyntax)_syntaxFactory.IdentifierName(identifierOrThisOpt)
: _syntaxFactory.GenericName(identifierOrThisOpt, TypeArgumentFromTypeParameters(typeParameterListOpt));
type = (explicitInterfaceOpt == null)
? (TypeSyntax)newType
: _syntaxFactory.QualifiedName(explicitInterfaceOpt.Name, explicitInterfaceOpt.DotToken, newType);
explicitInterfaceOpt = null;
identifierOrThisOpt = default(SyntaxToken);
typeParameterListOpt = default(TypeParameterListSyntax);
return true;
}
private TypeArgumentListSyntax TypeArgumentFromTypeParameters(TypeParameterListSyntax typeParameterList)
{
var types = _pool.AllocateSeparated<TypeSyntax>();
foreach (var p in typeParameterList.Parameters.GetWithSeparators())
{
switch ((SyntaxKind)p.RawKind)
{
case SyntaxKind.TypeParameter:
var typeParameter = (TypeParameterSyntax)p;
var typeArgument = _syntaxFactory.IdentifierName(typeParameter.Identifier);
// NOTE: reverse order of variance keyword and attributes list so they come out in the right order.
if (typeParameter.VarianceKeyword != null)
{
// This only happens in error scenarios, so don't bother to produce a diagnostic about
// having a variance keyword on a type argument.
typeArgument = AddLeadingSkippedSyntax(typeArgument, typeParameter.VarianceKeyword);
}
if (typeParameter.AttributeLists.Node != null)
{
// This only happens in error scenarios, so don't bother to produce a diagnostic about
// having an attribute on a type argument.
typeArgument = AddLeadingSkippedSyntax(typeArgument, typeParameter.AttributeLists.Node);
}
types.Add(typeArgument);
break;
case SyntaxKind.CommaToken:
types.AddSeparator((SyntaxToken)p);
break;
default:
throw ExceptionUtilities.UnexpectedValue(p.RawKind);
}
}
var result = _syntaxFactory.TypeArgumentList(typeParameterList.LessThanToken, types.ToList(), typeParameterList.GreaterThanToken);
_pool.Free(types);
return result;
}
//private bool ReconsiderTypeAsAsyncModifier(ref SyntaxListBuilder modifiers, ref type, ref identifierOrThisOpt, ref typeParameterListOpt))
// {
// goto parse_member_name;
// }
private bool IsFieldDeclaration(bool isEvent)
{
if (this.CurrentToken.Kind != SyntaxKind.IdentifierToken)
......@@ -6569,10 +6530,16 @@ private StatementSyntax ParseStatementCore()
private StatementSyntax ParsePossibleDeclarationOrBadAwaitStatement()
{
ResetPoint resetPointBeforeStatement = this.GetResetPoint();
try
{
StatementSyntax result = ParsePossibleDeclarationOrBadAwaitStatement(ref resetPointBeforeStatement);
this.Release(ref resetPointBeforeStatement);
return result;
}
finally
{
this.Release(ref resetPointBeforeStatement);
}
}
private StatementSyntax ParsePossibleDeclarationOrBadAwaitStatement(ref ResetPoint resetPointBeforeStatement)
{
......
......@@ -458,5 +458,287 @@ public void TrashAfterDeclaration()
}
EOF();
}
[Fact]
[WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")]
public void GenericAsyncTask_01()
{
foreach (var options in new[] { TestOptions.Script, TestOptions.Regular })
{
UsingDeclaration("async Task<SomeNamespace.SomeType Method();", options: options,
// (1,1): error CS1073: Unexpected token '('
// async Task<SomeNamespace.SomeType Method();
Diagnostic(ErrorCode.ERR_UnexpectedToken, "async Task<SomeNamespace.SomeType Method").WithArguments("(").WithLocation(1, 1),
// (1,35): error CS1003: Syntax error, ',' expected
// async Task<SomeNamespace.SomeType Method();
Diagnostic(ErrorCode.ERR_SyntaxError, "Method").WithArguments(",", "").WithLocation(1, 35),
// (1,41): error CS1003: Syntax error, '>' expected
// async Task<SomeNamespace.SomeType Method();
Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">", "(").WithLocation(1, 41)
);
N(SyntaxKind.IncompleteMember);
{
N(SyntaxKind.AsyncKeyword);
N(SyntaxKind.GenericName);
{
N(SyntaxKind.IdentifierToken, "Task");
N(SyntaxKind.TypeArgumentList);
{
N(SyntaxKind.LessThanToken);
N(SyntaxKind.QualifiedName);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeNamespace");
}
N(SyntaxKind.DotToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeType");
}
}
M(SyntaxKind.CommaToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "Method");
}
M(SyntaxKind.GreaterThanToken);
}
}
}
EOF();
}
}
[Fact]
[WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")]
public void GenericPublicTask_01()
{
foreach (var options in new[] { TestOptions.Script, TestOptions.Regular })
{
UsingDeclaration("public Task<SomeNamespace.SomeType Method();", options: options,
// (1,1): error CS1073: Unexpected token '('
// public Task<SomeNamespace.SomeType Method();
Diagnostic(ErrorCode.ERR_UnexpectedToken, "public Task<SomeNamespace.SomeType Method").WithArguments("(").WithLocation(1, 1),
// (1,36): error CS1003: Syntax error, ',' expected
// public Task<SomeNamespace.SomeType Method();
Diagnostic(ErrorCode.ERR_SyntaxError, "Method").WithArguments(",", "").WithLocation(1, 36),
// (1,42): error CS1003: Syntax error, '>' expected
// public Task<SomeNamespace.SomeType Method();
Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">", "(").WithLocation(1, 42)
);
N(SyntaxKind.IncompleteMember);
{
N(SyntaxKind.PublicKeyword);
N(SyntaxKind.GenericName);
{
N(SyntaxKind.IdentifierToken, "Task");
N(SyntaxKind.TypeArgumentList);
{
N(SyntaxKind.LessThanToken);
N(SyntaxKind.QualifiedName);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeNamespace");
}
N(SyntaxKind.DotToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeType");
}
}
M(SyntaxKind.CommaToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "Method");
}
M(SyntaxKind.GreaterThanToken);
}
}
}
EOF();
}
}
[Fact]
[WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")]
public void GenericAsyncTask_02()
{
foreach (var options in new[] { TestOptions.Script, TestOptions.Regular })
{
UsingDeclaration("async Task<SomeNamespace. Method();", options: options,
// (1,1): error CS1073: Unexpected token '('
// async Task<SomeNamespace. Method();
Diagnostic(ErrorCode.ERR_UnexpectedToken, "async Task<SomeNamespace. Method").WithArguments("(").WithLocation(1, 1),
// (1,33): error CS1003: Syntax error, '>' expected
// async Task<SomeNamespace. Method();
Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">", "(").WithLocation(1, 33)
);
N(SyntaxKind.IncompleteMember);
{
N(SyntaxKind.AsyncKeyword);
N(SyntaxKind.GenericName);
{
N(SyntaxKind.IdentifierToken, "Task");
N(SyntaxKind.TypeArgumentList);
{
N(SyntaxKind.LessThanToken);
N(SyntaxKind.QualifiedName);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeNamespace");
N(SyntaxKind.DotToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "Method");
}
M(SyntaxKind.GreaterThanToken);
}
}
}
}
}
EOF();
}
}
[Fact]
[WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")]
public void GenericPublicTask_02()
{
foreach (var options in new[] { TestOptions.Script, TestOptions.Regular })
{
UsingDeclaration("public Task<SomeNamespace. Method();", options: options,
// (1,1): error CS1073: Unexpected token '('
// public Task<SomeNamespace. Method();
Diagnostic(ErrorCode.ERR_UnexpectedToken, "public Task<SomeNamespace. Method").WithArguments("(").WithLocation(1, 1),
// (1,34): error CS1003: Syntax error, '>' expected
// public Task<SomeNamespace. Method();
Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">", "(").WithLocation(1, 34)
);
N(SyntaxKind.IncompleteMember);
{
N(SyntaxKind.PublicKeyword);
N(SyntaxKind.GenericName);
{
N(SyntaxKind.IdentifierToken, "Task");
N(SyntaxKind.TypeArgumentList);
{
N(SyntaxKind.LessThanToken);
N(SyntaxKind.QualifiedName);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeNamespace");
}
N(SyntaxKind.DotToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "Method");
}
}
M(SyntaxKind.GreaterThanToken);
}
}
}
EOF();
}
}
[Fact]
[WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")]
public void GenericAsyncTask_03()
{
foreach (var options in new[] { TestOptions.Script, TestOptions.Regular })
{
UsingDeclaration("async Task<SomeNamespace.> Method();", options: options,
// (1,26): error CS1001: Identifier expected
// async Task<SomeNamespace.> Method();
Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(1, 26)
);
N(SyntaxKind.MethodDeclaration);
{
N(SyntaxKind.AsyncKeyword);
N(SyntaxKind.GenericName);
{
N(SyntaxKind.IdentifierToken, "Task");
N(SyntaxKind.TypeArgumentList);
{
N(SyntaxKind.LessThanToken);
N(SyntaxKind.QualifiedName);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeNamespace");
}
N(SyntaxKind.DotToken);
M(SyntaxKind.IdentifierName);
{
M(SyntaxKind.IdentifierToken);
}
}
N(SyntaxKind.GreaterThanToken);
}
}
N(SyntaxKind.IdentifierToken, "Method");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.SemicolonToken);
}
EOF();
}
}
[Fact]
[WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")]
public void GenericPublicTask_03()
{
foreach (var options in new[] { TestOptions.Script, TestOptions.Regular })
{
UsingDeclaration("public Task<SomeNamespace.> Method();", options: options,
// (1,27): error CS1001: Identifier expected
// public Task<SomeNamespace.> Method();
Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(1, 27)
);
N(SyntaxKind.MethodDeclaration);
{
N(SyntaxKind.PublicKeyword);
N(SyntaxKind.GenericName);
{
N(SyntaxKind.IdentifierToken, "Task");
N(SyntaxKind.TypeArgumentList);
{
N(SyntaxKind.LessThanToken);
N(SyntaxKind.QualifiedName);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "SomeNamespace");
}
N(SyntaxKind.DotToken);
M(SyntaxKind.IdentifierName);
{
M(SyntaxKind.IdentifierToken);
}
}
N(SyntaxKind.GreaterThanToken);
}
}
N(SyntaxKind.IdentifierToken, "Method");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.SemicolonToken);
}
EOF();
}
}
}
}
......@@ -4135,6 +4135,32 @@ class C
End Using
End Function
<WorkItem(11959, "https://github.com/dotnet/roslyn/issues/11959")>
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestGenericAsyncTaskDeclaration(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(completionImplementation,
<Document>
namespace A.B
{
class TestClass { }
}
namespace A
{
class C
{
async Task&lt;A$$ Method()
{ }
}
}
</Document>)
state.SendTypeChars(".")
Await state.AssertSelectedCompletionItem(displayText:="B", isSoftSelected:=True)
End Using
End Function
Private Class MultipleChangeCompletionProvider
Inherits CompletionProvider
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册