-
Notifications
You must be signed in to change notification settings - Fork 4k
/
SyntaxFacts.vb
1190 lines (969 loc) · 55.9 KB
/
SyntaxFacts.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
' NOTE: The other partial class definition is generated by a tool.
' Because VB doesn't support Partial Module definitions the actual SyntaxFacts implementations are in this class
' but the SyntaxFacts extension methods are thin wrappers around this class exposed in separate Modules.
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Public Class SyntaxFacts
''' <summary>
''' Determine if the token instance represents a syntax trivia such as comment, whitespace, etc...
''' </summary>
Public Shared Function IsTrivia(this As SyntaxKind) As Boolean
Return IsSyntaxTrivia(this)
End Function
''' <summary>
''' Get all reserved and contextual keywords
''' </summary>
Public Shared Function GetKeywordKinds() As IEnumerable(Of SyntaxKind)
Return GetReservedKeywordKinds.Concat(GetContextualKeywordKinds)
End Function
''' <summary>
''' Helper to check whether the token is a predefined type
''' </summary>
''' <returns>True if it is a predefined type</returns>
Public Shared Function IsPredefinedType(kind As SyntaxKind) As Boolean
Return IsPredefinedTypeKeyword(kind)
End Function
''' <summary>
''' Helper to check whether the token is a predefined type OR Variant keyword
''' </summary>
''' <returns>True if it is a predefined type OR Variant keyword</returns>
Friend Shared Function IsPredefinedTypeOrVariant(kind As SyntaxKind) As Boolean
Return IsPredefinedTypeKeyword(kind) OrElse kind = SyntaxKind.VariantKeyword
End Function
''' <summary>
''' Returns true if the node is the object of an invocation expression
''' </summary>
Public Shared Function IsInvoked(node As ExpressionSyntax) As Boolean
node = SyntaxFactory.GetStandaloneExpression(node)
Dim inv = TryCast(node.Parent, InvocationExpressionSyntax)
Return inv IsNot Nothing AndAlso inv.Expression Is node
End Function
''' <summary>
''' Returns true if the node is the operand of an AddressOf expression
''' </summary>
Public Shared Function IsAddressOfOperand(node As ExpressionSyntax) As Boolean
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso parent.Kind = SyntaxKind.AddressOfExpression
End Function
''' <summary>
''' Returns true if the node is the operand of an AddressOf expression, or the object
''' of an invocation. This is used for special binding rules around the return value variable
''' inside Functions and Property Get accessors.
''' </summary>
Public Shared Function IsInvocationOrAddressOfOperand(node As ExpressionSyntax) As Boolean
Return IsInvoked(node) OrElse IsAddressOfOperand(node)
End Function
' Determines whether a particular node is in a context where it must bind to a type.
Public Shared Function IsInTypeOnlyContext(node As ExpressionSyntax) As Boolean
'Typeof does a null check and will result in returning false if nothing is passed rather than throwing an exception
If Not (TypeOf node Is TypeSyntax) Then
Return False ' Only nodes deriving from TypeSyntax could possible be in type context.
End If
Dim parent As VisualBasicSyntaxNode = node.Parent
If parent IsNot Nothing Then
Select Case parent.Kind
Case SyntaxKind.SimpleAsClause, SyntaxKind.AsNewClause
Return DirectCast(parent, AsClauseSyntax).Type Is node
Case SyntaxKind.GetTypeExpression
Return DirectCast(parent, GetTypeExpressionSyntax).Type Is node
Case SyntaxKind.TypeOfIsExpression, SyntaxKind.TypeOfIsNotExpression
Return DirectCast(parent, TypeOfExpressionSyntax).Type Is node
Case SyntaxKind.CTypeExpression, SyntaxKind.DirectCastExpression, SyntaxKind.TryCastExpression
Return DirectCast(parent, CastExpressionSyntax).Type Is node
Case SyntaxKind.TypeArgumentList
Return True ' all non-token children are types
Case SyntaxKind.InheritsStatement, SyntaxKind.ImplementsStatement
Return True ' all non-token children are types
Case SyntaxKind.TypeConstraint
Return True ' all non-token children are types
Case SyntaxKind.CrefSignaturePart
Return True ' all non-token children are types
Case SyntaxKind.Attribute
Return DirectCast(parent, AttributeSyntax).Name Is node
Case SyntaxKind.ObjectCreationExpression
Return DirectCast(parent, ObjectCreationExpressionSyntax).Type Is node
Case SyntaxKind.ArrayCreationExpression
Return DirectCast(parent, ArrayCreationExpressionSyntax).Type Is node
Case SyntaxKind.ArrayType
Return DirectCast(parent, ArrayTypeSyntax).ElementType Is node
Case SyntaxKind.NullableType
Return DirectCast(parent, NullableTypeSyntax).ElementType Is node
Case SyntaxKind.QualifiedName
Dim parentQualName = DirectCast(parent, QualifiedNameSyntax)
If parentQualName.Parent IsNot Nothing AndAlso parentQualName.Parent.Kind = SyntaxKind.ImplementsClause Then
Return parentQualName.Left Is node
Else
Return parentQualName.Right Is node
End If
Case SyntaxKind.TypedTupleElement
Return DirectCast(parent, TypedTupleElementSyntax).Type Is node
End Select
End If
Return False
End Function
' Is this node in a place where it bind to an implemented member.
Friend Shared Function IsImplementedMember(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso parent.IsKind(SyntaxKind.ImplementsClause)
End Function
' Is this node in a place where it bind to a handled event.
Friend Shared Function IsHandlesEvent(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso
parent.IsKind(SyntaxKind.HandlesClauseItem) AndAlso
TypeOf node Is IdentifierNameSyntax
End Function
' Is this node in a place where it bind to a handled event's container.
Friend Shared Function IsHandlesContainer(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Return TypeOf node Is WithEventsEventContainerSyntax
End Function
' Is this node in a place where it bind to a handled event's container.
Friend Shared Function IsHandlesProperty(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso
parent.IsKind(SyntaxKind.WithEventsPropertyEventContainer) AndAlso
TypeOf node Is IdentifierNameSyntax
End Function
' Is this node in a place where is must bind to either a namespace or a type.
Public Shared Function IsInNamespaceOrTypeContext(node As SyntaxNode) As Boolean
If node IsNot Nothing Then
If TypeOf node IsNot TypeSyntax Then
Return False ' Only nodes deriving from TypeSyntax could possible be in type or namespace context.
End If
Dim parent = node.Parent
If parent IsNot Nothing Then
Select Case parent.Kind()
Case SyntaxKind.SimpleImportsClause
Return DirectCast(parent, SimpleImportsClauseSyntax).Name Is node
Case SyntaxKind.NamespaceStatement
Return DirectCast(parent, NamespaceStatementSyntax).Name Is node
Case SyntaxKind.QualifiedName
Dim parentQualName = DirectCast(parent, QualifiedNameSyntax)
If Not (parentQualName.Parent IsNot Nothing AndAlso parentQualName.Parent.Kind = SyntaxKind.ImplementsClause) Then
Return DirectCast(parent, QualifiedNameSyntax).Left Is node
End If
End Select
End If
Dim expressionNode = TryCast(node, ExpressionSyntax)
If expressionNode IsNot Nothing Then
Return IsInTypeOnlyContext(expressionNode)
End If
End If
Return False
End Function
''' <summary>
''' Determines if position is before or within the span of a node, or in the trailing trivia of a node
''' up to, but not including, a newline or colon trivia (which mark the end of a statement.)
''' </summary>
Private Shared Function InOrBeforeSpanOrEffectiveTrailingOfNode(node As SyntaxNode, position As Integer) As Boolean
Return position < node.SpanStart OrElse InSpanOrEffectiveTrailingOfNode(node, position)
End Function
''' <summary>
''' Determines if position is within the span of a node, or in the trailing trivia of a node
''' up to, but not including, a newline or colon trivia (which mark the end of a statement.)
''' </summary>
Friend Shared Function InSpanOrEffectiveTrailingOfNode(node As SyntaxNode, position As Integer) As Boolean
Dim span = node.Span
If span.Contains(position) Then
Return True
ElseIf position >= span.End AndAlso position < node.FullSpan.End Then
' Position is in the trailing trivia of node. Check for newline or :.
Dim trailingTrivia As SyntaxTriviaList = node.GetTrailingTrivia()
For Each trivia In trailingTrivia
If trivia.Kind = SyntaxKind.EndOfLineTrivia OrElse trivia.Kind = SyntaxKind.ColonTrivia Then
Exit For
End If
If trivia.FullSpan.Contains(position) Then
Return True
End If
Next
' The effective trailing trivia didn't contain the position
Return False
End If
Return False
End Function
' Determines if possibleBlock is a block statement and position is in the interior.
' If so, then return true.
Friend Shared Function InBlockInterior(possibleBlock As SyntaxNode, position As Integer) As Boolean
Dim body As SyntaxList(Of StatementSyntax) = Nothing
Return InBlockInterior(possibleBlock, position, body)
End Function
''' <summary>
''' Determines if possibleLambda is a lambda expression and position is in the interior.
''' </summary>
Friend Shared Function InLambdaInterior(
possibleLambda As SyntaxNode,
position As Integer
) As Boolean
Dim afterBegin As Boolean
Dim beforeEnd As Boolean
Select Case possibleLambda.Kind()
Case SyntaxKind.SingleLineFunctionLambdaExpression,
SyntaxKind.SingleLineSubLambdaExpression
Dim singleLineLambda = DirectCast(possibleLambda, SingleLineLambdaExpressionSyntax)
Dim parameterList As ParameterListSyntax = singleLineLambda.SubOrFunctionHeader.ParameterList
If parameterList Is Nothing OrElse parameterList.CloseParenToken.IsMissing Then
afterBegin = (position >= singleLineLambda.SubOrFunctionHeader.Span.End)
Else
afterBegin = (position >= parameterList.CloseParenToken.SpanStart)
End If
beforeEnd = (position <= singleLineLambda.Body.Span.End)
Case SyntaxKind.MultiLineFunctionLambdaExpression,
SyntaxKind.MultiLineSubLambdaExpression
Dim multiLineLambda = DirectCast(possibleLambda, MultiLineLambdaExpressionSyntax)
Dim parameterList As ParameterListSyntax = multiLineLambda.SubOrFunctionHeader.ParameterList
If parameterList Is Nothing OrElse parameterList.CloseParenToken.IsMissing Then
afterBegin = (position >= multiLineLambda.SubOrFunctionHeader.Span.End)
Else
afterBegin = (position >= parameterList.CloseParenToken.SpanStart)
End If
beforeEnd = (position < multiLineLambda.EndSubOrFunctionStatement.SpanStart)
Case Else
Return False
End Select
Return afterBegin AndAlso beforeEnd
End Function
' Determines if possibleBlock is a block statement and position is in the interior.
' If so, then return true and the body.
Friend Shared Function InBlockInterior(possibleBlock As SyntaxNode,
position As Integer,
ByRef body As SyntaxList(Of StatementSyntax)) As Boolean
Dim beginStatement As StatementSyntax = Nothing
Dim endStatement As StatementSyntax = Nothing
Dim beginTerminator As SyntaxToken = Nothing
If IsBlockStatement(possibleBlock, beginStatement, beginTerminator, body, endStatement) Then
Dim afterBegin As Boolean = True
Dim beforeEnd As Boolean = True
If beginTerminator.Kind <> SyntaxKind.None AndAlso beginTerminator.Width > 0 Then
afterBegin = position >= beginTerminator.SpanStart
Else
afterBegin = Not InOrBeforeSpanOrEffectiveTrailingOfNode(beginStatement, position)
End If
If endStatement Is Nothing Then
Select Case possibleBlock.Kind
Case SyntaxKind.SingleLineIfStatement, SyntaxKind.SingleLineElseClause
' No expected end statement. These are "single" line blocks, check based on last statement in block instead.
If body.Count > 0 Then
Dim lastStatement = body(body.Count - 1)
beforeEnd = InOrBeforeSpanOrEffectiveTrailingOfNode(lastStatement, position)
End If
Case Else
' No expected end statement. These are multi-line blocks, check based on a token that follows the block instead.
Dim followingToken As SyntaxToken = possibleBlock.GetLastToken(includeZeroWidth:=True).GetNextToken()
If followingToken <> Nothing Then
' These blocks are always followed by a construct that terminates them. Let's treat it similar to the endStatement.
beforeEnd = position < followingToken.SpanStart
End If
End Select
ElseIf endStatement.Width > 0 Then
beforeEnd = InOrBeforeSpanOrEffectiveTrailingOfNode(endStatement, position)
End If
Return afterBegin AndAlso beforeEnd
End If
Return False
End Function
' Returns is possibleBlock is a block statement. If so, return the begin, body, and end statement. Note that
' many blocks (IfPart, TryPart, CaseBlock, etc. ) do not have immediate end statements. Also a few blocks don't
' have bodies that are SeparatedSyntaxList(Of StatementSyntax).
'
' Only for single-line If And Else, also return the token that ends that "begin" part (Then or Else tokens).
Friend Shared Function IsBlockStatement(possibleBlock As SyntaxNode,
ByRef beginStatement As StatementSyntax,
ByRef beginTerminator As SyntaxToken,
ByRef body As SyntaxList(Of StatementSyntax),
ByRef endStatement As StatementSyntax) As Boolean
beginTerminator = Nothing
Select Case possibleBlock.Kind()
Case SyntaxKind.NamespaceBlock
Dim nsBlock = DirectCast(possibleBlock, NamespaceBlockSyntax)
beginStatement = nsBlock.NamespaceStatement
body = nsBlock.Members
endStatement = nsBlock.EndNamespaceStatement
Return True
Case SyntaxKind.ModuleBlock, SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ClassBlock
Dim typeBlock = DirectCast(possibleBlock, TypeBlockSyntax)
beginStatement = typeBlock.BlockStatement
body = typeBlock.Members
endStatement = typeBlock.EndBlockStatement
Return True
Case SyntaxKind.EnumBlock
Dim enumBlock = DirectCast(possibleBlock, EnumBlockSyntax)
beginStatement = enumBlock.EnumStatement
body = enumBlock.Members
endStatement = enumBlock.EndEnumStatement
Return True
Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock, SyntaxKind.ConstructorBlock,
SyntaxKind.OperatorBlock, SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock,
SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock
Dim methodBlock = DirectCast(possibleBlock, MethodBlockBaseSyntax)
beginStatement = methodBlock.BlockStatement
body = methodBlock.Statements
endStatement = methodBlock.EndBlockStatement
Return True
Case SyntaxKind.PropertyBlock
Dim propertyBlock = DirectCast(possibleBlock, PropertyBlockSyntax)
beginStatement = propertyBlock.PropertyStatement
body = Nothing ' doesn't have a body per se
endStatement = propertyBlock.EndPropertyStatement
Return True
Case SyntaxKind.EventBlock
Dim eventBlock = DirectCast(possibleBlock, EventBlockSyntax)
beginStatement = eventBlock.EventStatement
body = Nothing ' doesn't have a body per se
endStatement = eventBlock.EndEventStatement
Return True
Case SyntaxKind.WhileBlock
Dim whileBlock = DirectCast(possibleBlock, WhileBlockSyntax)
beginStatement = whileBlock.WhileStatement
body = whileBlock.Statements
endStatement = whileBlock.EndWhileStatement
Return True
Case SyntaxKind.ForBlock, SyntaxKind.ForEachBlock
Dim forBlock = DirectCast(possibleBlock, ForOrForEachBlockSyntax)
beginStatement = forBlock.ForOrForEachStatement
body = forBlock.Statements
endStatement = forBlock.NextStatement
Return True
Case SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock,
SyntaxKind.DoUntilLoopBlock,
SyntaxKind.DoLoopWhileBlock,
SyntaxKind.DoLoopUntilBlock
Dim doBlock = DirectCast(possibleBlock, DoLoopBlockSyntax)
beginStatement = doBlock.DoStatement
body = doBlock.Statements
endStatement = doBlock.LoopStatement
Return True
Case SyntaxKind.UsingBlock
Dim usingBlock = DirectCast(possibleBlock, UsingBlockSyntax)
beginStatement = usingBlock.UsingStatement
body = usingBlock.Statements
endStatement = usingBlock.EndUsingStatement
Return True
Case SyntaxKind.SyncLockBlock
Dim syncBlock = DirectCast(possibleBlock, SyncLockBlockSyntax)
beginStatement = syncBlock.SyncLockStatement
body = syncBlock.Statements
endStatement = syncBlock.EndSyncLockStatement
Return True
Case SyntaxKind.WithBlock
Dim withBlock = DirectCast(possibleBlock, WithBlockSyntax)
beginStatement = withBlock.WithStatement
body = withBlock.Statements
endStatement = withBlock.EndWithStatement
Return True
Case SyntaxKind.SelectBlock
Dim selectBlock = DirectCast(possibleBlock, SelectBlockSyntax)
beginStatement = selectBlock.SelectStatement
body = Nothing ' doesn't fit
endStatement = selectBlock.EndSelectStatement
Return True
Case SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock
Dim caseBlock = DirectCast(possibleBlock, CaseBlockSyntax)
beginStatement = caseBlock.CaseStatement
body = caseBlock.Statements
endStatement = Nothing ' doesn't fit
Return True
Case SyntaxKind.SingleLineIfStatement
Dim ifStatement = DirectCast(possibleBlock, SingleLineIfStatementSyntax)
beginStatement = Nothing ' doesn't fit
beginTerminator = ifStatement.ThenKeyword
body = ifStatement.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.SingleLineElseClause
Dim elseClause = DirectCast(possibleBlock, SingleLineElseClauseSyntax)
beginStatement = Nothing ' doesn't fit
beginTerminator = elseClause.ElseKeyword
body = elseClause.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.MultiLineIfBlock
Dim ifBlock = DirectCast(possibleBlock, MultiLineIfBlockSyntax)
beginStatement = ifBlock.IfStatement
body = ifBlock.Statements
endStatement = ifBlock.EndIfStatement
Return True
Case SyntaxKind.ElseIfBlock
Dim elseIfBlock = DirectCast(possibleBlock, ElseIfBlockSyntax)
beginStatement = elseIfBlock.ElseIfStatement
body = elseIfBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.ElseBlock
Dim elseBlock = DirectCast(possibleBlock, ElseBlockSyntax)
beginStatement = elseBlock.ElseStatement
body = elseBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.TryBlock
Dim tryBlock = DirectCast(possibleBlock, TryBlockSyntax)
beginStatement = tryBlock.TryStatement
body = tryBlock.Statements
endStatement = tryBlock.EndTryStatement
Return True
Case SyntaxKind.CatchBlock
Dim catchBlock = DirectCast(possibleBlock, CatchBlockSyntax)
beginStatement = catchBlock.CatchStatement
body = catchBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.FinallyBlock
Dim finallyBlock = DirectCast(possibleBlock, FinallyBlockSyntax)
beginStatement = finallyBlock.FinallyStatement
body = finallyBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case Else
Return False
End Select
End Function
''' <summary>
''' If "node" is a block statement return the Begin statement of "node", otherwise return "node".
''' </summary>
Friend Shared Function BeginOfBlockStatementIfAny(node As SyntaxNode) As SyntaxNode
Dim beginStatement As StatementSyntax = Nothing
Dim body As SyntaxList(Of StatementSyntax) = Nothing
Dim endStatement As StatementSyntax = Nothing
Dim beginTerminator As SyntaxToken = Nothing
If IsBlockStatement(node, beginStatement, beginTerminator, body, endStatement) Then
If beginStatement IsNot Nothing Then
Return beginStatement
End If
End If
Return node
End Function
Public Shared Function GetText(accessibility As Accessibility) As String
Select Case accessibility
Case Accessibility.Friend
Return GetText(SyntaxKind.FriendKeyword)
Case Accessibility.NotApplicable
Return String.Empty
Case Accessibility.Private
Return GetText(SyntaxKind.PrivateKeyword)
Case Accessibility.Protected
Return GetText(SyntaxKind.ProtectedKeyword)
Case Accessibility.ProtectedAndFriend
Return GetText(SyntaxKind.PrivateKeyword) + " " + GetText(SyntaxKind.ProtectedKeyword)
Case Accessibility.ProtectedOrFriend
Return GetText(SyntaxKind.ProtectedKeyword) + " " + GetText(SyntaxKind.FriendKeyword)
Case Accessibility.Public
Return GetText(SyntaxKind.PublicKeyword)
Case Else
Debug.Assert(False, String.Format("Unknown accessibility '{0}'", accessibility))
Return Nothing
End Select
End Function
Public Shared Function IsAnyToken(kind As SyntaxKind) As Boolean
Return kind >= SyntaxKind.AddHandlerKeyword AndAlso kind <= SyntaxKind.CharacterLiteralToken
End Function
Public Shared Function GetUnaryExpression(token As SyntaxKind) As SyntaxKind
Select Case token
Case SyntaxKind.PlusToken
Return SyntaxKind.UnaryPlusExpression
Case SyntaxKind.MinusToken
Return SyntaxKind.UnaryMinusExpression
Case SyntaxKind.NotKeyword
Return SyntaxKind.NotExpression
Case SyntaxKind.AddressOfKeyword
Return SyntaxKind.AddressOfExpression
Case Else
Return SyntaxKind.None
End Select
End Function
Public Shared Function IsPreprocessorPunctuation(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.HashToken
End Function
Public Shared Function IsLanguagePunctuation(kind As SyntaxKind) As Boolean
Return IsPunctuation(kind) AndAlso Not IsPreprocessorPunctuation(kind)
End Function
Public Shared Function IsName(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.IdentifierName OrElse
kind = SyntaxKind.GenericName OrElse
kind = SyntaxKind.QualifiedName OrElse
kind = SyntaxKind.GlobalName
End Function
Public Shared Function IsNamespaceMemberDeclaration(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.ClassStatement OrElse kind = SyntaxKind.InterfaceStatement OrElse
kind = SyntaxKind.StructureStatement OrElse kind = SyntaxKind.EnumStatement OrElse
kind = SyntaxKind.ModuleStatement OrElse kind = SyntaxKind.NamespaceStatement OrElse
kind = SyntaxKind.DelegateFunctionStatement OrElse kind = SyntaxKind.DelegateSubStatement
End Function
Public Shared Function IsPunctuationOrKeyword(kind As SyntaxKind) As Boolean
Select Case kind
Case SyntaxKind.AddHandlerKeyword To SyntaxKind.EndOfXmlToken,
SyntaxKind.NameOfKeyword,
SyntaxKind.DollarSignDoubleQuoteToken,
SyntaxKind.EndOfInterpolatedStringToken
Return True
Case Else
Return False
End Select
End Function
Public Shared Function VarianceKindFromToken(token As SyntaxToken) As VarianceKind
Select Case token.Kind
Case SyntaxKind.OutKeyword
Return VarianceKind.Out
Case SyntaxKind.InKeyword
Return VarianceKind.In
Case Else
Return VarianceKind.None
End Select
End Function
''' <summary>
''' Checks if the SyntaxNode is an attribute name. To be an attribute name, the syntax
''' must be parented by an Attribute and the node itself must be equal to the Attribute.Name
''' property.
''' </summary>
Public Shared Function IsAttributeName(node As SyntaxNode) As Boolean
Dim nextNode As SyntaxNode = node
Do While nextNode IsNot Nothing
Select Case nextNode.Kind()
Case SyntaxKind.IdentifierName, SyntaxKind.QualifiedName
nextNode = nextNode.Parent
Case SyntaxKind.Attribute
Dim attribute = DirectCast(nextNode, AttributeSyntax)
If attribute.Name Is node Then
Return True
End If
Dim name As QualifiedNameSyntax = TryCast(attribute.Name, QualifiedNameSyntax)
Return name IsNot Nothing AndAlso name.Right Is node
Case Else
Return False
End Select
Loop
Return False
End Function
''' <summary>
''' Is the node the name of a named argument of an invocation or object creation expression,
''' but not an attribute.
''' </summary>
Public Shared Function IsNamedArgumentName(node As SyntaxNode) As Boolean
If node.Kind <> SyntaxKind.IdentifierName Then
Return False
End If
Dim parent1 = TryCast(node.Parent, NameColonEqualsSyntax)
If parent1 Is Nothing Then
Return False
End If
Dim parent2 = parent1.Parent.Parent
If parent2 Is Nothing OrElse Not parent2.IsKind(SyntaxKind.ArgumentList) Then
Return False
End If
Dim parent3 = parent2.Parent
If parent3 Is Nothing Then
Return False
End If
Select Case parent3.Kind
Case SyntaxKind.InvocationExpression,
SyntaxKind.ObjectCreationExpression,
SyntaxKind.RaiseEventStatement
Return True
Case Else
Return False
End Select
End Function
''' <summary>
''' Return keyword or punctuation text based on SyntaxKind
''' </summary>
Public Shared Function GetBlockName(kind As SyntaxKind) As String
Select Case kind
Case SyntaxKind.CaseBlock
Return "Case"
Case SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock,
SyntaxKind.DoUntilLoopBlock,
SyntaxKind.DoLoopWhileBlock,
SyntaxKind.DoLoopUntilBlock
Return "Do Loop"
Case SyntaxKind.WhileBlock
Return "While"
Case SyntaxKind.WithBlock
Return "With"
Case SyntaxKind.SyncLockBlock
Return "SyncLock"
Case SyntaxKind.UsingBlock
Return "Using"
Case SyntaxKind.ForBlock
Return "For"
Case SyntaxKind.ForEachBlock
Return "For Each"
Case SyntaxKind.SelectBlock
Return "Select"
Case SyntaxKind.MultiLineIfBlock
Return "If"
Case SyntaxKind.ElseIfBlock
Return "Else If"
Case SyntaxKind.ElseBlock
Return "Else"
Case SyntaxKind.TryBlock
Return "Try"
Case SyntaxKind.CatchBlock
Return "Catch"
Case SyntaxKind.FinallyBlock
Return "Finally"
Case Else
Throw New ArgumentOutOfRangeException(NameOf(kind))
End Select
End Function
''' <summary>
''' Indicates whether a newline may validly follow the specified SyntaxToken without requiring an explicit line continuation sequence ' _' or terminating the containing statement.
''' </summary>
''' <param name="token">The token to test. This token must be parented by a SyntaxNode.</param>
''' <returns>True if implicit line continuation is allowed after token.</returns>
''' <remarks>
''' <para>Refer to "Statements in Visual Basic", 2010 version, http://msdn.microsoft.com/en-us/library/865x40k4(v=vs.100).aspx
''' for examples.</para>
''' <para>Implicit line continuation may be used in Visual Basic: </para>
''' <list>
''' <item>After a comma (,).</item>
''' <item>After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.</item>
''' <item>After an open parenthesis (() or before a closing parenthesis ()).</item>
''' <item>After an open curly brace ({) or before a closing curly brace (}).</item>
''' <item>After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.</item>
''' <item>
''' <para>Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
''' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).</para>
''' <para>You cannot break a line between the keywords of query operators that are made up of multiple keywords
''' (Order By, Group Join, Take While, and Skip While).</para>
''' </item>
''' <item>After the concatenation operator (&).</item>
''' <item>After assignment operators (=, &=, :=, +=, -=, *=, /=, \=, ^=, <<=, >>=).</item>
''' <item>After binary operators (+, -, /, *, Mod, <>, <, >, <=, >=, ^, >>, <<, And, AndAlso, Or, OrElse, Like, Xor) within an expression.</item>
''' <item>After the Is and IsNot operators.</item>
''' <item>After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.</item>
''' <item>
''' <para>Also after a greater-than sign (>) when you specify an attribute.</para>
''' <para>However, you must include a line-continuation character (_) when you specify assembly-level or module-level attributes.</para>
''' </item>
''' <item>
''' <para>After a member qualifier character (.) and before the member name.</para>
''' <para>However, you must include a line-continuation character (_) following a member qualifier character when you are using the With statement or
''' supplying values in the initialization list for a type.</para>
''' </item>
''' <item>
''' <para>After an XML axis property qualifier (. or ...).</para>
''' <para>However, you must include a line-continuation character (_) when you specify a member qualifier when you are using the With keyword.</para>
''' </item>
''' <item>After the From keyword in a collection initializer.</item>
''' <item>After the With keyword in a member initializer.</item>
''' <item>After the In keyword in a For Each statement.</item>
''' </list>
''' </remarks>
Public Shared Function AllowsTrailingImplicitLineContinuation(token As SyntaxToken) As Boolean
If token.Parent Is Nothing Then Throw New ArgumentException("'token' must be parented by a SyntaxNode.")
Dim kind = token.Kind
Dim parentKind = token.Parent.Kind
' This list taken from: "Statements in Visual Basic", 2010 version, http://msdn.microsoft.com/en-us/library/865x40k4(v=vs.100).aspx
' After a comma (,).
If kind = SyntaxKind.CommaToken Then Return True
' Disallowed after unary minus and plus.
If kind = SyntaxKind.MinusToken OrElse kind = SyntaxKind.PlusToken Then
Return TypeOf token.Parent Is BinaryExpressionSyntax
End If
' Disallowed after xml namespace imports
If kind = SyntaxKind.GreaterThanToken AndAlso parentKind = SyntaxKind.XmlNamespaceImportsClause Then
Return False
End If
' After the concatenation operator (&).
' After assignment operators (=, &=, :=, +=, -=, *=, /=, \=, ^=, <<=, >>=).
' After binary operators (+, -, /, *, Mod, <>, <, >, <=, >=, ^, >>, <<, And, AndAlso, Or, OrElse, Like, Xor) within an expression.
' After the Is and IsNot operators.
' These cases are also covered by the binary operator check.
' After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.
' Also after a greater-than sign (>) when you specify an attribute.
' NOTE: No idea what this means:
' However, you must include a line-continuation character (_) when you specify assembly-level or module-level attributes.
If IsBinaryExpressionOperatorToken(kind) OrElse IsAssignmentStatementOperatorToken(kind) Then Return True
Select Case kind
Case SyntaxKind.ColonEqualsToken
Return True
' After an open parenthesis (() or before a closing parenthesis ()).
' After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.
Case SyntaxKind.OpenParenToken,
SyntaxKind.LessThanPercentEqualsToken,
SyntaxKind.PercentGreaterThanToken
Return True
' After an open curly brace ({) or before a closing curly brace (})
' However, a line-continuation character is required following the open curly brace of a string interpolation.
Case SyntaxKind.OpenBraceToken
If parentKind = SyntaxKind.Interpolation Then
Return False
End If
Return True
' After a member qualifier character (.) and before the member name.
' However, you must include a line-continuation character (_) following a member qualifier character when you are using the With statement or
' supplying values in the initialization list for a type.
Case SyntaxKind.DotToken
' bug # 12903
' when dot is directly under named field initializer, (_) is needed between "." and member name
If parentKind = SyntaxKind.NamedFieldInitializer Then
Return False
ElseIf parentKind = SyntaxKind.SimpleMemberAccessExpression Then
Return CType(token.Parent, MemberAccessExpressionSyntax).Expression IsNot Nothing OrElse
token.Parent.Parent.Kind = SyntaxKind.NamedFieldInitializer
' After an XML axis property qualifier (. or .@ or ...).
' However, you must include a line-continuation character (_) when you specify a member qualifier when you are using the With keyword.
' BUG: Dev11 doesn't allow after the @ token
ElseIf parentKind = SyntaxKind.XmlElementAccessExpression OrElse
parentKind = SyntaxKind.XmlAttributeAccessExpression OrElse
parentKind = SyntaxKind.XmlDescendantAccessExpression Then
' Dev 10/11 do not allow a "." on a line after a ".",
' This is an error
' a = <x/>.
' ..<x>
'
' while this is allowed
' a = <x/>.
' @<x>
' Note, this restriction may not be necessary. See comment in ParseQualifiedExpr line 830.
If CType(token.Parent, XmlMemberAccessExpressionSyntax).Base IsNot Nothing Then
Return token.GetNextToken.Kind <> SyntaxKind.DotToken
Else
Return False
End If
Else
Return True
End If
' After the With keyword in a member initializer.
Case SyntaxKind.WithKeyword
Return parentKind = SyntaxKind.ObjectMemberInitializer
' Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).
' After the From keyword in a collection initializer.
Case SyntaxKind.AggregateKeyword,
SyntaxKind.ByKeyword,
SyntaxKind.EqualsKeyword,
SyntaxKind.FromKeyword,
SyntaxKind.IntoKeyword,
SyntaxKind.JoinKeyword,
SyntaxKind.WhereKeyword
Return True
' This is new in Roslyn.
Case SyntaxKind.GetXmlNamespaceKeyword,
SyntaxKind.OfKeyword
Return True
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.GroupKeyword
Return parentKind <> SyntaxKind.GroupJoinClause
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.SkipKeyword
Return parentKind <> SyntaxKind.SkipWhileClause
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.TakeKeyword
Return parentKind <> SyntaxKind.TakeWhileClause
' After the In keyword in a For Each statement.
Case SyntaxKind.InKeyword
Return parentKind = SyntaxKind.CollectionRangeVariable OrElse
parentKind = SyntaxKind.ForEachStatement
' Keywords that may appear outside of query clauses
Case SyntaxKind.OnKeyword,
SyntaxKind.LetKeyword,
SyntaxKind.SelectKeyword,
SyntaxKind.WhileKeyword
Return TypeOf token.Parent Is QueryClauseSyntax
' XML Literals
Case SyntaxKind.BeginCDataToken,
SyntaxKind.DoubleQuoteToken,
SyntaxKind.LessThanExclamationMinusMinusToken,
SyntaxKind.LessThanQuestionToken,
SyntaxKind.XmlKeyword,
SyntaxKind.XmlNameToken,
SyntaxKind.XmlTextLiteralToken
Return True
Case SyntaxKind.EndCDataToken,
SyntaxKind.MinusMinusGreaterThanToken,
SyntaxKind.QuestionGreaterThanToken,
SyntaxKind.SlashGreaterThanToken
' An implicit line continuation is allowed only if the token is not the end of
' the xml literal. Walk up the parent chain and see if there is a parent node
' whose end extends beyond this token.
Dim p As XmlNodeSyntax = Nothing
Dim n = TryCast(token.Parent.Parent, XmlNodeSyntax)
While n IsNot Nothing
p = n
If p.EndPosition > token.EndPosition Then
Return True
End If
n = TryCast(n.Parent, XmlNodeSyntax)
End While
Return False
Case SyntaxKind.ColonToken
Return parentKind = SyntaxKind.XmlPrefix
Case Else
Return False
End Select
End Function
''' <summary>
''' Indicates whether a newline may validly precede the specified SyntaxToken without requiring an explicit line continuation sequence ' _' or terminating the containing statement.
''' </summary>
''' <param name="token">The token to test. This token must be parented by a SyntaxNode.</param>
''' <returns>True if implicit line continuation is allowed after token.</returns>