Skip to content

Commit a666da3

Browse files
Deal with initializers not in the part where constructor is created
Fixes #281
1 parent 37a3dd6 commit a666da3

24 files changed

+239
-107
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1717
* Fix logic issue when converting property passed byref - [#324](https://github.com/icsharpcode/CodeConverter/issues/324)
1818
* Fix logic issue when converting expression passed in byref within conditional expression - [#310](https://github.com/icsharpcode/CodeConverter/issues/310)
1919
* Added constructors now only added to the relevant type - not other types in the same file
20-
* Converted field initializers moved to constructor in most cases - [#281](https://github.com/icsharpcode/CodeConverter/issues/281)
20+
* Converted non-static field initializers moved to constructor - [#281](https://github.com/icsharpcode/CodeConverter/issues/281)
2121

2222
### C# -> VB
2323

CodeConverter/CSharp/CommonConversions.cs

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
using Microsoft.CodeAnalysis.Editing;
1515
using Microsoft.CodeAnalysis.FindSymbols;
1616
using Microsoft.CodeAnalysis.Operations;
17-
using Microsoft.CodeAnalysis.VisualBasic;
18-
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
17+
using VBasic = Microsoft.CodeAnalysis.VisualBasic;
18+
using VBSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax;
1919
using ArgumentListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ArgumentListSyntax;
2020
using ArrayRankSpecifierSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.ArrayRankSpecifierSyntax;
2121
using ArrayTypeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.ArrayTypeSyntax;
@@ -27,7 +27,6 @@
2727
using TypeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax;
2828
using VariableDeclaratorSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.VariableDeclaratorSyntax;
2929
using VisualBasicExtensions = Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions;
30-
using VBSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax;
3130
using CSSyntax = Microsoft.CodeAnalysis.CSharp.Syntax;
3231
using CSSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
3332
using ITypeSymbol = Microsoft.CodeAnalysis.ITypeSymbol;
@@ -121,7 +120,7 @@ public bool ShouldPreferExplicitType(VBSyntax.ExpressionSyntax exp,
121120
}
122121

123122
private async Task<EqualsValueClauseSyntax> ConvertEqualsValueClauseSyntax(
124-
VariableDeclaratorSyntax vbDeclarator, ModifiedIdentifierSyntax vbName,
123+
VariableDeclaratorSyntax vbDeclarator, VBSyntax.ModifiedIdentifierSyntax vbName,
125124
VBSyntax.ExpressionSyntax vbInitValue,
126125
ITypeSymbol declaredSymbolType,
127126
ISymbol declaredSymbol, CSharpSyntaxNode initializerOrMethodDecl)
@@ -140,12 +139,16 @@ private async Task<EqualsValueClauseSyntax> ConvertEqualsValueClauseSyntax(
140139
? TypeConversionAnalyzer.AddExplicitConversion(vbInitValue, adjustedInitializerExpr, isConst: declaredConst)
141140
: adjustedInitializerExpr;
142141

143-
if (isField && !declaredSymbol.IsStatic && !IsDefinitelyStatic(vbName, vbInitValue)) {
144-
//TODO If not the part where we're doing type wide init, convert this declaration into an arrow property called "initial<FieldName>", then call it from the other part
145-
// Assuming this is the part for type wide init
146-
var lhs = SyntaxFactory.IdentifierName(ConvertIdentifier(vbName.Identifier, sourceTriviaMapKind: SourceTriviaMapKind.None));
147-
_typeContext.Initializers.AdditionalInstanceInitializers.Add((lhs, CSSyntaxKind.SimpleAssignmentExpression, adjustedInitializerExpr));
148-
equalsValueClauseSyntax = null;
142+
if (isField && !declaredSymbol.IsStatic && !_semanticModel.IsDefinitelyStatic(vbName, vbInitValue)) {
143+
if (_typeContext.Initializers.ShouldAddTypeWideInitToThisPart) {
144+
var lhs = SyntaxFactory.IdentifierName(ConvertIdentifier(vbName.Identifier, sourceTriviaMapKind: SourceTriviaMapKind.None));
145+
_typeContext.Initializers.AdditionalInstanceInitializers.Add((lhs, CSSyntaxKind.SimpleAssignmentExpression, adjustedInitializerExpr));
146+
equalsValueClauseSyntax = null;
147+
} else {
148+
var returnBlock = SyntaxFactory.Block(SyntaxFactory.ReturnStatement(adjustedInitializerExpr));
149+
_typeContext.HoistedState.Hoist<HoistedParameterlessFunction>(new HoistedParameterlessFunction(GetInitialValueFunctionName(vbName), csTypeSyntax, returnBlock));
150+
equalsValueClauseSyntax = null;
151+
}
149152
} else {
150153
equalsValueClauseSyntax = SyntaxFactory.EqualsValueClause(convertedInitializer);
151154
}
@@ -163,22 +166,13 @@ private async Task<EqualsValueClauseSyntax> ConvertEqualsValueClauseSyntax(
163166
return equalsValueClauseSyntax;
164167
}
165168

166-
/// <summary>
167-
/// Returns true only if expressions static (i.e. doesn't reference the containing instance)
168-
/// </summary>
169-
private bool IsDefinitelyStatic(ModifiedIdentifierSyntax vbName, VBSyntax.ExpressionSyntax vbInitValue)
170-
{
171-
var arrayBoundExpressions = vbName.ArrayBounds != null ? vbName.ArrayBounds.Arguments.Select(a => a.GetExpression()).Where(x => x != null) : Enumerable.Empty<VBSyntax.ExpressionSyntax>();
172-
var expressions = vbInitValue.Yield().Concat(arrayBoundExpressions).ToArray();
173-
return expressions.All(IsDefinitelyStatic);
174-
}
175-
176-
/// <summary>
177-
/// Returns true only if expression is static (i.e. doesn't reference the containing instance)
178-
/// </summary>
179-
private bool IsDefinitelyStatic(VBSyntax.ExpressionSyntax e)
169+
/// <remarks>
170+
/// In CS we need to lift non-static initializers to the constructor. But for partial classes these can be in different files.
171+
/// Rather than re-architect to allow communication between files, we create an initializer function, and call it from the other part, and just hope the name doesn't clash.
172+
/// </remarks>
173+
public static string GetInitialValueFunctionName(VBSyntax.ModifiedIdentifierSyntax vbName)
180174
{
181-
return _semanticModel.GetOperation(e).DescendantsAndSelf().OfType<IInstanceReferenceOperation>().Any() == false;
175+
return "initial" + vbName.Identifier.ValueText.ToPascalCase();
182176
}
183177

184178
private VariableDeclarationSyntax CreateVariableDeclaration(VariableDeclaratorSyntax vbDeclarator, bool preferExplicitType,
@@ -235,13 +229,13 @@ private static TypeSyntax WithDeclarationCasing(TypeSyntax syntax, ITypeSymbol t
235229
private static VBSyntax.ExpressionSyntax GetInitializerToConvert(VariableDeclaratorSyntax declarator)
236230
{
237231
return declarator.AsClause?.TypeSwitch(
238-
(SimpleAsClauseSyntax _) => declarator.Initializer?.Value,
239-
(AsNewClauseSyntax c) => c.NewExpression
232+
(VBSyntax.SimpleAsClauseSyntax _) => declarator.Initializer?.Value,
233+
(VBSyntax.AsNewClauseSyntax c) => c.NewExpression
240234
) ?? declarator.Initializer?.Value;
241235
}
242236

243237
private async Task<CSharpSyntaxNode> GetInitializerFromNameAndType(ITypeSymbol typeSymbol,
244-
ModifiedIdentifierSyntax name, CSharpSyntaxNode initializer)
238+
VBSyntax.ModifiedIdentifierSyntax name, CSharpSyntaxNode initializer)
245239
{
246240
if (!SyntaxTokenExtensions.IsKind(name.Nullable, SyntaxKind.None))
247241
{
@@ -333,7 +327,7 @@ public static bool MustInlinePropertyWithEventsAccess(SyntaxNode anyNodePossibly
333327

334328
public static bool InMethodCalledInitializeComponent(SyntaxNode anyNodePossiblyWithinMethod)
335329
{
336-
return anyNodePossiblyWithinMethod.GetAncestor<MethodBlockSyntax>()?.SubOrFunctionStatement.Identifier.Text == "InitializeComponent";
330+
return anyNodePossiblyWithinMethod.GetAncestor<VBSyntax.MethodBlockSyntax>()?.SubOrFunctionStatement.Identifier.Text == "InitializeComponent";
337331
}
338332

339333
public static SyntaxToken CsEscapedIdentifier(string text)
@@ -489,8 +483,8 @@ public async Task<ArrayRankSpecifierSyntax> ConvertArrayBounds(ArgumentListSynta
489483
private async Task<IEnumerable<ExpressionSyntax>> ConvertArrayBounds(SeparatedSyntaxList<VBSyntax.ArgumentSyntax> arguments)
490484
{
491485
return await arguments.SelectAsync(a => {
492-
VBSyntax.ExpressionSyntax upperBoundExpression = a is SimpleArgumentSyntax sas ? sas.Expression
493-
: a is RangeArgumentSyntax ras ? ras.UpperBound
486+
VBSyntax.ExpressionSyntax upperBoundExpression = a is VBSyntax.SimpleArgumentSyntax sas ? sas.Expression
487+
: a is VBSyntax.RangeArgumentSyntax ras ? ras.UpperBound
494488
: throw new ArgumentOutOfRangeException(nameof(a), a, null);
495489

496490
return IncreaseArrayUpperBoundExpression(upperBoundExpression);
@@ -559,7 +553,7 @@ public static CSSyntax.VariableDeclaratorSyntax CreateVariableDeclarator(string
559553
public async Task<(string, ExpressionSyntax extraArg)> GetParameterizedPropertyAccessMethod(IOperation operation)
560554
{
561555
if (operation is IPropertyReferenceOperation pro && pro.Arguments.Any() &&
562-
!pro.Property.IsDefault()) {
556+
!VBasic.VisualBasicExtensions.IsDefault(pro.Property)) {
563557
var isSetter = pro.Parent.Kind == OperationKind.SimpleAssignment && pro.Parent.Children.First() == pro;
564558
var extraArg = isSetter
565559
? (ExpressionSyntax) await operation.Parent.Syntax.ChildNodes().ElementAt(1).AcceptAsync(TriviaConvertingExpressionVisitor)
@@ -615,7 +609,7 @@ public static SyntaxToken GetMethodBlockBaseIdentifierForImplicitReturn(SyntaxNo
615609

616610
public static bool IsDefaultIndexer(SyntaxNode node)
617611
{
618-
return node is PropertyStatementSyntax pss && pss.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DefaultKeyword));
612+
return node is VBSyntax.PropertyStatementSyntax pss && pss.Modifiers.Any(m => SyntaxTokenExtensions.IsKind(m, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DefaultKeyword));
619613
}
620614

621615

@@ -641,7 +635,7 @@ public bool IsOutAttribute(VBSyntax.AttributeSyntax a)
641635
?.Equals(OutAttributeType.FullName) == true;
642636
}
643637

644-
public ISymbol GetDeclaredCsOriginalSymbolOrNull(VisualBasicSyntaxNode node)
638+
public ISymbol GetDeclaredCsOriginalSymbolOrNull(VBasic.VisualBasicSyntaxNode node)
645639
{
646640
var declaredSymbol = _semanticModel.GetDeclaredSymbol(node);
647641
return declaredSymbol != null ? GetCsOriginalSymbolOrNull(declaredSymbol) : null;

0 commit comments

Comments
 (0)