forked from icsharpcode/CodeConverter
/
NodesVisitor.cs
2089 lines (1815 loc) · 123 KB
/
NodesVisitor.cs
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ICSharpCode.CodeConverter.Shared;
using ICSharpCode.CodeConverter.Util;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using SyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using SyntaxNodeExtensions = ICSharpCode.CodeConverter.Util.SyntaxNodeExtensions;
using VBSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax;
using VBasic = Microsoft.CodeAnalysis.VisualBasic;
using SyntaxToken = Microsoft.CodeAnalysis.SyntaxToken;
namespace ICSharpCode.CodeConverter.CSharp
{
public partial class VisualBasicConverter
{
class NodesVisitor : VBasic.VisualBasicSyntaxVisitor<CSharpSyntaxNode>
{
private readonly CSharpCompilation _csCompilation;
private readonly SemanticModel _semanticModel;
private readonly Dictionary<ITypeSymbol, string> _createConvertMethodsLookupByReturnType;
private List<MethodWithHandles> _methodsWithHandles;
private readonly Dictionary<VBSyntax.StatementSyntax, MemberDeclarationSyntax[]> _additionalDeclarations = new Dictionary<VBSyntax.StatementSyntax, MemberDeclarationSyntax[]>();
private readonly Stack<string> _withBlockTempVariableNames = new Stack<string>();
private static readonly SyntaxToken SemicolonToken = SyntaxFactory.Token(SyntaxKind.SemicolonToken);
private static readonly TypeSyntax VarType = SyntaxFactory.ParseTypeName("var");
private readonly AdditionalInitializers _additionalInitializers;
private readonly AdditionalLocals _additionalLocals = new AdditionalLocals();
private readonly QueryConverter _queryConverter;
private uint failedMemberConversionMarkerCount;
private HashSet<string> _extraUsingDirectives = new HashSet<string>();
private static readonly Type ExtensionAttributeType = typeof(ExtensionAttribute);
private readonly TypeConversionAnalyzer _typeConversionAnalyzer;
public CommentConvertingNodesVisitor TriviaConvertingVisitor { get; }
private bool _optionCompareText = false;
private CommonConversions CommonConversions { get; }
public NodesVisitor(SemanticModel semanticModel, CSharpCompilation csCompilation)
{
this._semanticModel = semanticModel;
this._csCompilation = csCompilation;
TriviaConvertingVisitor = new CommentConvertingNodesVisitor(this);
_createConvertMethodsLookupByReturnType = CreateConvertMethodsLookupByReturnType(semanticModel);
CommonConversions = new CommonConversions(semanticModel, TriviaConvertingVisitor);
_typeConversionAnalyzer = new TypeConversionAnalyzer(semanticModel, csCompilation, CommonConversions, _extraUsingDirectives);
_queryConverter = new QueryConverter(CommonConversions, TriviaConvertingVisitor);
_additionalInitializers = new AdditionalInitializers();
}
private static Dictionary<ITypeSymbol, string> CreateConvertMethodsLookupByReturnType(SemanticModel semanticModel)
{
var systemDotConvert = typeof(Convert).FullName;
var convertMethods = semanticModel.Compilation.GetTypeByMetadataName(systemDotConvert).GetMembers().Where(m =>
m.Name.StartsWith("To", StringComparison.Ordinal) && m.GetParameters().Length == 1);
var methodsByType = convertMethods.Where(m => m.Name != nameof(Convert.ToBase64String))
.GroupBy(m => new { ReturnType = m.GetReturnType(), Name = $"{systemDotConvert}.{m.Name}" })
.ToDictionary(m => m.Key.ReturnType, m => m.Key.Name);
return methodsByType;
}
public override CSharpSyntaxNode DefaultVisit(SyntaxNode node)
{
throw new NotImplementedException($"Conversion for {VBasic.VisualBasicExtensions.Kind(node)} not implemented, please report this issue")
.WithNodeInformation(node);
}
public override CSharpSyntaxNode VisitGetTypeExpression(VBSyntax.GetTypeExpressionSyntax node)
{
return SyntaxFactory.TypeOfExpression((TypeSyntax)node.Type.Accept(TriviaConvertingVisitor));
}
public override CSharpSyntaxNode VisitGlobalName(VBSyntax.GlobalNameSyntax node)
{
return SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.GlobalKeyword));
}
#region Attributes
private SyntaxList<AttributeListSyntax> ConvertAttributes(SyntaxList<VBSyntax.AttributeListSyntax> attributeListSyntaxs)
{
return SyntaxFactory.List(attributeListSyntaxs.SelectMany(ConvertAttribute));
}
IEnumerable<AttributeListSyntax> ConvertAttribute(VBSyntax.AttributeListSyntax attributeList)
{
return attributeList.Attributes.Where(a => !IsExtensionAttribute(a)).Select(a => (AttributeListSyntax)a.Accept(TriviaConvertingVisitor));
}
public override CSharpSyntaxNode VisitAttribute(VBSyntax.AttributeSyntax node)
{
return SyntaxFactory.AttributeList(
node.Target == null ? null : SyntaxFactory.AttributeTargetSpecifier(node.Target.AttributeModifier.ConvertToken()),
SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute((NameSyntax)node.Name.Accept(TriviaConvertingVisitor), (AttributeArgumentListSyntax)node.ArgumentList?.Accept(TriviaConvertingVisitor)))
);
}
#endregion
public override CSharpSyntaxNode VisitCompilationUnit(VBSyntax.CompilationUnitSyntax node)
{
var options = (VBasic.VisualBasicCompilationOptions)_semanticModel.Compilation.Options;
var importsClauses = options.GlobalImports.Select(gi => gi.Clause).Concat(node.Imports.SelectMany(imp => imp.ImportsClauses)).ToList();
_optionCompareText = node.Options.Any(x => x.NameKeyword.ValueText.Equals("Compare", StringComparison.OrdinalIgnoreCase) &&
x.ValueKeyword.ValueText.Equals("Text", StringComparison.OrdinalIgnoreCase));
var attributes = SyntaxFactory.List(node.Attributes.SelectMany(a => a.AttributeLists).SelectMany(ConvertAttribute));
var sourceAndConverted = node.Members.Select(m => (Source: m, Converted: ConvertMember(m))).ToReadOnlyCollection();
var convertedMembers = string.IsNullOrEmpty(options.RootNamespace)
? sourceAndConverted.Select(sd => sd.Converted)
: PrependRootNamespace(sourceAndConverted, SyntaxFactory.IdentifierName(options.RootNamespace));
var usingDirectiveSyntax = importsClauses.GroupBy(c => c.ToString()).Select(g => g.First())
.Select(c => (UsingDirectiveSyntax)c.Accept(TriviaConvertingVisitor))
.Concat(_extraUsingDirectives.Select(u => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(u))))
.GroupBy(u => u.ToString())
.Select(g => g.First());
return SyntaxFactory.CompilationUnit(
SyntaxFactory.List<ExternAliasDirectiveSyntax>(),
SyntaxFactory.List(usingDirectiveSyntax),
attributes,
SyntaxFactory.List(convertedMembers)
);
}
private IReadOnlyCollection<MemberDeclarationSyntax> PrependRootNamespace(
IReadOnlyCollection<(VBSyntax.StatementSyntax VbNode, MemberDeclarationSyntax CsNode)> memberConversion,
IdentifierNameSyntax rootNamespaceIdentifier)
{
var inGlobalNamespace = memberConversion
.ToLookup(m => IsNamespaceDeclarationInGlobalScope(m.VbNode), m => m.CsNode);
var members = inGlobalNamespace[true].ToList();
if (inGlobalNamespace[false].Any()) {
var newNamespaceDecl = (MemberDeclarationSyntax)SyntaxFactory.NamespaceDeclaration(rootNamespaceIdentifier)
.WithMembers(SyntaxFactory.List(inGlobalNamespace[false]));
members.Add(newNamespaceDecl);
}
return members;
}
private bool IsNamespaceDeclarationInGlobalScope(VBSyntax.StatementSyntax m)
{
if (!(m is VBSyntax.NamespaceBlockSyntax nss)) return false;
if (!(_semanticModel.GetSymbolInfo(nss.NamespaceStatement.Name).Symbol is INamespaceSymbol nsSymbol)) return false;
return nsSymbol.ContainingNamespace.IsGlobalNamespace;
}
public override CSharpSyntaxNode VisitSimpleImportsClause(VBSyntax.SimpleImportsClauseSyntax node)
{
var nameEqualsSyntax = node.Alias == null ? null
: SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(ConvertIdentifier(node.Alias.Identifier)));
var usingDirective = SyntaxFactory.UsingDirective(nameEqualsSyntax, (NameSyntax)node.Name.Accept(TriviaConvertingVisitor));
return usingDirective;
}
public override CSharpSyntaxNode VisitNamespaceBlock(VBSyntax.NamespaceBlockSyntax node)
{
var members = node.Members.Select(ConvertMember);
var namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(
(NameSyntax)node.NamespaceStatement.Name.Accept(TriviaConvertingVisitor),
SyntaxFactory.List<ExternAliasDirectiveSyntax>(),
SyntaxFactory.List<UsingDirectiveSyntax>(),
SyntaxFactory.List(members)
);
return namespaceDeclaration;
}
#region Namespace Members
IEnumerable<MemberDeclarationSyntax> ConvertMembers(SyntaxList<VBSyntax.StatementSyntax> members)
{
var parentType = members.FirstOrDefault()?.GetAncestor<VBSyntax.TypeBlockSyntax>();
_methodsWithHandles = GetMethodWithHandles(parentType);
if (parentType == null || !_methodsWithHandles.Any()) {
return GetDirectlyConvertMembers();
}
return _additionalInitializers.WithAdditionalInitializers(GetDirectlyConvertMembers().ToList(), ConvertIdentifier(parentType.BlockStatement.Identifier));
IEnumerable<MemberDeclarationSyntax> GetDirectlyConvertMembers()
{
foreach (var member in members) {
yield return ConvertMember(member);
if (_additionalDeclarations.TryGetValue(member, out var additionalStatements)) {
_additionalDeclarations.Remove(member);
foreach (var additionalStatement in additionalStatements) {
yield return additionalStatement;
}
}
}
}
}
/// <summary>
/// In case of error, creates a dummy class to attach the error comment to.
/// This is because:
/// * Empty statements are invalid in many contexts in C#.
/// * There may be no previous node to attach to.
/// * Attaching to a parent would result in the code being out of order from where it was originally.
/// </summary>
private MemberDeclarationSyntax ConvertMember(VBSyntax.StatementSyntax member)
{
try {
return (MemberDeclarationSyntax)member.Accept(TriviaConvertingVisitor);
} catch (Exception e) {
return CreateErrorMember(member, e);
}
MemberDeclarationSyntax CreateErrorMember(VBSyntax.StatementSyntax memberCausingError, Exception e)
{
var dummyClass
= SyntaxFactory.ClassDeclaration("_failedMemberConversionMarker" + ++failedMemberConversionMarkerCount);
return dummyClass.WithCsTrailingErrorComment(memberCausingError, e);
}
}
public override CSharpSyntaxNode VisitClassBlock(VBSyntax.ClassBlockSyntax node)
{
var classStatement = node.ClassStatement;
var attributes = ConvertAttributes(classStatement.AttributeLists);
SplitTypeParameters(classStatement.TypeParameterList, out var parameters, out var constraints);
var convertedIdentifier = ConvertIdentifier(classStatement.Identifier);
return SyntaxFactory.ClassDeclaration(
attributes, ConvertTypeBlockModifiers(classStatement, TokenContext.Global),
convertedIdentifier,
parameters,
ConvertInheritsAndImplements(node.Inherits, node.Implements),
constraints,
SyntaxFactory.List(ConvertMembers(node.Members))
);
}
private BaseListSyntax ConvertInheritsAndImplements(SyntaxList<VBSyntax.InheritsStatementSyntax> inherits, SyntaxList<VBSyntax.ImplementsStatementSyntax> implements)
{
if (inherits.Count + implements.Count == 0)
return null;
var baseTypes = new List<BaseTypeSyntax>();
foreach (var t in inherits.SelectMany(c => c.Types).Concat(implements.SelectMany(c => c.Types)))
baseTypes.Add(SyntaxFactory.SimpleBaseType((TypeSyntax)t.Accept(TriviaConvertingVisitor)));
return SyntaxFactory.BaseList(SyntaxFactory.SeparatedList(baseTypes));
}
public override CSharpSyntaxNode VisitModuleBlock(VBSyntax.ModuleBlockSyntax node)
{
var stmt = node.ModuleStatement;
var attributes = ConvertAttributes(stmt.AttributeLists);
var members = SyntaxFactory.List(ConvertMembers(node.Members));
TypeParameterListSyntax parameters;
SyntaxList<TypeParameterConstraintClauseSyntax> constraints;
SplitTypeParameters(stmt.TypeParameterList, out parameters, out constraints);
return SyntaxFactory.ClassDeclaration(
attributes, ConvertTypeBlockModifiers(stmt, TokenContext.InterfaceOrModule).Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword)),
ConvertIdentifier(stmt.Identifier),
parameters,
ConvertInheritsAndImplements(node.Inherits, node.Implements),
constraints,
members
);
}
public override CSharpSyntaxNode VisitStructureBlock(VBSyntax.StructureBlockSyntax node)
{
var stmt = node.StructureStatement;
var attributes = ConvertAttributes(stmt.AttributeLists);
var members = SyntaxFactory.List(ConvertMembers(node.Members));
TypeParameterListSyntax parameters;
SyntaxList<TypeParameterConstraintClauseSyntax> constraints;
SplitTypeParameters(stmt.TypeParameterList, out parameters, out constraints);
return SyntaxFactory.StructDeclaration(
attributes, ConvertTypeBlockModifiers(stmt, TokenContext.Global),
ConvertIdentifier(stmt.Identifier),
parameters,
ConvertInheritsAndImplements(node.Inherits, node.Implements),
constraints,
members
);
}
public override CSharpSyntaxNode VisitInterfaceBlock(VBSyntax.InterfaceBlockSyntax node)
{
var stmt = node.InterfaceStatement;
var attributes = ConvertAttributes(stmt.AttributeLists);
var members = SyntaxFactory.List(ConvertMembers(node.Members));
TypeParameterListSyntax parameters;
SyntaxList<TypeParameterConstraintClauseSyntax> constraints;
SplitTypeParameters(stmt.TypeParameterList, out parameters, out constraints);
return SyntaxFactory.InterfaceDeclaration(
attributes, ConvertTypeBlockModifiers(stmt, TokenContext.InterfaceOrModule),
ConvertIdentifier(stmt.Identifier),
parameters,
ConvertInheritsAndImplements(node.Inherits, node.Implements),
constraints,
members
);
}
private SyntaxTokenList ConvertTypeBlockModifiers(VBSyntax.TypeStatementSyntax stmt, TokenContext interfaceOrModule)
{
var extraModifiers = IsPartialType(stmt) && !HasPartialKeyword(stmt.Modifiers)
? new[] {SyntaxFactory.Token(SyntaxKind.PartialKeyword)}
: new SyntaxToken[0];
return CommonConversions.ConvertModifiers(stmt.Modifiers, interfaceOrModule).AddRange(extraModifiers);
}
private static bool HasPartialKeyword(SyntaxTokenList modifiers)
{
return modifiers.Any(m => m.IsKind(VBasic.SyntaxKind.PartialKeyword));
}
private bool IsPartialType(VBSyntax.DeclarationStatementSyntax stmt)
{
var declaredSymbol = _semanticModel.GetDeclaredSymbol(stmt);
return declaredSymbol.GetDeclarations().Count() > 1;
}
public override CSharpSyntaxNode VisitEnumBlock(VBSyntax.EnumBlockSyntax node)
{
var stmt = node.EnumStatement;
// we can cast to SimpleAsClause because other types make no sense as enum-type.
var asClause = (VBSyntax.SimpleAsClauseSyntax)stmt.UnderlyingType;
var attributes = stmt.AttributeLists.SelectMany(ConvertAttribute);
BaseListSyntax baseList = null;
if (asClause != null) {
baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList<BaseTypeSyntax>(SyntaxFactory.SimpleBaseType((TypeSyntax)asClause.Type.Accept(TriviaConvertingVisitor))));
if (asClause.AttributeLists.Count > 0) {
attributes = attributes.Concat(
SyntaxFactory.AttributeList(
SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.ReturnKeyword)),
SyntaxFactory.SeparatedList(asClause.AttributeLists.SelectMany(l => ConvertAttribute(l).SelectMany(a => a.Attributes)))
)
);
}
}
var members = SyntaxFactory.SeparatedList(node.Members.Select(m => (EnumMemberDeclarationSyntax)m.Accept(TriviaConvertingVisitor)));
return SyntaxFactory.EnumDeclaration(
SyntaxFactory.List(attributes), CommonConversions.ConvertModifiers(stmt.Modifiers, TokenContext.Global),
ConvertIdentifier(stmt.Identifier),
baseList,
members
);
}
public override CSharpSyntaxNode VisitEnumMemberDeclaration(VBSyntax.EnumMemberDeclarationSyntax node)
{
var attributes = ConvertAttributes(node.AttributeLists);
return SyntaxFactory.EnumMemberDeclaration(
attributes,
ConvertIdentifier(node.Identifier),
(EqualsValueClauseSyntax)node.Initializer?.Accept(TriviaConvertingVisitor)
);
}
public override CSharpSyntaxNode VisitDelegateStatement(VBSyntax.DelegateStatementSyntax node)
{
var attributes = node.AttributeLists.SelectMany(ConvertAttribute);
TypeParameterListSyntax typeParameters;
SyntaxList<TypeParameterConstraintClauseSyntax> constraints;
SplitTypeParameters(node.TypeParameterList, out typeParameters, out constraints);
TypeSyntax returnType;
var asClause = node.AsClause;
if (asClause == null) {
returnType = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword));
} else {
returnType = (TypeSyntax)asClause.Type.Accept(TriviaConvertingVisitor);
if (asClause.AttributeLists.Count > 0) {
attributes = attributes.Concat(
SyntaxFactory.AttributeList(
SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.ReturnKeyword)),
SyntaxFactory.SeparatedList(asClause.AttributeLists.SelectMany(l => ConvertAttribute(l).SelectMany(a => a.Attributes)))
)
);
}
}
return SyntaxFactory.DelegateDeclaration(
SyntaxFactory.List(attributes), CommonConversions.ConvertModifiers(node.Modifiers, TokenContext.Global),
returnType,
ConvertIdentifier(node.Identifier),
typeParameters,
(ParameterListSyntax)node.ParameterList?.Accept(TriviaConvertingVisitor),
constraints
);
}
#endregion
#region Type Members
public override CSharpSyntaxNode VisitFieldDeclaration(VBSyntax.FieldDeclarationSyntax node)
{
_additionalLocals.PushScope();
var attributes = node.AttributeLists.SelectMany(ConvertAttribute).ToList();
var convertableModifiers = node.Modifiers.Where(m => !SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.WithEventsKeyword));
var isWithEvents = node.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.WithEventsKeyword));
var convertedModifiers = CommonConversions.ConvertModifiers(convertableModifiers, GetMemberContext(node), true);
var isConst = convertedModifiers.Any(a => a.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.ConstKeyword));
var declarations = new List<MemberDeclarationSyntax>(node.Declarators.Count);
foreach (var declarator in node.Declarators) {
foreach (var decl in CommonConversions.SplitVariableDeclarations(declarator, preferExplicitType: isConst).Values) {
if (isWithEvents) {
var initializers = decl.Variables
.Where(a => a.Initializer != null)
.ToDictionary(v => v.Identifier.Text, v => v.Initializer);
var fieldDecl = decl.RemoveNodes(initializers.Values, SyntaxRemoveOptions.KeepNoTrivia);
var initializerCollection = convertedModifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword))
? _additionalInitializers.AdditionalStaticInitializers
: _additionalInitializers.AdditionalInstanceInitializers;
foreach (var initializer in initializers) {
initializerCollection.Add(initializer.Key, initializer.Value.Value);
}
var fieldDecls = MethodWithHandles.GetDeclarationsForFieldBackedProperty(fieldDecl,
convertedModifiers, SyntaxFactory.List(attributes), _methodsWithHandles);
declarations.AddRange(fieldDecls);
} else {
FieldDeclarationSyntax baseFieldDeclarationSyntax;
if (_additionalLocals.Count() > 0) {
if (decl.Variables.Count > 1) {
// Currently no way to tell which _additionalLocals would apply to which initializer
throw new NotImplementedException("Fields with multiple declarations and initializers with ByRef parameters not currently supported");
}
var v = decl.Variables.First();
if (v.Initializer.Value.DescendantNodes().OfType<InvocationExpressionSyntax>().Count() > 1) {
throw new NotImplementedException("Field initializers with nested method calls not currently supported");
}
var calledMethodName = v.Initializer.Value.DescendantNodesAndSelf().OfType<InvocationExpressionSyntax>().First().DescendantNodes().OfType<IdentifierNameSyntax>().First();
var newMethodName = $"{calledMethodName.Identifier.ValueText}_{v.Identifier.ValueText}";
var localVars = _additionalLocals.Select(l => l.Value)
.Select(al => SyntaxFactory.LocalDeclarationStatement(CommonConversions.CreateVariableDeclarationAndAssignment(al.Prefix, al.Initializer)))
.Cast<StatementSyntax>().ToList();
var newInitializer = v.Initializer.Value.ReplaceNodes(v.Initializer.Value.GetAnnotatedNodes(AdditionalLocals.Annotation), (an, _) => {
// This should probably use a unique name like in MethodBodyVisitor - a collision is far less likely here
var id = (an as IdentifierNameSyntax).Identifier.ValueText;
return SyntaxFactory.IdentifierName(_additionalLocals[id].Prefix);
});
var body = SyntaxFactory.Block(localVars.Concat(SyntaxFactory.SingletonList(SyntaxFactory.ReturnStatement(newInitializer))));
var methodAttrs = SyntaxFactory.List<AttributeListSyntax>();
// Method calls in initializers must be static in C# - Supporting this is #281
var modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword));
var typeConstraints = SyntaxFactory.List<TypeParameterConstraintClauseSyntax>();
var parameterList = SyntaxFactory.ParameterList();
var methodDecl = SyntaxFactory.MethodDeclaration(methodAttrs, modifiers, decl.Type, null, SyntaxFactory.Identifier(newMethodName), null, parameterList, typeConstraints, body, null);
declarations.Add(methodDecl);
var newVar = v.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(newMethodName))));
var newVarDecl = SyntaxFactory.VariableDeclaration(decl.Type, SyntaxFactory.SingletonSeparatedList(newVar));
baseFieldDeclarationSyntax = SyntaxFactory.FieldDeclaration(SyntaxFactory.List(attributes), convertedModifiers, newVarDecl);
} else {
baseFieldDeclarationSyntax = SyntaxFactory.FieldDeclaration(SyntaxFactory.List(attributes), convertedModifiers, decl);
}
declarations.Add(baseFieldDeclarationSyntax);
}
}
}
_additionalLocals.PopScope();
_additionalDeclarations.Add(node, declarations.Skip(1).ToArray());
return declarations.First();
}
private List<MethodWithHandles> GetMethodWithHandles(VBSyntax.TypeBlockSyntax parentType)
{
if (parentType == null) return new List<MethodWithHandles>();
return parentType.Members.OfType<VBSyntax.MethodBlockSyntax>()
.Select(m => {
var handlesClauseSyntax = m.SubOrFunctionStatement.HandlesClause;
if (handlesClauseSyntax == null) return null;
var csPropIds = handlesClauseSyntax.Events
.Where(e => e.EventContainer is VBSyntax.WithEventsEventContainerSyntax)
.Select(p => (ConvertIdentifier(((VBSyntax.WithEventsEventContainerSyntax) p.EventContainer).Identifier), ConvertIdentifier(p.EventMember.Identifier)))
.ToList();
if (!csPropIds.Any()) return null;
var csMethodId = ConvertIdentifier(m.SubOrFunctionStatement.Identifier);
return new MethodWithHandles(csMethodId, csPropIds);
}).Where(x => x != null)
.ToList();
}
public override CSharpSyntaxNode VisitPropertyStatement(VBSyntax.PropertyStatementSyntax node)
{
bool hasBody = node.Parent is VBSyntax.PropertyBlockSyntax;
var attributes = node.AttributeLists.SelectMany(ConvertAttribute).ToArray();
var isReadonly = node.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.ReadOnlyKeyword));
var isWriteOnly = node.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.WriteOnlyKeyword));
var convertibleModifiers = node.Modifiers.Where(m => !m.IsKind(VBasic.SyntaxKind.ReadOnlyKeyword, VBasic.SyntaxKind.WriteOnlyKeyword, VBasic.SyntaxKind.DefaultKeyword));
var modifiers = CommonConversions.ConvertModifiers(convertibleModifiers, GetMemberContext(node));
var isIndexer = node.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.DefaultKeyword));
var accessedThroughMyClass = IsAccessedThroughMyClass(node, node.Identifier, _semanticModel.GetDeclaredSymbol(node));
bool isInInterface = node.Ancestors().OfType<VBSyntax.InterfaceBlockSyntax>().FirstOrDefault() != null;
var initializer = (EqualsValueClauseSyntax)node.Initializer?.Accept(TriviaConvertingVisitor);
var rawType = (TypeSyntax)node.AsClause?.TypeSwitch(
(VBSyntax.SimpleAsClauseSyntax c) => c.Type,
(VBSyntax.AsNewClauseSyntax c) => {
initializer = SyntaxFactory.EqualsValueClause((ExpressionSyntax)c.NewExpression.Accept(TriviaConvertingVisitor));
return VBasic.SyntaxExtensions.Type(c.NewExpression.WithoutTrivia()); // We'll end up visiting this twice so avoid trivia this time
},
_ => { throw new NotImplementedException($"{_.GetType().FullName} not implemented!"); }
)?.Accept(TriviaConvertingVisitor) ?? VarType;
AccessorListSyntax accessors = null;
if (!hasBody) {
var getAccessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SemicolonToken);
var setAccessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SemicolonToken);
if (isWriteOnly) {
getAccessor = getAccessor.AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword));
}
if (isReadonly) {
setAccessor = setAccessor.AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword));
}
if (isInInterface && isReadonly) {
accessors = SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { getAccessor }));
} else if (isInInterface && isWriteOnly) {
accessors = SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { setAccessor }));
} else {
// In VB, there's a backing field which can always be read and written to even on ReadOnly/WriteOnly properties.
// Our conversion will rewrite usages of that field to use the property accessors which therefore must exist and be private at minimum.
accessors = SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { getAccessor, setAccessor }));
}
} else {
accessors = SyntaxFactory.AccessorList(
SyntaxFactory.List(
((VBSyntax.PropertyBlockSyntax)node.Parent).Accessors.Select(a => (AccessorDeclarationSyntax)a.Accept(TriviaConvertingVisitor))
)
);
}
if (isIndexer) {
if (accessedThroughMyClass) {
// Not sure if this is possible
throw new NotImplementedException("MyClass indexing not implemented");
}
return SyntaxFactory.IndexerDeclaration(
SyntaxFactory.List(attributes),
modifiers,
rawType,
null,
SyntaxFactory.BracketedParameterList(SyntaxFactory.SeparatedList(node.ParameterList.Parameters.Select(p => (ParameterSyntax)p.Accept(TriviaConvertingVisitor)))),
accessors
);
} else {
var csIdentifier = ConvertIdentifier(node.Identifier);
if (accessedThroughMyClass) {
var csIndentifierName = "MyClass" + csIdentifier.ValueText;
ExpressionSyntax thisDotIdentifier = SyntaxFactory.ParseExpression($"this.{csIndentifierName}");
var getReturn = SyntaxFactory.Block(SyntaxFactory.ReturnStatement(thisDotIdentifier));
var getAccessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, getReturn);
var setValue = SyntaxFactory.Block(SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, thisDotIdentifier, SyntaxFactory.IdentifierName("value"))));
var setAccessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration, setValue);
var realAccessors = SyntaxFactory.AccessorList(SyntaxFactory.List(new[] {getAccessor, setAccessor}));
var realDecl = SyntaxFactory.PropertyDeclaration(
SyntaxFactory.List(attributes),
modifiers,
rawType,
null,
csIdentifier, realAccessors,
null,
null,
SyntaxFactory.Token(SyntaxKind.None));
_additionalDeclarations.Add(node, new MemberDeclarationSyntax[] { realDecl });
modifiers = modifiers.Remove(modifiers.Single(m => m.IsKind(SyntaxKind.VirtualKeyword)));
csIdentifier = SyntaxFactory.Identifier(csIndentifierName);
}
return SyntaxFactory.PropertyDeclaration(
SyntaxFactory.List(attributes),
modifiers,
rawType,
null,
csIdentifier, accessors,
null,
initializer,
SyntaxFactory.Token(initializer == null ? SyntaxKind.None : SyntaxKind.SemicolonToken));
}
}
public override CSharpSyntaxNode VisitPropertyBlock(VBSyntax.PropertyBlockSyntax node)
{
return node.PropertyStatement.Accept(TriviaConvertingVisitor);
}
public override CSharpSyntaxNode VisitAccessorBlock(VBSyntax.AccessorBlockSyntax node)
{
SyntaxKind blockKind;
bool isIterator = node.GetModifiers().Any(m => SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.IteratorKeyword));
var csReturnVariableOrNull = GetRetVariableNameOrNull(node);
var convertedStatements = ConvertStatements(node.Statements, CreateMethodBodyVisitor(node, isIterator));
var body = WithImplicitReturnStatements(node, convertedStatements, csReturnVariableOrNull);
var attributes = ConvertAttributes(node.AccessorStatement.AttributeLists);
var modifiers = CommonConversions.ConvertModifiers(node.AccessorStatement.Modifiers, TokenContext.Local);
switch (node.Kind()) {
case VBasic.SyntaxKind.GetAccessorBlock:
blockKind = SyntaxKind.GetAccessorDeclaration;
break;
case VBasic.SyntaxKind.SetAccessorBlock:
blockKind = SyntaxKind.SetAccessorDeclaration;
break;
case VBasic.SyntaxKind.AddHandlerAccessorBlock:
blockKind = SyntaxKind.AddAccessorDeclaration;
break;
case VBasic.SyntaxKind.RemoveHandlerAccessorBlock:
blockKind = SyntaxKind.RemoveAccessorDeclaration;
break;
case VBasic.SyntaxKind.RaiseEventAccessorBlock:
blockKind = SyntaxKind.MethodDeclaration;
break;
default:
throw new NotSupportedException(node.Kind().ToString());
}
if (blockKind == SyntaxKind.MethodDeclaration) {
var parameterListSyntax = (ParameterListSyntax) node.AccessorStatement.ParameterList.Accept(TriviaConvertingVisitor);
var eventStatement = ((VBSyntax.EventBlockSyntax)node.Parent).EventStatement;
var eventName = ConvertIdentifier(eventStatement.Identifier).ValueText;
return SyntaxFactory.MethodDeclaration(attributes, modifiers,
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), null,
SyntaxFactory.Identifier($"On{eventName}"), null,
parameterListSyntax, SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(), body, null);
}
return SyntaxFactory.AccessorDeclaration(blockKind, attributes, modifiers, body);
}
public override CSharpSyntaxNode VisitAccessorStatement(VBSyntax.AccessorStatementSyntax node)
{
return SyntaxFactory.AccessorDeclaration(node.Kind().ConvertToken(), null);
}
public override CSharpSyntaxNode VisitMethodBlock(VBSyntax.MethodBlockSyntax node)
{
var methodBlock = (BaseMethodDeclarationSyntax)node.SubOrFunctionStatement.Accept(TriviaConvertingVisitor);
if (_semanticModel.GetDeclaredSymbol(node).IsPartialDefinition()) {
return methodBlock;
}
var csReturnVariableOrNull = GetRetVariableNameOrNull(node);
var visualBasicSyntaxVisitor = CreateMethodBodyVisitor(node, IsIterator(node), csReturnVariableOrNull);
var convertedStatements = ConvertStatements(node.Statements, visualBasicSyntaxVisitor);
var body = WithImplicitReturnStatements(node, convertedStatements, csReturnVariableOrNull);
return methodBlock.WithBody(body);
}
private static bool AllowsImplicitReturn(VBSyntax.MethodBlockBaseSyntax node)
{
return !IsIterator(node) && node.IsKind(VBasic.SyntaxKind.FunctionBlock, VBasic.SyntaxKind.GetAccessorBlock);
}
private static bool IsIterator(VBSyntax.MethodBlockBaseSyntax node)
{
return node.BlockStatement.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, VBasic.SyntaxKind.IteratorKeyword));
}
private BlockSyntax WithImplicitReturnStatements(VBSyntax.MethodBlockBaseSyntax node, BlockSyntax convertedStatements,
IdentifierNameSyntax csReturnVariableOrNull)
{
if (!AllowsImplicitReturn(node)) return convertedStatements;
var preBodyStatements = new List<StatementSyntax>();
var postBodyStatements = new List<StatementSyntax>();
var functionSym = _semanticModel.GetDeclaredSymbol(node);
var returnType = CommonConversions.ToCsTypeSyntax(functionSym.GetReturnType(), node);
if (csReturnVariableOrNull != null)
{
var retDeclaration = CommonConversions.CreateVariableDeclarationAndAssignment(
csReturnVariableOrNull.Identifier.ValueText, SyntaxFactory.DefaultExpression(returnType), returnType);
preBodyStatements.Add(SyntaxFactory.LocalDeclarationStatement(retDeclaration));
}
ControlFlowAnalysis controlFlowAnalysis = null;
if (!node.Statements.IsEmpty())
controlFlowAnalysis = _semanticModel.AnalyzeControlFlow(node.Statements.First(), node.Statements.Last());
bool mayNeedReturn = controlFlowAnalysis?.EndPointIsReachable != false;
if (mayNeedReturn)
{
var csReturnExpression = csReturnVariableOrNull ?? (ExpressionSyntax) SyntaxFactory.DefaultExpression(returnType);
postBodyStatements.Add(SyntaxFactory.ReturnStatement(csReturnExpression));
}
var statements = preBodyStatements
.Concat(convertedStatements.Statements)
.Concat(postBodyStatements);
return SyntaxFactory.Block(statements);
}
private IdentifierNameSyntax GetRetVariableNameOrNull(VBSyntax.MethodBlockBaseSyntax node)
{
if (!AllowsImplicitReturn(node)) return null;
bool assignsToMethodNameVariable = false;
if (!node.Statements.IsEmpty()) {
string methodName = GetMethodBlockBaseIdentifierForImplicitReturn(node).ValueText;
Func<ISymbol, bool> equalsMethodName = s => s.IsKind(SymbolKind.Local) && s.Name.Equals(methodName, StringComparison.OrdinalIgnoreCase);
var flow = _semanticModel.AnalyzeDataFlow(node.Statements.First(), node.Statements.Last());
if (flow.Succeeded) {
assignsToMethodNameVariable = flow.ReadInside.Any(equalsMethodName) || flow.WrittenInside.Any(equalsMethodName);
}
}
IdentifierNameSyntax csReturnVariable = null;
if (assignsToMethodNameVariable)
{
// In VB, assigning to the method name implicitly creates a variable that is returned when the method exits
var csReturnVariableName =
CommonConversions.ConvertIdentifier(GetMethodBlockBaseIdentifierForImplicitReturn(node)).ValueText + "Ret";
csReturnVariable = SyntaxFactory.IdentifierName(csReturnVariableName);
}
return csReturnVariable;
}
private BlockSyntax ConvertStatements(SyntaxList<VBSyntax.StatementSyntax> statements, VBasic.VisualBasicSyntaxVisitor<SyntaxList<StatementSyntax>> methodBodyVisitor)
{
return SyntaxFactory.Block(statements.SelectMany(s => s.Accept(methodBodyVisitor)));
}
private static bool IsAccessedThroughMyClass(SyntaxNode node, SyntaxToken identifier, ISymbol symbol)
{
bool accessedThroughMyClass = false;
if (symbol.IsVirtual && !symbol.IsAbstract) {
var classBlock = node.Ancestors().OfType<VBSyntax.ClassBlockSyntax>().FirstOrDefault();
if (classBlock != null) {
var memberAccesses = classBlock.DescendantNodes().OfType<VBSyntax.MemberAccessExpressionSyntax>();
accessedThroughMyClass = memberAccesses.Any(mae => {
bool isMyClass = mae.Expression is VBSyntax.MyClassExpressionSyntax;
bool namesMatch = mae.Name.Identifier.ValueText.Equals(identifier.ValueText, StringComparison.OrdinalIgnoreCase);
return isMyClass && namesMatch;
});
}
}
return accessedThroughMyClass;
}
public override CSharpSyntaxNode VisitMethodStatement(VBSyntax.MethodStatementSyntax node)
{
var attributes = ConvertAttributes(node.AttributeLists);
bool hasBody = node.Parent is VBSyntax.MethodBlockBaseSyntax;
if ("Finalize".Equals(node.Identifier.ValueText, StringComparison.OrdinalIgnoreCase)
&& node.Modifiers.Any(m => VBasic.VisualBasicExtensions.Kind(m) == VBasic.SyntaxKind.OverridesKeyword)) {
var decl = SyntaxFactory.DestructorDeclaration(
ConvertIdentifier(node.GetAncestor<VBSyntax.TypeBlockSyntax>().BlockStatement.Identifier)
).WithAttributeLists(attributes);
if (hasBody) return decl;
return decl.WithSemicolonToken(SemicolonToken);
} else {
var tokenContext = GetMemberContext(node);
var convertedModifiers = CommonConversions.ConvertModifiers(node.Modifiers, tokenContext);
var declaredSymbol = _semanticModel.GetDeclaredSymbol(node);
bool accessedThroughMyClass = IsAccessedThroughMyClass(node, node.Identifier, declaredSymbol);
var isPartialDefinition = declaredSymbol.IsPartialDefinition();
if (declaredSymbol.IsPartialImplementation() || isPartialDefinition) {
var privateModifier = convertedModifiers.SingleOrDefault(m => m.IsKind(SyntaxKind.PrivateKeyword));
if (privateModifier != default(SyntaxToken)) {
convertedModifiers = convertedModifiers.Remove(privateModifier);
}
if (!HasPartialKeyword(node.Modifiers)) {
convertedModifiers = convertedModifiers.Add(SyntaxFactory.Token(SyntaxKind.PartialKeyword));
}
}
SplitTypeParameters(node.TypeParameterList, out var typeParameters, out var constraints);
var csIdentifier = ConvertIdentifier(node.Identifier);
// If the method is virtual, and there is a MyClass.SomeMethod() call,
// we need to emit a non-virtual method for it to call
if (accessedThroughMyClass)
{
var identifierName = "MyClass" + csIdentifier.ValueText;
var arrowClause = SyntaxFactory.ArrowExpressionClause(
SyntaxFactory.ParseExpression($"this.{identifierName}();\n")
);
var realDecl = SyntaxFactory.MethodDeclaration(
attributes,
convertedModifiers,
(TypeSyntax)node.AsClause?.Type?.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)),
null,
ConvertIdentifier(node.Identifier),
typeParameters,
(ParameterListSyntax)node.ParameterList?.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.ParameterList(),
constraints,
null,
arrowClause
);
var declNode = (VBSyntax.StatementSyntax)node.Parent;
_additionalDeclarations.Add(declNode, new MemberDeclarationSyntax[] { realDecl });
convertedModifiers = convertedModifiers.Remove(convertedModifiers.Single(m => m.IsKind(SyntaxKind.VirtualKeyword)));
csIdentifier = SyntaxFactory.Identifier(identifierName);
}
var decl = SyntaxFactory.MethodDeclaration(
attributes,
convertedModifiers,
(TypeSyntax)node.AsClause?.Type?.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)),
null,
csIdentifier,
typeParameters,
(ParameterListSyntax)node.ParameterList?.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.ParameterList(),
constraints,
null,
null
);
if (hasBody && !isPartialDefinition) return decl;
return decl.WithSemicolonToken(SemicolonToken);
}
}
private bool HasExtensionAttribute(VBSyntax.AttributeListSyntax a)
{
return a.Attributes.Any(IsExtensionAttribute);
}
private bool IsExtensionAttribute(VBSyntax.AttributeSyntax a)
{
return _semanticModel.GetTypeInfo(a).ConvertedType?.GetFullMetadataName()?.Equals(ExtensionAttributeType.FullName) == true;
}
private TokenContext GetMemberContext(VBSyntax.StatementSyntax member)
{
var parentType = member.GetAncestorOrThis<VBSyntax.TypeBlockSyntax>();
var parentTypeKind = parentType?.Kind();
switch (parentTypeKind) {
case VBasic.SyntaxKind.ModuleBlock:
return TokenContext.MemberInModule;
case VBasic.SyntaxKind.ClassBlock:
return TokenContext.MemberInClass;
case VBasic.SyntaxKind.InterfaceBlock:
return TokenContext.MemberInInterface;
case VBasic.SyntaxKind.StructureBlock:
return TokenContext.MemberInStruct;
default:
throw new ArgumentOutOfRangeException(nameof(member));
}
}
public override CSharpSyntaxNode VisitEventBlock(VBSyntax.EventBlockSyntax node)
{
var block = node.EventStatement;
var attributes = block.AttributeLists.SelectMany(ConvertAttribute);
var modifiers = CommonConversions.ConvertModifiers(block.Modifiers, GetMemberContext(node));
var rawType = (TypeSyntax)block.AsClause?.Type.Accept(TriviaConvertingVisitor) ?? VarType;
var convertedAccessors = node.Accessors.Select(a => a.Accept(TriviaConvertingVisitor)).ToList();
_additionalDeclarations.Add(node, convertedAccessors.OfType<MemberDeclarationSyntax>().ToArray());
return SyntaxFactory.EventDeclaration(
SyntaxFactory.List(attributes),
modifiers,
rawType,
null,
ConvertIdentifier(block.Identifier),
SyntaxFactory.AccessorList(SyntaxFactory.List(convertedAccessors.OfType<AccessorDeclarationSyntax>()))
);
}
public override CSharpSyntaxNode VisitEventStatement(VBSyntax.EventStatementSyntax node)
{
var attributes = node.AttributeLists.SelectMany(ConvertAttribute);
var modifiers = CommonConversions.ConvertModifiers(node.Modifiers, GetMemberContext(node));
var id = ConvertIdentifier(node.Identifier);
if (node.AsClause == null) {
var delegateName = SyntaxFactory.Identifier(id.ValueText + "EventHandler");
var delegateDecl = SyntaxFactory.DelegateDeclaration(
SyntaxFactory.List<AttributeListSyntax>(),
modifiers,
SyntaxFactory.ParseTypeName("void"),
delegateName,
null,
(ParameterListSyntax)node.ParameterList.Accept(TriviaConvertingVisitor),
SyntaxFactory.List<TypeParameterConstraintClauseSyntax>()
);
var eventDecl = SyntaxFactory.EventFieldDeclaration(
SyntaxFactory.List(attributes),
modifiers,
SyntaxFactory.VariableDeclaration(SyntaxFactory.IdentifierName(delegateName),
SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(id)))
);
_additionalDeclarations.Add(node, new MemberDeclarationSyntax[] { delegateDecl });
return eventDecl;
}
return SyntaxFactory.EventFieldDeclaration(
SyntaxFactory.List(attributes),
modifiers,
SyntaxFactory.VariableDeclaration((TypeSyntax)node.AsClause.Type.Accept(TriviaConvertingVisitor),
SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(id)))
);
}
public override CSharpSyntaxNode VisitOperatorBlock(VBSyntax.OperatorBlockSyntax node)
{
return node.BlockStatement.Accept(TriviaConvertingVisitor);
}
public override CSharpSyntaxNode VisitOperatorStatement(VBSyntax.OperatorStatementSyntax node)
{
var containingBlock = (VBSyntax.OperatorBlockSyntax) node.Parent;
var attributes = SyntaxFactory.List(node.AttributeLists.SelectMany(ConvertAttribute));
var returnType = (TypeSyntax)node.AsClause?.Type.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword));
var parameterList = (ParameterListSyntax)node.ParameterList.Accept(TriviaConvertingVisitor);
var methodBodyVisitor = CreateMethodBodyVisitor(node);
var body = SyntaxFactory.Block(containingBlock.Statements.SelectMany(s => s.Accept(methodBodyVisitor)));
var modifiers = CommonConversions.ConvertModifiers(node.Modifiers, GetMemberContext(node));
var conversionModifiers = modifiers.Where(CommonConversions.IsConversionOperator).ToList();
var nonConversionModifiers = SyntaxFactory.TokenList(modifiers.Except(conversionModifiers));
if (conversionModifiers.Any()) {
return SyntaxFactory.ConversionOperatorDeclaration(attributes, nonConversionModifiers,
conversionModifiers.Single(), returnType, parameterList, body, null);
}
return SyntaxFactory.OperatorDeclaration(attributes, nonConversionModifiers, returnType, node.OperatorToken.ConvertToken(), parameterList, body, null);
}
private VBasic.VisualBasicSyntaxVisitor<SyntaxList<StatementSyntax>> CreateMethodBodyVisitor(VBasic.VisualBasicSyntaxNode node, bool isIterator = false, IdentifierNameSyntax csReturnVariable = null)
{
var methodBodyVisitor = new MethodBodyVisitor(node, _semanticModel, TriviaConvertingVisitor, _withBlockTempVariableNames, _extraUsingDirectives, _additionalLocals, TriviaConvertingVisitor.TriviaConverter) {
IsIterator = isIterator,
ReturnVariable = csReturnVariable,
};
return methodBodyVisitor.CommentConvertingVisitor;
}
public override CSharpSyntaxNode VisitConstructorBlock(VBSyntax.ConstructorBlockSyntax node)
{
var block = node.BlockStatement;
var attributes = block.AttributeLists.SelectMany(ConvertAttribute);
var modifiers = CommonConversions.ConvertModifiers(block.Modifiers, GetMemberContext(node), isConstructor: true);
var ctor = (node.Statements.FirstOrDefault() as VBSyntax.ExpressionStatementSyntax)?.Expression as VBSyntax.InvocationExpressionSyntax;
var ctorExpression = ctor?.Expression as VBSyntax.MemberAccessExpressionSyntax;
var ctorArgs = (ArgumentListSyntax)ctor?.ArgumentList?.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.ArgumentList();
IEnumerable<VBSyntax.StatementSyntax> statements;
ConstructorInitializerSyntax ctorCall;
if (ctorExpression == null || !ctorExpression.Name.Identifier.IsKindOrHasMatchingText(VBasic.SyntaxKind.NewKeyword)) {
statements = node.Statements;
ctorCall = null;
} else if (ctorExpression.Expression is VBSyntax.MyBaseExpressionSyntax) {
statements = node.Statements.Skip(1);
ctorCall = SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, ctorArgs);
} else if (ctorExpression.Expression is VBSyntax.MeExpressionSyntax || ctorExpression.Expression is VBSyntax.MyClassExpressionSyntax) {
statements = node.Statements.Skip(1);
ctorCall = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer, ctorArgs);
} else {
statements = node.Statements;
ctorCall = null;
}
var methodBodyVisitor = CreateMethodBodyVisitor(node);
return SyntaxFactory.ConstructorDeclaration(
SyntaxFactory.List(attributes),
modifiers,
ConvertIdentifier(node.GetAncestor<VBSyntax.TypeBlockSyntax>().BlockStatement.Identifier),
(ParameterListSyntax)block.ParameterList.Accept(TriviaConvertingVisitor),
ctorCall,
SyntaxFactory.Block(statements.SelectMany(s => s.Accept(methodBodyVisitor)))
);
}