@@ -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 }
0 commit comments