Skip to content

Commit b663496

Browse files
Merge pull request #566 from icsharpcode/byref
Byref
2 parents 4fdb645 + b88c2aa commit b663496

18 files changed

+1010
-512
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1414
* Add parentheses around ternary statement - [#565](https://github.com/icsharpcode/CodeConverter/issues/565)
1515
* When converting ForEach loop, avoid duplicate variable compilation issue [#558](https://github.com/icsharpcode/CodeConverter/issues/558)
1616
* Improvements to for loop with missing semantic info - [#482](https://github.com/icsharpcode/CodeConverter/issues/482)
17+
* Fix logic issue when converting property passed byref - [#324](https://github.com/icsharpcode/CodeConverter/issues/324)
18+
* Fix logic issue when converting expression passed in byref within conditional expression - [#310](https://github.com/icsharpcode/CodeConverter/issues/310)
1719

1820
### C# -> VB
1921

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
3+
namespace ICSharpCode.CodeConverter.CSharp
4+
{
5+
internal class AdditionalAssignment : IHoistedNode
6+
{
7+
public AdditionalAssignment(ExpressionSyntax lhs, ExpressionSyntax rhs)
8+
{
9+
RightHandSide = rhs ?? throw new System.ArgumentNullException(nameof(rhs));
10+
LeftHandSide = lhs ?? throw new System.ArgumentNullException(nameof(lhs));
11+
}
12+
13+
public ExpressionSyntax LeftHandSide { get; set; }
14+
public ExpressionSyntax RightHandSide { get; }
15+
}
16+
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using Microsoft.CodeAnalysis;
35
using Microsoft.CodeAnalysis.CSharp;
46
using Microsoft.CodeAnalysis.CSharp.Syntax;
57

68
namespace ICSharpCode.CodeConverter.CSharp
79
{
8-
public class AdditionalLocal
10+
internal class AdditionalDeclaration : IHoistedNode
911
{
1012
public string Prefix { get; }
1113
public string Id { get; }
1214
public ExpressionSyntax Initializer { get; }
1315
public TypeSyntax Type { get; }
1416

15-
public AdditionalLocal(string prefix, ExpressionSyntax initializer, TypeSyntax type)
17+
public AdditionalDeclaration(string prefix, ExpressionSyntax initializer, TypeSyntax type)
1618
{
1719
Prefix = prefix;
1820
Id = $"ph{Guid.NewGuid().ToString("N")}";
1921
Initializer = initializer;
2022
Type = type;
2123
}
2224

23-
public IdentifierNameSyntax IdentifierName => SyntaxFactory.IdentifierName(Id).WithAdditionalAnnotations(AdditionalLocals.Annotation);
25+
public IdentifierNameSyntax IdentifierName => SyntaxFactory.IdentifierName(Id).WithAdditionalAnnotations(HoistedNodeState.Annotation);
2426
}
2527
}

CodeConverter/CSharp/AdditionalLocals.cs

Lines changed: 0 additions & 50 deletions
This file was deleted.

CodeConverter/CSharp/CommonConversions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,11 @@ public static AttributeArgumentListSyntax CreateAttributeArgumentList(params Att
508508
return SyntaxFactory.AttributeArgumentList(SyntaxFactory.SeparatedList(attributeArgumentSyntaxs));
509509
}
510510

511+
public static CSSyntax.LocalDeclarationStatementSyntax CreateLocalVariableDeclarationAndAssignment(string variableName, ExpressionSyntax initValue)
512+
{
513+
return SyntaxFactory.LocalDeclarationStatement(CreateVariableDeclarationAndAssignment(variableName, initValue));
514+
}
515+
511516
public static VariableDeclarationSyntax CreateVariableDeclarationAndAssignment(string variableName,
512517
ExpressionSyntax initValue, TypeSyntax explicitType = null)
513518
{

CodeConverter/CSharp/DeclarationNodeVisitor.cs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,14 @@ internal class DeclarationNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSh
2929
private static readonly Type DllImportType = typeof(DllImportAttribute);
3030
private static readonly Type CharSetType = typeof(CharSet);
3131
private static readonly SyntaxToken SemicolonToken = SyntaxFactory.Token(Microsoft.CodeAnalysis.CSharp.SyntaxKind.SemicolonToken);
32-
private static readonly TypeSyntax VarType = SyntaxFactory.ParseTypeName("var");
3332
private readonly CSharpCompilation _csCompilation;
3433
private readonly SyntaxGenerator _csSyntaxGenerator;
3534
private readonly Compilation _compilation;
3635
private readonly SemanticModel _semanticModel;
3736
private readonly MethodsWithHandles _methodsWithHandles = new MethodsWithHandles();
3837
private readonly Dictionary<VBSyntax.StatementSyntax, MemberDeclarationSyntax[]> _additionalDeclarations = new Dictionary<VBSyntax.StatementSyntax, MemberDeclarationSyntax[]>();
3938
private readonly AdditionalInitializers _additionalInitializers;
40-
private readonly AdditionalLocals _additionalLocals = new AdditionalLocals();
39+
private readonly HoistedNodeState _additionalLocals = new HoistedNodeState();
4140
private uint _failedMemberConversionMarkerCount;
4241
private readonly HashSet<string> _extraUsingDirectives = new HashSet<string>();
4342
private readonly VisualBasicEqualityComparison _visualBasicEqualityComparison;
@@ -490,7 +489,7 @@ private IEnumerable<MemberDeclarationSyntax> CreateMemberDeclarations(IReadOnlyC
490489
foreach (var f in fieldDecls) yield return f;
491490
} else
492491
{
493-
if (_additionalLocals.Count() > 0) {
492+
if (_additionalLocals.GetDeclarations().Count() > 0) {
494493
foreach (var additionalDecl in CreateAdditionalLocalMembers(convertedModifiers, attributes, decl)) {
495494
yield return additionalDecl;
496495
}
@@ -547,26 +546,19 @@ private IEnumerable<MemberDeclarationSyntax> CreateAdditionalLocalMembers(Syntax
547546
var methodName = invocationExpressionSyntax.Expression
548547
.ChildNodes().OfType<SimpleNameSyntax>().Last();
549548
var newMethodName = $"{methodName.Identifier.ValueText}_{v.Identifier.ValueText}";
550-
var localVars = _additionalLocals.Select(l => l.Value)
551-
.Select(al =>
552-
SyntaxFactory.LocalDeclarationStatement(
553-
CommonConversions.CreateVariableDeclarationAndAssignment(al.Prefix, al.Initializer)))
554-
.Cast<StatementSyntax>().ToList();
555-
var newInitializer = v.Initializer.Value.ReplaceNodes(
556-
v.Initializer.Value.GetAnnotatedNodes(AdditionalLocals.Annotation), (an, _) => {
557-
// This should probably use a unique name like in MethodBodyVisitor - a collision is far less likely here
558-
var id = ((IdentifierNameSyntax)an).Identifier.ValueText;
559-
return SyntaxFactory.IdentifierName(_additionalLocals[id].Prefix);
560-
});
561-
var body = SyntaxFactory.Block(
562-
localVars.Concat(SyntaxFactory.SingletonList(SyntaxFactory.ReturnStatement(newInitializer))));
563-
var methodAttrs = SyntaxFactory.List<AttributeListSyntax>();
549+
var declarationInfo = _additionalLocals.GetDeclarations();
550+
551+
var localVars = declarationInfo
552+
.Select(al => CommonConversions.CreateLocalVariableDeclarationAndAssignment(al.Prefix, al.Initializer))
553+
.ToArray<StatementSyntax>();
554+
555+
// This should probably use a unique name like in MethodBodyVisitor - a collision is far less likely here
556+
var newNames = declarationInfo.ToDictionary(l => l.Id, l => l.Prefix);
557+
var newInitializer = HoistedNodeState.ReplaceNames(v.Initializer.Value, newNames);
558+
559+
var body = SyntaxFactory.Block(localVars.Concat(SyntaxFactory.ReturnStatement(newInitializer).Yield()));
564560
// Method calls in initializers must be static in C# - Supporting this is #281
565-
var modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(Microsoft.CodeAnalysis.CSharp.SyntaxKind.StaticKeyword));
566-
var typeConstraints = SyntaxFactory.List<TypeParameterConstraintClauseSyntax>();
567-
var parameterList = SyntaxFactory.ParameterList();
568-
var methodDecl = SyntaxFactory.MethodDeclaration(methodAttrs, modifiers, decl.Type, null,
569-
SyntaxFactory.Identifier(newMethodName), null, parameterList, typeConstraints, body, null);
561+
var methodDecl = CreateParameterlessMethod(newMethodName, decl.Type, body);
570562
yield return methodDecl;
571563

572564
var newVar =
@@ -578,6 +570,17 @@ private IEnumerable<MemberDeclarationSyntax> CreateAdditionalLocalMembers(Syntax
578570
yield return SyntaxFactory.FieldDeclaration(SyntaxFactory.List(attributes), convertedModifiers, newVarDecl);
579571
}
580572

573+
private static MethodDeclarationSyntax CreateParameterlessMethod(string newMethodName, TypeSyntax type, BlockSyntax body)
574+
{
575+
var modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(Microsoft.CodeAnalysis.CSharp.SyntaxKind.StaticKeyword));
576+
var typeConstraints = SyntaxFactory.List<TypeParameterConstraintClauseSyntax>();
577+
var parameterList = SyntaxFactory.ParameterList();
578+
var methodAttrs = SyntaxFactory.List<AttributeListSyntax>();
579+
var methodDecl = SyntaxFactory.MethodDeclaration(methodAttrs, modifiers, type, null,
580+
SyntaxFactory.Identifier(newMethodName), null, parameterList, typeConstraints, body, null);
581+
return methodDecl;
582+
}
583+
581584
private List<MethodWithHandles> GetMethodWithHandles(VBSyntax.TypeBlockSyntax parentType)
582585
{
583586
if (parentType == null || !(this._semanticModel.GetDeclaredSymbol((global::Microsoft.CodeAnalysis.SyntaxNode)parentType) is ITypeSymbol containingType)) return new List<MethodWithHandles>();
@@ -1077,7 +1080,7 @@ public override async Task<CSharpSyntaxNode> VisitEventBlock(VBSyntax.EventBlock
10771080
var attributes = await block.AttributeLists.SelectManyAsync(CommonConversions.ConvertAttribute);
10781081
var modifiers = CommonConversions.ConvertModifiers(block, block.Modifiers, GetMemberContext(node));
10791082

1080-
var rawType = (TypeSyntax) await (block.AsClause?.Type).AcceptAsync(_triviaConvertingExpressionVisitor) ?? VarType;
1083+
var rawType = (TypeSyntax) await (block.AsClause?.Type).AcceptAsync(_triviaConvertingExpressionVisitor) ?? ValidSyntaxFactory.VarType;
10811084

10821085
var convertedAccessors = await node.Accessors.SelectAsync(async a => await a.AcceptAsync(TriviaConvertingDeclarationVisitor));
10831086
_additionalDeclarations.Add(node, convertedAccessors.OfType<MemberDeclarationSyntax>().ToArray());

0 commit comments

Comments
 (0)