Skip to content

Commit d85f6b3

Browse files
Merge remote-tracking branch 'origin/master' into fix/ExplicitelyOmittedArguments/1
# Conflicts: # Tests/CSharp/MemberTests/MemberTests.cs
2 parents d686ca0 + 0658a1b commit d85f6b3

4 files changed

Lines changed: 84 additions & 14 deletions

File tree

CodeConverter/CSharp/CommonConversions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ namespace ICSharpCode.CodeConverter.CSharp;
2020

2121
internal class CommonConversions
2222
{
23-
public ITypeSymbol System_Linq_Expressions_Expression_T { get; }
2423
private static readonly Type ExtensionAttributeType = typeof(ExtensionAttribute);
2524
public Document Document { get; }
2625
public SemanticModel SemanticModel { get; }
@@ -49,9 +48,11 @@ public CommonConversions(Document document, SemanticModel semanticModel,
4948
_typeContext = typeContext;
5049
VisualBasicEqualityComparison = visualBasicEqualityComparison;
5150
WinformsConversions = new WinformsConversions(typeContext);
52-
System_Linq_Expressions_Expression_T = semanticModel.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1");
51+
KnownTypes = new KnownNamedTypes(semanticModel);
5352
}
5453

54+
public KnownNamedTypes KnownTypes { get; }
55+
5556
public record VariablePair(CSSyntax.VariableDeclaratorSyntax CsVar, VBSyntax.ModifiedIdentifierSyntax VbVar);
5657
public record VariablesDeclaration(CSSyntax.VariableDeclarationSyntax Decl, ITypeSymbol Type, List<VariablePair> Variables);
5758

@@ -756,5 +757,5 @@ public bool IsLinqDelegateExpression(VisualBasicSyntaxNode node)
756757
return false;
757758
}
758759

759-
private bool IsLinqDelegateExpression(ITypeSymbol convertedType) => System_Linq_Expressions_Expression_T?.Equals(convertedType?.OriginalDefinition, SymbolEqualityComparer.Default) == true;
760+
private bool IsLinqDelegateExpression(ITypeSymbol convertedType) =>KnownTypes.System_Linq_Expressions_Expression_T?.Equals(convertedType?.OriginalDefinition, SymbolEqualityComparer.Default) == true;
760761
}

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ internal class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSha
3535
private readonly QueryConverter _queryConverter;
3636
private readonly Lazy<IReadOnlyDictionary<ITypeSymbol, string>> _convertMethodsLookupByReturnType;
3737
private readonly LambdaConverter _lambdaConverter;
38-
private readonly INamedTypeSymbol _vbBooleanTypeSymbol;
3938
private readonly VisualBasicNullableExpressionsConverter _visualBasicNullableTypesConverter;
4039
private readonly Dictionary<string, Stack<(SyntaxNode Scope, string TempName)>> _tempNameForAnonymousScope = new();
4140
private readonly HashSet<string> _generatedNames = new(StringComparer.OrdinalIgnoreCase);
@@ -58,7 +57,6 @@ public ExpressionNodeVisitor(SemanticModel semanticModel,
5857
// If this isn't needed, the assembly with Conversions may not be referenced, so this must be done lazily
5958
_convertMethodsLookupByReturnType =
6059
new Lazy<IReadOnlyDictionary<ITypeSymbol, string>>(() => CreateConvertMethodsLookupByReturnType(semanticModel));
61-
_vbBooleanTypeSymbol = _semanticModel.Compilation.GetTypeByMetadataName("System.Boolean");
6260
}
6361

6462
private static IReadOnlyDictionary<ITypeSymbol, string> CreateConvertMethodsLookupByReturnType(
@@ -775,7 +773,7 @@ public override async Task<CSharpSyntaxNode> VisitBinaryConditionalExpression(VB
775773
public override async Task<CSharpSyntaxNode> VisitTernaryConditionalExpression(VBasic.Syntax.TernaryConditionalExpressionSyntax node)
776774
{
777775
var condition = await node.Condition.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
778-
condition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.Condition, condition, forceTargetType: _vbBooleanTypeSymbol);
776+
condition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.Condition, condition, forceTargetType: CommonConversions.KnownTypes.Boolean);
779777

780778
var whenTrue = await node.WhenTrue.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
781779
whenTrue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.WhenTrue, whenTrue);
@@ -900,7 +898,7 @@ private async Task<CSharpSyntaxNode> ConvertBinaryExpressionAsync(VBasic.Syntax.
900898
omitConversion = lhsTypeInfo.Type.SpecialType == SpecialType.System_String ||
901899
rhsTypeInfo.Type.SpecialType == SpecialType.System_String;
902900
if (lhsTypeInfo.ConvertedType.SpecialType != SpecialType.System_String) {
903-
forceLhsTargetType = _semanticModel.Compilation.GetTypeByMetadataName("System.String");
901+
forceLhsTargetType = CommonConversions.KnownTypes.String;
904902
}
905903
}
906904
}
@@ -938,6 +936,8 @@ private async Task<CSharpSyntaxNode> ConvertBinaryExpressionAsync(VBasic.Syntax.
938936
return node.Parent.IsKind(VBasic.SyntaxKind.SimpleArgument) ? exp : exp.AddParens();
939937
}
940938

939+
940+
941941
private async Task<ExpressionSyntax> RewriteBinaryOperatorOrNullAsync(VBSyntax.BinaryExpressionSyntax node) =>
942942
await _operatorConverter.ConvertRewrittenBinaryOperatorOrNullAsync(node, TriviaConvertingExpressionVisitor.IsWithinQuery);
943943

@@ -1823,8 +1823,54 @@ private ArgumentSyntax CreateExtraArgOrNull(IParameterSymbol p, bool requiresCom
18231823
private ArgumentSyntax CreateOptionalRefArg(IParameterSymbol p, RefKind refKind)
18241824
{
18251825
string prefix = $"arg{p.Name}";
1826-
var local = _typeContext.PerScopeState.Hoist(new AdditionalDeclaration(prefix, CommonConversions.Literal(p.ExplicitDefaultValue), CommonConversions.GetTypeSyntax(p.Type)));
1826+
var type = CommonConversions.GetTypeSyntax(p.Type);
1827+
ExpressionSyntax initializer;
1828+
if (p.HasExplicitDefaultValue) {
1829+
initializer = CommonConversions.Literal(p.ExplicitDefaultValue);
1830+
} else if (HasOptionalAttribute(p)) {
1831+
if (TryGetDefaultParameterValueAttributeValue(p, out var defaultValue)){
1832+
initializer = CommonConversions.Literal(defaultValue);
1833+
} else {
1834+
initializer = SyntaxFactory.DefaultExpression(type);
1835+
}
1836+
} else {
1837+
//invalid VB.NET code
1838+
return null;
1839+
}
1840+
var local = _typeContext.PerScopeState.Hoist(new AdditionalDeclaration(prefix, initializer, type));
18271841
return (ArgumentSyntax)CommonConversions.CsSyntaxGenerator.Argument(p.Name, refKind, local.IdentifierName);
1842+
1843+
bool HasOptionalAttribute(IParameterSymbol p)
1844+
{
1845+
var optionalAttribute = CommonConversions.KnownTypes.OptionalAttribute;
1846+
if (optionalAttribute == null) {
1847+
return false;
1848+
}
1849+
1850+
return p.GetAttributes().Any(a => SymbolEqualityComparer.IncludeNullability.Equals(a.AttributeClass, optionalAttribute));
1851+
}
1852+
1853+
bool TryGetDefaultParameterValueAttributeValue(IParameterSymbol p, out object defaultValue)
1854+
{
1855+
defaultValue = null;
1856+
1857+
var defaultParameterValueAttribute = CommonConversions.KnownTypes.DefaultParameterValueAttribute;
1858+
if (defaultParameterValueAttribute == null) {
1859+
return false;
1860+
}
1861+
1862+
var attributeData = p.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.IncludeNullability.Equals(a.AttributeClass, defaultParameterValueAttribute));
1863+
if (attributeData == null) {
1864+
return false;
1865+
}
1866+
1867+
if (attributeData.ConstructorArguments.Length == 0) {
1868+
return false;
1869+
}
1870+
1871+
defaultValue = attributeData.ConstructorArguments.First().Value;
1872+
return true;
1873+
}
18281874
}
18291875

18301876
private RefConversion NeedsVariableForArgument(VBasic.Syntax.ArgumentSyntax node, RefKind refKind)
@@ -1841,6 +1887,9 @@ RefConversion GetRefConversion(VBSyntax.ExpressionSyntax expression)
18411887
if (symbolInfo is IPropertySymbol propertySymbol) {
18421888
return propertySymbol.IsReadOnly ? RefConversion.PreAssigment : RefConversion.PreAndPostAssignment;
18431889
}
1890+
else if (symbolInfo is IFieldSymbol { IsConst: true } or ILocalSymbol { IsConst: true }) {
1891+
return RefConversion.PreAssigment;
1892+
}
18441893

18451894
if (DeclaredInUsing(symbolInfo)) return RefConversion.PreAssigment;
18461895

@@ -1900,7 +1949,7 @@ private ISymbol GetInvocationSymbol(SyntaxNode invocation)
19001949
(VBSyntax.InvocationExpressionSyntax e) => _semanticModel.GetSymbolInfo(e).ExtractBestMatch<ISymbol>(),
19011950
(VBSyntax.ObjectCreationExpressionSyntax e) => _semanticModel.GetSymbolInfo(e).ExtractBestMatch<ISymbol>(),
19021951
(VBSyntax.RaiseEventStatementSyntax e) => _semanticModel.GetSymbolInfo(e.Name).ExtractBestMatch<ISymbol>(),
1903-
(VBSyntax.MidExpressionSyntax _) => _semanticModel.Compilation.GetTypeByMetadataName("Microsoft.VisualBasic.CompilerServices.StringType")?.GetMembers("MidStmtStr").FirstOrDefault(),
1952+
(VBSyntax.MidExpressionSyntax _) => CommonConversions.KnownTypes.VbCompilerStringType?.GetMembers("MidStmtStr").FirstOrDefault(),
19041953
_ => throw new NotSupportedException());
19051954
return symbol;
19061955
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace ICSharpCode.CodeConverter.CSharp;
2+
3+
internal class KnownNamedTypes
4+
{
5+
public KnownNamedTypes(SemanticModel semanticModel)
6+
{
7+
Boolean = semanticModel.Compilation.GetTypeByMetadataName("System.Boolean");
8+
String = semanticModel.Compilation.GetTypeByMetadataName("System.String");
9+
DefaultParameterValueAttribute = semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.DefaultParameterValueAttribute");
10+
OptionalAttribute = semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.OptionalAttribute");
11+
System_Linq_Expressions_Expression_T = semanticModel.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1");
12+
VbCompilerStringType = semanticModel.Compilation.GetTypeByMetadataName("Microsoft.VisualBasic.CompilerServices.StringType");
13+
}
14+
15+
public INamedTypeSymbol System_Linq_Expressions_Expression_T { get; set; }
16+
17+
public INamedTypeSymbol Boolean { get; }
18+
public INamedTypeSymbol String { get; }
19+
public INamedTypeSymbol DefaultParameterValueAttribute { get; }
20+
public INamedTypeSymbol OptionalAttribute { get; }
21+
public INamedTypeSymbol VbCompilerStringType { get; }
22+
}

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ internal class MethodBodyExecutableStatementVisitor : VBasic.VisualBasicSyntaxVi
2424
private readonly HashSet<string> _extraUsingDirectives;
2525
private readonly HandledEventsAnalysis _handledEventsAnalysis;
2626
private readonly HashSet<string> _generatedNames = new();
27-
private readonly INamedTypeSymbol _vbBooleanTypeSymbol;
2827
private readonly HashSet<ILocalSymbol> _localsToInlineInLoop;
2928
private readonly PerScopeState _perScopeState;
3029

@@ -65,7 +64,6 @@ private MethodBodyExecutableStatementVisitor(VisualBasicSyntaxNode methodNode, S
6564
_perScopeState = typeContext.PerScopeState;
6665
var byRefParameterVisitor = new PerScopeStateVisitorDecorator(this, _perScopeState, semanticModel, _generatedNames);
6766
CommentConvertingVisitor = new CommentConvertingMethodBodyVisitor(byRefParameterVisitor);
68-
_vbBooleanTypeSymbol = _semanticModel.Compilation.GetTypeByMetadataName("System.Boolean");
6967
_localsToInlineInLoop = localsToInlineInLoop;
7068
}
7169

@@ -520,7 +518,7 @@ await node.Name.AcceptAsync<NameSyntax>(_expressionVisitor),
520518
public override async Task<SyntaxList<StatementSyntax>> VisitSingleLineIfStatement(VBSyntax.SingleLineIfStatementSyntax node)
521519
{
522520
var condition = await node.Condition.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
523-
condition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.Condition, condition, forceTargetType: _vbBooleanTypeSymbol);
521+
condition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.Condition, condition, forceTargetType: CommonConversions.KnownTypes.Boolean);
524522
var block = SyntaxFactory.Block(await ConvertStatementsAsync(node.Statements));
525523
ElseClauseSyntax elseClause = null;
526524

@@ -534,7 +532,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSingleLineIfStateme
534532
public override async Task<SyntaxList<StatementSyntax>> VisitMultiLineIfBlock(VBSyntax.MultiLineIfBlockSyntax node)
535533
{
536534
var condition = await node.IfStatement.Condition.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
537-
condition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.IfStatement.Condition, condition, forceTargetType: _vbBooleanTypeSymbol);
535+
condition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.IfStatement.Condition, condition, forceTargetType: CommonConversions.KnownTypes.Boolean);
538536
var block = SyntaxFactory.Block(await ConvertStatementsAsync(node.Statements));
539537

540538
var elseClause = await ConvertElseClauseAsync(node.ElseBlock);
@@ -553,7 +551,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitMultiLineIfBlock(VB
553551
{
554552
var elseBlock = SyntaxFactory.Block(await ConvertStatementsAsync(elseIf.Statements));
555553
var elseIfCondition = await elseIf.ElseIfStatement.Condition.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
556-
elseIfCondition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(elseIf.ElseIfStatement.Condition, elseIfCondition, forceTargetType: _vbBooleanTypeSymbol);
554+
elseIfCondition = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(elseIf.ElseIfStatement.Condition, elseIfCondition, forceTargetType: CommonConversions.KnownTypes.Boolean);
557555
return (elseIfCondition, elseBlock);
558556
}
559557

0 commit comments

Comments
 (0)