Skip to content

Commit dd335bb

Browse files
committed
Classify langword in VB code
1 parent 845a3c2 commit dd335bb

File tree

3 files changed

+230
-3
lines changed

3 files changed

+230
-3
lines changed

src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2670,6 +2670,162 @@ End Class"
26702670
Keyword("Class"))
26712671
End Function
26722672

2673+
<Theory, CombinatorialData>
2674+
Public Async Function TestXmlDocComment_LangWordAttribute_Keyword(testHost As TestHost) As Task
2675+
Dim code =
2676+
"''' <summary>
2677+
''' <see langword=""True"" />
2678+
''' </summary>
2679+
Class MyClass
2680+
End Class"
2681+
2682+
Await TestAsync(code,
2683+
testHost,
2684+
XmlDoc.Delimiter("'''"),
2685+
XmlDoc.Text(" "),
2686+
XmlDoc.Delimiter("<"),
2687+
XmlDoc.Name("summary"),
2688+
XmlDoc.Delimiter(">"),
2689+
XmlDoc.Delimiter("'''"),
2690+
XmlDoc.Text(" "),
2691+
XmlDoc.Delimiter("<"),
2692+
XmlDoc.Name("see"),
2693+
XmlDoc.Name(" "),
2694+
XmlDoc.AttributeName("langword"),
2695+
XmlDoc.Delimiter("="),
2696+
XmlDoc.AttributeQuotes(""""),
2697+
Keyword("True"),
2698+
XmlDoc.AttributeQuotes(""""),
2699+
XmlDoc.AttributeQuotes(" "),
2700+
XmlDoc.Delimiter("/>"),
2701+
XmlDoc.Delimiter("'''"),
2702+
XmlDoc.Text(" "),
2703+
XmlDoc.Delimiter("</"),
2704+
XmlDoc.Name("summary"),
2705+
XmlDoc.Delimiter(">"),
2706+
Keyword("Class"),
2707+
[Class]("MyClass"),
2708+
Keyword("End"),
2709+
Keyword("Class"))
2710+
End Function
2711+
2712+
<Theory, CombinatorialData>
2713+
Public Async Function TestXmlDocComment_LangWordAttribute_ControlKeyword(testHost As TestHost) As Task
2714+
Dim code =
2715+
"''' <summary>
2716+
''' <see langword=""Return"" />
2717+
''' </summary>
2718+
Class MyClass
2719+
End Class"
2720+
2721+
Await TestAsync(code,
2722+
testHost,
2723+
XmlDoc.Delimiter("'''"),
2724+
XmlDoc.Text(" "),
2725+
XmlDoc.Delimiter("<"),
2726+
XmlDoc.Name("summary"),
2727+
XmlDoc.Delimiter(">"),
2728+
XmlDoc.Delimiter("'''"),
2729+
XmlDoc.Text(" "),
2730+
XmlDoc.Delimiter("<"),
2731+
XmlDoc.Name("see"),
2732+
XmlDoc.Name(" "),
2733+
XmlDoc.AttributeName("langword"),
2734+
XmlDoc.Delimiter("="),
2735+
XmlDoc.AttributeQuotes(""""),
2736+
ControlKeyword("Return"),
2737+
XmlDoc.AttributeQuotes(""""),
2738+
XmlDoc.AttributeQuotes(" "),
2739+
XmlDoc.Delimiter("/>"),
2740+
XmlDoc.Delimiter("'''"),
2741+
XmlDoc.Text(" "),
2742+
XmlDoc.Delimiter("</"),
2743+
XmlDoc.Name("summary"),
2744+
XmlDoc.Delimiter(">"),
2745+
Keyword("Class"),
2746+
[Class]("MyClass"),
2747+
Keyword("End"),
2748+
Keyword("Class"))
2749+
End Function
2750+
2751+
<Theory, CombinatorialData>
2752+
Public Async Function TestXmlDocComment_LangWordAttribute_ContextualKeyword(testHost As TestHost) As Task
2753+
Dim code =
2754+
"''' <summary>
2755+
''' <see langword=""All"" />
2756+
''' </summary>
2757+
Class MyClass
2758+
End Class"
2759+
2760+
Await TestAsync(code,
2761+
testHost,
2762+
XmlDoc.Delimiter("'''"),
2763+
XmlDoc.Text(" "),
2764+
XmlDoc.Delimiter("<"),
2765+
XmlDoc.Name("summary"),
2766+
XmlDoc.Delimiter(">"),
2767+
XmlDoc.Delimiter("'''"),
2768+
XmlDoc.Text(" "),
2769+
XmlDoc.Delimiter("<"),
2770+
XmlDoc.Name("see"),
2771+
XmlDoc.Name(" "),
2772+
XmlDoc.AttributeName("langword"),
2773+
XmlDoc.Delimiter("="),
2774+
XmlDoc.AttributeQuotes(""""),
2775+
Keyword("All"),
2776+
XmlDoc.AttributeQuotes(""""),
2777+
XmlDoc.AttributeQuotes(" "),
2778+
XmlDoc.Delimiter("/>"),
2779+
XmlDoc.Delimiter("'''"),
2780+
XmlDoc.Text(" "),
2781+
XmlDoc.Delimiter("</"),
2782+
XmlDoc.Name("summary"),
2783+
XmlDoc.Delimiter(">"),
2784+
Keyword("Class"),
2785+
[Class]("MyClass"),
2786+
Keyword("End"),
2787+
Keyword("Class"))
2788+
End Function
2789+
2790+
<Theory, CombinatorialData>
2791+
Public Async Function TestXmlDocComment_LangWordAttribute_NonKeyword(testHost As TestHost) As Task
2792+
Dim code =
2793+
"''' <summary>
2794+
''' <see langword=""MyWord"" />
2795+
''' </summary>
2796+
Class MyClass
2797+
End Class"
2798+
2799+
Await TestAsync(code,
2800+
testHost,
2801+
XmlDoc.Delimiter("'''"),
2802+
XmlDoc.Text(" "),
2803+
XmlDoc.Delimiter("<"),
2804+
XmlDoc.Name("summary"),
2805+
XmlDoc.Delimiter(">"),
2806+
XmlDoc.Delimiter("'''"),
2807+
XmlDoc.Text(" "),
2808+
XmlDoc.Delimiter("<"),
2809+
XmlDoc.Name("see"),
2810+
XmlDoc.Name(" "),
2811+
XmlDoc.AttributeName("langword"),
2812+
XmlDoc.Delimiter("="),
2813+
XmlDoc.AttributeQuotes(""""),
2814+
XmlDoc.AttributeValue("MyWord"),
2815+
XmlDoc.AttributeQuotes(""""),
2816+
XmlDoc.AttributeQuotes(" "),
2817+
XmlDoc.Delimiter("/>"),
2818+
XmlDoc.Delimiter("'''"),
2819+
XmlDoc.Text(" "),
2820+
XmlDoc.Delimiter("</"),
2821+
XmlDoc.Name("summary"),
2822+
XmlDoc.Delimiter(">"),
2823+
Keyword("Class"),
2824+
[Class]("MyClass"),
2825+
Keyword("End"),
2826+
Keyword("Class"))
2827+
End Function
2828+
26732829
<Theory, CombinatorialData>
26742830
Public Async Function TestXmlDocComment_EmptyElementAttributesWithExteriorTrivia(testHost As TestHost) As Task
26752831
Dim code =

src/Workspaces/VisualBasic/Portable/Classification/ClassificationHelpers.vb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification
7878
''' <summary>
7979
''' Determine if the kind represents a control keyword
8080
''' </summary>
81-
Private Function IsControlKeywordKind(kind As SyntaxKind) As Boolean
81+
Public Function IsControlKeywordKind(kind As SyntaxKind) As Boolean
8282
Select Case kind
8383
Case _
8484
SyntaxKind.CaseKeyword,
@@ -119,7 +119,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification
119119
''' <summary>
120120
''' Determine if the kind represents a control statement
121121
''' </summary>
122-
Private Function IsControlStatementKind(kind As SyntaxKind) As Boolean
122+
Public Function IsControlStatementKind(kind As SyntaxKind) As Boolean
123123
Select Case kind
124124
Case _
125125
SyntaxKind.CallStatement,

src/Workspaces/VisualBasic/Portable/Classification/Worker.DocumentationCommentClassifier.vb

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification
210210
If attribute IsNot Nothing Then
211211
Select Case attribute.Kind
212212
Case SyntaxKind.XmlAttribute
213-
ClassifyAttribute(DirectCast(attribute, XmlAttributeSyntax))
213+
Dim xmlAttribute = DirectCast(attribute, XmlAttributeSyntax)
214+
If IsLangWordAttribute(xmlAttribute) Then
215+
ClassifyLangWordAttribute(xmlAttribute)
216+
217+
Else
218+
ClassifyAttribute(xmlAttribute)
219+
End If
214220

215221
Case SyntaxKind.XmlCrefAttribute
216222
ClassifyCrefAttribute(DirectCast(attribute, XmlCrefAttributeSyntax))
@@ -227,6 +233,71 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification
227233
ClassifyXmlNode(attribute.Value)
228234
End Sub
229235

236+
Private Shared Function IsLangWordAttribute(attribute As XmlAttributeSyntax) As Boolean
237+
Dim nameNode = DirectCast(attribute.Name, XmlNameSyntax)
238+
If nameNode.LocalName.Text <> DocumentationCommentXmlNames.LangwordAttributeName Then
239+
Return False
240+
End If
241+
242+
Dim startTag = TryCast(attribute.Parent, XmlElementStartTagSyntax)
243+
If (startTag IsNot Nothing) Then
244+
Dim startTagName = TryCast(startTag.Name, XmlNameSyntax)
245+
Return startTagName IsNot Nothing AndAlso
246+
startTagName.Prefix Is Nothing AndAlso
247+
startTagName.LocalName.Text = DocumentationCommentXmlNames.SeeElementName
248+
End If
249+
250+
Dim emptyElement = TryCast(attribute.Parent, XmlEmptyElementSyntax)
251+
If (emptyElement IsNot Nothing) Then
252+
Dim emptyElementName = TryCast(emptyElement.Name, XmlNameSyntax)
253+
Return emptyElementName IsNot Nothing AndAlso
254+
emptyElementName.Prefix Is Nothing AndAlso
255+
emptyElementName.LocalName.Text = DocumentationCommentXmlNames.SeeElementName
256+
End If
257+
258+
Return False
259+
End Function
260+
261+
Private Sub ClassifyLangWordAttribute(attribute As XmlAttributeSyntax)
262+
ClassifyXmlNode(attribute.Name)
263+
AddXmlClassification(attribute.EqualsToken, ClassificationTypeNames.XmlDocCommentDelimiter)
264+
265+
Dim node = (DirectCast(attribute.Value, XmlStringSyntax))
266+
267+
AddXmlClassification(node.StartQuoteToken, ClassificationTypeNames.XmlDocCommentAttributeQuotes)
268+
ClassifyLangWordTextTokenList(node.TextTokens)
269+
AddXmlClassification(node.EndQuoteToken, ClassificationTypeNames.XmlDocCommentAttributeQuotes)
270+
End Sub
271+
272+
Private Sub ClassifyLangWordTextTokenList(list As SyntaxTokenList)
273+
For Each token In list
274+
If (token.HasLeadingTrivia) Then
275+
ClassifyXmlTrivia(token.LeadingTrivia, ClassificationTypeNames.XmlDocCommentText)
276+
End If
277+
278+
ClassifyLangWordTextToken(token)
279+
280+
If (token.HasTrailingTrivia) Then
281+
ClassifyXmlTrivia(token.TrailingTrivia, ClassificationTypeNames.XmlDocCommentText)
282+
End If
283+
Next
284+
End Sub
285+
286+
Private Sub ClassifyLangWordTextToken(token As SyntaxToken)
287+
Dim kind = SyntaxFacts.GetKeywordKind(token.Text)
288+
If kind = SyntaxKind.None Then
289+
kind = SyntaxFacts.GetContextualKeywordKind(token.Text)
290+
End If
291+
292+
If kind = SyntaxKind.None Then
293+
AddXmlClassification(token, ClassificationTypeNames.XmlDocCommentAttributeValue)
294+
Return
295+
End If
296+
297+
Dim isControlKeyword = IsControlKeywordKind(kind) Or IsControlStatementKind(kind)
298+
AddXmlClassification(token, If(isControlKeyword, ClassificationTypeNames.ControlKeyword, ClassificationTypeNames.Keyword))
299+
End Sub
300+
230301
Private Sub ClassifyCrefAttribute(attribute As XmlCrefAttributeSyntax)
231302
ClassifyXmlNode(attribute.Name)
232303
AddXmlClassification(attribute.EqualsToken, ClassificationTypeNames.XmlDocCommentDelimiter)

0 commit comments

Comments
 (0)