@@ -14,12 +14,10 @@ namespace ICSharpCode.CodeConverter.CSharp;
1414/// </summary>
1515internal partial class ExpressionNodeVisitor : VBasic . VisualBasicSyntaxVisitor < Task < CSharpSyntaxNode > >
1616{
17- private static readonly Type ConvertType = typeof ( Conversions ) ;
1817 public CommentConvertingVisitorWrapper TriviaConvertingExpressionVisitor => CommonConversions . TriviaConvertingExpressionVisitor ;
1918 private readonly SemanticModel _semanticModel ;
2019 private readonly HashSet < string > _extraUsingDirectives ;
2120 private readonly IOperatorConverter _operatorConverter ;
22- private readonly VisualBasicEqualityComparison _visualBasicEqualityComparison ;
2321 private readonly Stack < ExpressionSyntax > _withBlockLhs = new ( ) ;
2422 private readonly ITypeContext _typeContext ;
2523 private readonly QueryConverter _queryConverter ;
@@ -30,6 +28,7 @@ internal partial class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<T
3028 private readonly NameExpressionNodeVisitor _nameExpressionNodeVisitor ;
3129 private readonly ArgumentConverter _argumentConverter ;
3230 private readonly BinaryExpressionConverter _binaryExpressionConverter ;
31+ private readonly InitializerConverter _initializerConverter ;
3332
3433 public ExpressionNodeVisitor ( SemanticModel semanticModel ,
3534 VisualBasicEqualityComparison visualBasicEqualityComparison , ITypeContext typeContext , CommonConversions commonConversions ,
@@ -38,8 +37,8 @@ public ExpressionNodeVisitor(SemanticModel semanticModel,
3837 _semanticModel = semanticModel ;
3938 CommonConversions = commonConversions ;
4039 commonConversions . TriviaConvertingExpressionVisitor = new CommentConvertingVisitorWrapper ( this , _semanticModel . SyntaxTree ) ;
40+ _initializerConverter = new InitializerConverter ( semanticModel , commonConversions , _generatedNames , _tempNameForAnonymousScope ) ;
4141 _lambdaConverter = new LambdaConverter ( commonConversions , semanticModel , _withBlockLhs , extraUsingDirectives , typeContext ) ;
42- _visualBasicEqualityComparison = visualBasicEqualityComparison ;
4342 _queryConverter = new QueryConverter ( commonConversions , _semanticModel , TriviaConvertingExpressionVisitor ) ;
4443 _typeContext = typeContext ;
4544 _extraUsingDirectives = extraUsingDirectives ;
@@ -82,6 +81,12 @@ public override async Task<CSharpSyntaxNode> DefaultVisit(SyntaxNode node)
8281 public override async Task < CSharpSyntaxNode > VisitBinaryExpression ( VBasic . Syntax . BinaryExpressionSyntax entryNode ) => await _binaryExpressionConverter . ConvertBinaryExpressionAsync ( entryNode ) ;
8382 public override Task < CSharpSyntaxNode > VisitSingleLineLambdaExpression ( VBasic . Syntax . SingleLineLambdaExpressionSyntax node ) => _lambdaConverter . ConvertSingleLineLambdaAsync ( node ) ;
8483 public override Task < CSharpSyntaxNode > VisitMultiLineLambdaExpression ( VBasic . Syntax . MultiLineLambdaExpressionSyntax node ) => _lambdaConverter . ConvertMultiLineLambdaAsync ( node ) ;
84+ public override Task < CSharpSyntaxNode > VisitInferredFieldInitializer ( VBasic . Syntax . InferredFieldInitializerSyntax node ) => _initializerConverter . ConvertInferredFieldInitializerAsync ( node ) ;
85+ /// <remarks>Collection initialization has many variants in both VB and C#. Please add especially many test cases when touching this.</remarks>
86+ public override Task < CSharpSyntaxNode > VisitCollectionInitializer ( VBasic . Syntax . CollectionInitializerSyntax node ) => _initializerConverter . ConvertCollectionInitializerAsync ( node ) ;
87+ public override Task < CSharpSyntaxNode > VisitObjectMemberInitializer ( VBasic . Syntax . ObjectMemberInitializerSyntax node ) => _initializerConverter . ConvertObjectMemberInitializerAsync ( node ) ;
88+ public override Task < CSharpSyntaxNode > VisitNamedFieldInitializer ( VBasic . Syntax . NamedFieldInitializerSyntax node ) => _initializerConverter . ConvertNamedFieldInitializerAsync ( node ) ;
89+ public override Task < CSharpSyntaxNode > VisitObjectCollectionInitializer ( VBasic . Syntax . ObjectCollectionInitializerSyntax node ) => _initializerConverter . ConvertObjectCollectionInitializerAsync ( node ) ;
8590
8691 public override async Task < CSharpSyntaxNode > VisitGetTypeExpression ( VBasic . Syntax . GetTypeExpressionSyntax node )
8792 {
@@ -244,11 +249,6 @@ public override async Task<CSharpSyntaxNode> VisitAnonymousObjectCreationExpress
244249
245250 }
246251
247- public override async Task < CSharpSyntaxNode > VisitInferredFieldInitializer ( VBasic . Syntax . InferredFieldInitializerSyntax node )
248- {
249- return SyntaxFactory . AnonymousObjectMemberDeclarator ( await node . Expression . AcceptAsync < ExpressionSyntax > ( TriviaConvertingExpressionVisitor ) ) ;
250- }
251-
252252 public override async Task < CSharpSyntaxNode > VisitObjectCreationExpression ( VBasic . Syntax . ObjectCreationExpressionSyntax node )
253253 {
254254
@@ -295,52 +295,6 @@ await initializerToConvert.AcceptAsync<InitializerExpressionSyntax>(TriviaConver
295295 ) ;
296296 }
297297
298- /// <remarks>Collection initialization has many variants in both VB and C#. Please add especially many test cases when touching this.</remarks>
299- public override async Task < CSharpSyntaxNode > VisitCollectionInitializer ( VBasic . Syntax . CollectionInitializerSyntax node )
300- {
301- var isExplicitCollectionInitializer = node . Parent is VBasic . Syntax . ObjectCollectionInitializerSyntax
302- || node . Parent is VBasic . Syntax . CollectionInitializerSyntax
303- || node . Parent is VBasic . Syntax . ArrayCreationExpressionSyntax ;
304- var initializerKind = node . IsParentKind ( VBasic . SyntaxKind . ObjectCollectionInitializer ) || node . IsParentKind ( VBasic . SyntaxKind . ObjectCreationExpression ) ?
305- SyntaxKind . CollectionInitializerExpression :
306- node . IsParentKind ( VBasic . SyntaxKind . CollectionInitializer ) && IsComplexInitializer ( node ) ? SyntaxKind . ComplexElementInitializerExpression :
307- SyntaxKind . ArrayInitializerExpression ;
308- var initializers = ( await node . Initializers . SelectAsync ( async i => {
309- var convertedInitializer = await i . AcceptAsync < ExpressionSyntax > ( TriviaConvertingExpressionVisitor ) ;
310- return CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( i , convertedInitializer , false ) ;
311- } ) ) ;
312- var initializer = SyntaxFactory . InitializerExpression ( initializerKind , SyntaxFactory . SeparatedList ( initializers ) ) ;
313- if ( isExplicitCollectionInitializer ) return initializer ;
314-
315- var convertedType = _semanticModel . GetTypeInfo ( node ) . ConvertedType ;
316- var dimensions = convertedType is IArrayTypeSymbol ats ? ats . Rank : 1 ; // For multidimensional array [,] note these are different from nested arrays [][]
317- if ( ! ( convertedType . GetEnumerableElementTypeOrDefault ( ) is { } elementType ) ) return SyntaxFactory . ImplicitArrayCreationExpression ( initializer ) ;
318-
319- if ( ! initializers . Any ( ) && dimensions == 1 ) {
320- var arrayTypeArgs = SyntaxFactory . TypeArgumentList ( SyntaxFactory . SingletonSeparatedList ( CommonConversions . GetTypeSyntax ( elementType ) ) ) ;
321- var arrayEmpty = SyntaxFactory . MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression ,
322- ValidSyntaxFactory . IdentifierName ( nameof ( Array ) ) , SyntaxFactory . GenericName ( nameof ( Array . Empty ) ) . WithTypeArgumentList ( arrayTypeArgs ) ) ;
323- return SyntaxFactory . InvocationExpression ( arrayEmpty ) ;
324- }
325-
326- bool hasExpressionToInferTypeFrom = node . Initializers . SelectMany ( n => n . DescendantNodesAndSelf ( ) ) . Any ( n => n is not VBasic . Syntax . CollectionInitializerSyntax ) ;
327- if ( hasExpressionToInferTypeFrom ) {
328- var commas = Enumerable . Repeat ( SyntaxFactory . Token ( SyntaxKind . CommaToken ) , dimensions - 1 ) ;
329- return SyntaxFactory . ImplicitArrayCreationExpression ( SyntaxFactory . TokenList ( commas ) , initializer ) ;
330- }
331-
332- var arrayType = ( ArrayTypeSyntax ) CommonConversions . CsSyntaxGenerator . ArrayTypeExpression ( CommonConversions . GetTypeSyntax ( elementType ) ) ;
333- var sizes = Enumerable . Repeat < ExpressionSyntax > ( SyntaxFactory . OmittedArraySizeExpression ( ) , dimensions ) ;
334- var arrayRankSpecifierSyntax = SyntaxFactory . SingletonList ( SyntaxFactory . ArrayRankSpecifier ( SyntaxFactory . SeparatedList ( sizes ) ) ) ;
335- arrayType = arrayType . WithRankSpecifiers ( arrayRankSpecifierSyntax ) ;
336- return SyntaxFactory . ArrayCreationExpression ( arrayType , initializer ) ;
337- }
338-
339- private bool IsComplexInitializer ( VBSyntax . CollectionInitializerSyntax node )
340- {
341- return _semanticModel . GetOperation ( node . Parent . Parent ) is IObjectOrCollectionInitializerOperation initializer &&
342- initializer . Initializers . OfType < IInvocationOperation > ( ) . Any ( ) ;
343- }
344298
345299 public override async Task < CSharpSyntaxNode > VisitQueryExpression ( VBasic . Syntax . QueryExpressionSyntax node )
346300 {
@@ -354,69 +308,9 @@ public override async Task<CSharpSyntaxNode> VisitOrdering(VBasic.Syntax.Orderin
354308 var ascendingOrDescendingKeyword = node . AscendingOrDescendingKeyword . ConvertToken ( ) ;
355309 return SyntaxFactory . Ordering ( convertToken , expressionSyntax , ascendingOrDescendingKeyword ) ;
356310 }
357-
358- public override async Task < CSharpSyntaxNode > VisitObjectMemberInitializer ( VBasic . Syntax . ObjectMemberInitializerSyntax node )
359- {
360- var initializers = await node . Initializers . AcceptSeparatedListAsync < VBSyntax . FieldInitializerSyntax , ExpressionSyntax > ( TriviaConvertingExpressionVisitor ) ;
361- return SyntaxFactory . InitializerExpression ( SyntaxKind . ObjectInitializerExpression , initializers ) ;
362- }
363-
364- public override async Task < CSharpSyntaxNode > VisitNamedFieldInitializer ( VBasic . Syntax . NamedFieldInitializerSyntax node )
365- {
366- var csExpressionSyntax = await node . Expression . AcceptAsync < ExpressionSyntax > ( TriviaConvertingExpressionVisitor ) ;
367- csExpressionSyntax =
368- CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( node . Expression , csExpressionSyntax ) ;
369- if ( node . Parent ? . Parent is VBasic . Syntax . AnonymousObjectCreationExpressionSyntax { Initializer : { Initializers : var initializers } } anonymousObjectCreationExpression ) {
370- string nameIdentifierText = node . Name . Identifier . Text ;
371- var isAnonymouslyReused = initializers . OfType < VBasic . Syntax . NamedFieldInitializerSyntax > ( )
372- . Select ( i => i . Expression ) . OfType < VBasic . Syntax . MemberAccessExpressionSyntax > ( )
373- . Any ( maes => maes . Expression is null && maes . Name . Identifier . Text . Equals ( nameIdentifierText , StringComparison . OrdinalIgnoreCase ) ) ;
374- if ( isAnonymouslyReused ) {
375- string tempNameForAnonymousSelfReference = GenerateUniqueVariableName ( node . Name , "temp" + ( ( VBSyntax . SimpleNameSyntax ) node . Name ) . Identifier . Text . UppercaseFirstLetter ( ) ) ;
376- csExpressionSyntax = DeclareVariableInline ( csExpressionSyntax , tempNameForAnonymousSelfReference ) ;
377- if ( ! _tempNameForAnonymousScope . TryGetValue ( nameIdentifierText , out var stack ) ) {
378- stack = _tempNameForAnonymousScope [ nameIdentifierText ] = new Stack < ( SyntaxNode Scope , string TempName ) > ( ) ;
379- }
380- stack . Push ( ( anonymousObjectCreationExpression , tempNameForAnonymousSelfReference ) ) ;
381- }
382-
383- var anonymousObjectMemberDeclaratorSyntax = SyntaxFactory . AnonymousObjectMemberDeclarator (
384- SyntaxFactory . NameEquals ( SyntaxFactory . IdentifierName ( ConvertIdentifier ( node . Name . Identifier ) ) ) ,
385- csExpressionSyntax ) ;
386- return anonymousObjectMemberDeclaratorSyntax ;
387- }
388-
389- return SyntaxFactory . AssignmentExpression ( SyntaxKind . SimpleAssignmentExpression ,
390- await node . Name . AcceptAsync < ExpressionSyntax > ( TriviaConvertingExpressionVisitor ) ,
391- csExpressionSyntax
392- ) ;
393- }
394-
395- private string GenerateUniqueVariableName ( VisualBasicSyntaxNode existingNode , string varNameBase ) => NameGenerator . CS . GetUniqueVariableNameInScope ( _semanticModel , _generatedNames , existingNode , varNameBase ) ;
396-
397- private static ExpressionSyntax DeclareVariableInline ( ExpressionSyntax csExpressionSyntax , string temporaryName )
398- {
399- var temporaryNameId = SyntaxFactory . Identifier ( temporaryName ) ;
400- var temporaryNameExpression = ValidSyntaxFactory . IdentifierName ( temporaryNameId ) ;
401- csExpressionSyntax = SyntaxFactory . ConditionalExpression (
402- SyntaxFactory . IsPatternExpression (
403- csExpressionSyntax ,
404- SyntaxFactory . VarPattern (
405- SyntaxFactory . SingleVariableDesignation ( temporaryNameId ) ) ) ,
406- temporaryNameExpression ,
407- SyntaxFactory . LiteralExpression (
408- SyntaxKind . DefaultLiteralExpression ,
409- SyntaxFactory . Token ( SyntaxKind . DefaultKeyword ) ) ) ;
410- return csExpressionSyntax ;
411- }
412-
413311 public override async Task < CSharpSyntaxNode > VisitVariableNameEquals ( VBSyntax . VariableNameEqualsSyntax node ) =>
414312 SyntaxFactory . NameEquals ( SyntaxFactory . IdentifierName ( ConvertIdentifier ( node . Identifier . Identifier ) ) ) ;
415313
416- public override async Task < CSharpSyntaxNode > VisitObjectCollectionInitializer ( VBasic . Syntax . ObjectCollectionInitializerSyntax node )
417- {
418- return await node . Initializer . AcceptAsync < CSharpSyntaxNode > ( TriviaConvertingExpressionVisitor ) ; //Dictionary initializer comes through here despite the FROM keyword not being in the source code
419- }
420314
421315 public override async Task < CSharpSyntaxNode > VisitBinaryConditionalExpression ( VBasic . Syntax . BinaryConditionalExpressionSyntax node )
422316 {
0 commit comments