提交 c6c0ed66 编写于 作者: C CyrusNajmabadi

Merge pull request #5573 from CyrusNajmabadi/awaitClassification

Optimistically classify the 'await' keyword

Fixes #2301
...@@ -3605,5 +3605,48 @@ public void LoadDirective() ...@@ -3605,5 +3605,48 @@ public void LoadDirective()
PPKeyword("load"), PPKeyword("load"),
String("\"file.csx\"")); String("\"file.csx\""));
} }
[Fact, Trait(Traits.Feature, Traits.Features.Classification)]
public void IncompleteAwaitInNonAsyncContext()
{
var code = @"
void M()
{
var x = await
}";
TestInClass(code,
Keyword("void"),
Identifier("M"),
Punctuation.OpenParen,
Punctuation.CloseParen,
Punctuation.OpenCurly,
Keyword("var"),
Identifier("x"),
Operators.Equals,
Keyword("await"),
Punctuation.CloseCurly);
}
[Fact, Trait(Traits.Feature, Traits.Features.Classification)]
public void CompleteAwaitInNonAsyncContext()
{
var code = @"
void M()
{
var x = await;
}";
TestInClass(code,
Keyword("void"),
Identifier("M"),
Punctuation.OpenParen,
Punctuation.CloseParen,
Punctuation.OpenCurly,
Keyword("var"),
Identifier("x"),
Operators.Equals,
Identifier("await"),
Punctuation.Semicolon,
Punctuation.CloseCurly);
}
} }
} }
...@@ -518,5 +518,31 @@ End Class ...@@ -518,5 +518,31 @@ End Class
Keyword("My")) Keyword("My"))
End Sub End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Classification)>
Public Sub TestAwaitInNonAsyncFunction1()
Dim text =
<code>
dim m = Await
</code>.NormalizedValue()
TestInMethod(text,
Keyword("Await"))
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Classification)>
Public Sub TestAwaitInNonAsyncFunction2()
Dim text =
<code>
sub await()
end sub
sub test()
dim m = Await
end sub
</code>.NormalizedValue()
TestInClass(text)
End Sub
End Class End Class
End Namespace End Namespace
...@@ -14,6 +14,7 @@ internal static class ClassificationHelpers ...@@ -14,6 +14,7 @@ internal static class ClassificationHelpers
private const string FromKeyword = "from"; private const string FromKeyword = "from";
private const string ValueKeyword = "value"; private const string ValueKeyword = "value";
private const string VarKeyword = "var"; private const string VarKeyword = "var";
private const string AwaitKeyword = "await";
/// <summary> /// <summary>
/// Determine the classification type for a given token. /// Determine the classification type for a given token.
...@@ -114,7 +115,7 @@ private static string GetClassificationForIdentifier(SyntaxToken token) ...@@ -114,7 +115,7 @@ private static string GetClassificationForIdentifier(SyntaxToken token)
{ {
return ClassificationTypeNames.TypeParameterName; return ClassificationTypeNames.TypeParameterName;
} }
else if (IsActualContextualKeyword(token) || CouldBeVarKeywordInDeclaration(token)) else if (IsActualContextualKeyword(token))
{ {
return ClassificationTypeNames.Keyword; return ClassificationTypeNames.Keyword;
} }
...@@ -259,11 +260,20 @@ private static bool IsActualContextualKeyword(SyntaxToken token) ...@@ -259,11 +260,20 @@ private static bool IsActualContextualKeyword(SyntaxToken token)
{ {
switch (token.ValueText) switch (token.ValueText)
{ {
case AwaitKeyword:
return token.GetNextToken(includeZeroWidth: true).IsMissing;
case FromKeyword: case FromKeyword:
var fromClause = token.Parent.FirstAncestorOrSelf<FromClauseSyntax>(); var fromClause = token.Parent.FirstAncestorOrSelf<FromClauseSyntax>();
return fromClause != null && fromClause.FromKeyword == token; return fromClause != null && fromClause.FromKeyword == token;
case VarKeyword: case VarKeyword:
// var
if (token.Parent is IdentifierNameSyntax && token.Parent?.Parent is ExpressionStatementSyntax)
{
return true;
}
// we allow var any time it looks like a variable declaration, and is not in a // we allow var any time it looks like a variable declaration, and is not in a
// field or event field. // field or event field.
return return
...@@ -277,18 +287,6 @@ private static bool IsActualContextualKeyword(SyntaxToken token) ...@@ -277,18 +287,6 @@ private static bool IsActualContextualKeyword(SyntaxToken token)
return false; return false;
} }
private static bool CouldBeVarKeywordInDeclaration(SyntaxToken token)
{
if (token.ValueText == VarKeyword && token.Parent != null && token.Parent.Parent != null)
{
// cases:
// var
return token.Parent is IdentifierNameSyntax && token.Parent.Parent is ExpressionStatementSyntax;
}
return false;
}
internal static void AddLexicalClassifications(SourceText text, TextSpan textSpan, List<ClassifiedSpan> result, CancellationToken cancellationToken) internal static void AddLexicalClassifications(SourceText text, TextSpan textSpan, List<ClassifiedSpan> result, CancellationToken cancellationToken)
{ {
var text2 = text.ToString(textSpan); var text2 = text.ToString(textSpan);
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
<Compile Include="CaseCorrection\VisualBasicCaseCorrectionServiceFactory.vb" /> <Compile Include="CaseCorrection\VisualBasicCaseCorrectionServiceFactory.vb" />
<Compile Include="Classification\ClassificationHelpers.vb" /> <Compile Include="Classification\ClassificationHelpers.vb" />
<Compile Include="Classification\Classifiers\AbstractSyntaxClassifier.vb" /> <Compile Include="Classification\Classifiers\AbstractSyntaxClassifier.vb" />
<Compile Include="Classification\Classifiers\IdentifierNameSyntaxClassifier.vb" />
<Compile Include="Classification\Classifiers\ImportAliasClauseSyntaxClassifier.vb" /> <Compile Include="Classification\Classifiers\ImportAliasClauseSyntaxClassifier.vb" />
<Compile Include="Classification\Classifiers\NameSyntaxClassifier.vb" /> <Compile Include="Classification\Classifiers\NameSyntaxClassifier.vb" />
<Compile Include="Classification\SyntaxClassifier.vb" /> <Compile Include="Classification\SyntaxClassifier.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Threading
Imports Microsoft.CodeAnalysis.Classification
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Namespace Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers
Friend Class IdentifierNameSyntaxClassifier
Inherits AbstractSyntaxClassifier
Private Const AwaitText = "Await"
Public Overrides ReadOnly Property SyntaxNodeTypes As IEnumerable(Of Type)
Get
Return {GetType(IdentifierNameSyntax)}
End Get
End Property
Public Overrides Function ClassifyNode(syntax As SyntaxNode, semanticModel As SemanticModel, cancellationToken As CancellationToken) As IEnumerable(Of ClassifiedSpan)
Dim identifierName = DirectCast(syntax, IdentifierNameSyntax)
Dim identifier = identifierName.Identifier
If CaseInsensitiveComparison.Equals(identifier.ValueText, AwaitText) Then
Dim symbolInfo = semanticModel.GetSymbolInfo(identifier)
If symbolInfo.GetAnySymbol() Is Nothing Then
Return SpecializedCollections.SingletonEnumerable(New ClassifiedSpan(ClassificationTypeNames.Keyword, identifier.Span))
End If
End If
Return MyBase.ClassifyNode(syntax, semanticModel, cancellationToken)
End Function
End Class
End Namespace
\ No newline at end of file
...@@ -9,7 +9,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification ...@@ -9,7 +9,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification
Public ReadOnly DefaultSyntaxClassifiers As IEnumerable(Of ISyntaxClassifier) = Public ReadOnly DefaultSyntaxClassifiers As IEnumerable(Of ISyntaxClassifier) =
ImmutableArray.Create(Of ISyntaxClassifier)( ImmutableArray.Create(Of ISyntaxClassifier)(
New NameSyntaxClassifier(), New NameSyntaxClassifier(),
New ImportAliasClauseSyntaxClassifier() New ImportAliasClauseSyntaxClassifier(),
) New IdentifierNameSyntaxClassifier())
End Module End Module
End Namespace End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册