77using Microsoft . CodeAnalysis . Text ;
88using ICSharpCode . CodeConverter . Util . FromRoslyn ;
99using ICSharpCode . CodeConverter . VB ;
10+ using ComparisonKind = ICSharpCode . CodeConverter . CSharp . VisualBasicEqualityComparison . ComparisonKind ;
1011
1112namespace ICSharpCode . CodeConverter . CSharp ;
1213
@@ -744,7 +745,8 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
744745 var csSwitchExpr = await vbExpr . AcceptAsync < ExpressionSyntax > ( _expressionVisitor ) ;
745746 csSwitchExpr = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( vbExpr , csSwitchExpr ) ;
746747 var switchExprTypeInfo = _semanticModel . GetTypeInfo ( vbExpr ) ;
747- var isStringComparison = switchExprTypeInfo . ConvertedType ? . SpecialType == SpecialType . System_String || switchExprTypeInfo . ConvertedType ? . IsArrayOf ( SpecialType . System_Char ) == true ;
748+ var isObjectComparison = switchExprTypeInfo . ConvertedType . SpecialType == SpecialType . System_Object ;
749+ var isStringComparison = ! isObjectComparison && switchExprTypeInfo . ConvertedType ? . SpecialType == SpecialType . System_String || switchExprTypeInfo . ConvertedType ? . IsArrayOf ( SpecialType . System_Char ) == true ;
748750 var caseInsensitiveStringComparison = vbEquality . OptionCompareTextCaseInsensitive &&
749751 isStringComparison ;
750752 if ( isStringComparison ) {
@@ -772,32 +774,53 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
772774 var isBooleanCase = caseTypeInfo . Type ? . SpecialType == SpecialType . System_Boolean ;
773775 bool enumRelated = IsEnumOrNullableEnum ( switchExprTypeInfo . ConvertedType ) || IsEnumOrNullableEnum ( caseTypeInfo . Type ) ;
774776 bool convertingEnum = IsEnumOrNullableEnum ( switchExprTypeInfo . ConvertedType ) ^ IsEnumOrNullableEnum ( caseTypeInfo . Type ) ;
775- var csExpressionToUse = ! isBooleanCase && ( convertingEnum || ! enumRelated && correctTypeExpressionSyntax . IsConst ) ? correctTypeExpressionSyntax . Expr : originalExpressionSyntax ;
777+ var csExpressionToUse = ! isObjectComparison && ! isBooleanCase && ( convertingEnum || ! enumRelated && correctTypeExpressionSyntax . IsConst )
778+ ? correctTypeExpressionSyntax . Expr
779+ : originalExpressionSyntax ;
776780
777- var caseSwitchLabelSyntax = ! wrapForStringComparison && correctTypeExpressionSyntax . IsConst && notAlreadyUsed
781+ var caseSwitchLabelSyntax = ! isObjectComparison && ! wrapForStringComparison && correctTypeExpressionSyntax . IsConst && notAlreadyUsed
778782 ? ( SwitchLabelSyntax ) SyntaxFactory . CaseSwitchLabel ( csExpressionToUse )
779783 : WrapInCasePatternSwitchLabelSyntax ( node , s . Value , csExpressionToUse , isBooleanCase ) ;
780784 labels . Add ( caseSwitchLabelSyntax ) ;
781785 } else if ( c is VBSyntax . ElseCaseClauseSyntax ) {
782786 labels . Add ( SyntaxFactory . DefaultSwitchLabel ( ) ) ;
783787 } else if ( c is VBSyntax . RelationalCaseClauseSyntax relational ) {
784788
785- var varName = CommonConversions . CsEscapedIdentifier ( GetUniqueVariableNameInScope ( node , "case" ) ) ;
786- ExpressionSyntax csLeft = ValidSyntaxFactory . IdentifierName ( varName ) ;
787789 var operatorKind = VBasic . VisualBasicExtensions . Kind ( relational ) ;
788790 var csRelationalValue = await relational . Value . AcceptAsync < ExpressionSyntax > ( _expressionVisitor ) ;
789- csRelationalValue = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( relational . Value , csRelationalValue ) ;
790- var binaryExp = SyntaxFactory . BinaryExpression ( operatorKind . ConvertToken ( ) , csLeft , csRelationalValue ) ;
791- labels . Add ( VarWhen ( varName , binaryExp ) ) ;
791+ CasePatternSwitchLabelSyntax caseSwitchLabelSyntax ;
792+ if ( isObjectComparison ) {
793+ caseSwitchLabelSyntax = WrapInCasePatternSwitchLabelSyntax ( node , relational . Value , csRelationalValue , false , operatorKind ) ;
794+ }
795+ else {
796+ var varName = CommonConversions . CsEscapedIdentifier ( GetUniqueVariableNameInScope ( node , "case" ) ) ;
797+ ExpressionSyntax csLeft = ValidSyntaxFactory . IdentifierName ( varName ) ;
798+ csRelationalValue = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( relational . Value , csRelationalValue ) ;
799+ var binaryExp = SyntaxFactory . BinaryExpression ( operatorKind . ConvertToken ( ) , csLeft , csRelationalValue ) ;
800+ caseSwitchLabelSyntax = VarWhen ( varName , binaryExp ) ;
801+ }
802+ labels . Add ( caseSwitchLabelSyntax ) ;
792803 } else if ( c is VBSyntax . RangeCaseClauseSyntax range ) {
793804 var varName = CommonConversions . CsEscapedIdentifier ( GetUniqueVariableNameInScope ( node , "case" ) ) ;
794- ExpressionSyntax csLeft = ValidSyntaxFactory . IdentifierName ( varName ) ;
805+ ExpressionSyntax csCaseVar = ValidSyntaxFactory . IdentifierName ( varName ) ;
795806 var lowerBound = await range . LowerBound . AcceptAsync < ExpressionSyntax > ( _expressionVisitor ) ;
796- lowerBound = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( range . LowerBound , lowerBound ) ;
797- var lowerBoundCheck = SyntaxFactory . BinaryExpression ( SyntaxKind . LessThanOrEqualExpression , lowerBound , csLeft ) ;
807+ ExpressionSyntax lowerBoundCheck ;
808+ if ( isObjectComparison ) {
809+ var caseTypeInfo = _semanticModel . GetTypeInfo ( range . LowerBound ) ;
810+ lowerBoundCheck = ComparisonAdjustedForStringComparison ( node , range . LowerBound , caseTypeInfo , lowerBound , csCaseVar , switchExprTypeInfo , ComparisonKind . LessThanOrEqual ) ;
811+ } else {
812+ lowerBound = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( range . LowerBound , lowerBound ) ;
813+ lowerBoundCheck = SyntaxFactory . BinaryExpression ( SyntaxKind . LessThanOrEqualExpression , lowerBound , csCaseVar ) ;
814+ }
798815 var upperBound = await range . UpperBound . AcceptAsync < ExpressionSyntax > ( _expressionVisitor ) ;
799- upperBound = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( range . UpperBound , upperBound ) ;
800- var upperBoundCheck = SyntaxFactory . BinaryExpression ( SyntaxKind . LessThanOrEqualExpression , csLeft , upperBound ) ;
816+ ExpressionSyntax upperBoundCheck ;
817+ if ( isObjectComparison ) {
818+ var caseTypeInfo = _semanticModel . GetTypeInfo ( range . UpperBound ) ;
819+ upperBoundCheck = ComparisonAdjustedForStringComparison ( node , range . UpperBound , switchExprTypeInfo , csCaseVar , upperBound , caseTypeInfo , ComparisonKind . LessThanOrEqual ) ;
820+ } else {
821+ upperBound = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( range . UpperBound , upperBound ) ;
822+ upperBoundCheck = SyntaxFactory . BinaryExpression ( SyntaxKind . LessThanOrEqualExpression , csCaseVar , upperBound ) ;
823+ }
801824 var withinBounds = SyntaxFactory . BinaryExpression ( SyntaxKind . LogicalAndExpression , lowerBoundCheck , upperBoundCheck ) ;
802825 labels . Add ( VarWhen ( varName , withinBounds ) ) ;
803826 } else {
@@ -916,7 +939,7 @@ private async Task<bool> IsNeverMutatedAsync(VBSyntax.NameSyntax ns)
916939 return symbol . MatchesKind ( SymbolKind . Parameter , SymbolKind . Local ) && await CommonConversions . Document . Project . Solution . IsNeverWrittenAsync ( symbol , allowedLocation ) ;
917940 }
918941
919- private CasePatternSwitchLabelSyntax WrapInCasePatternSwitchLabelSyntax ( VBSyntax . SelectBlockSyntax node , VBSyntax . ExpressionSyntax vbCase , ExpressionSyntax expression , bool treatAsBoolean = false )
942+ private CasePatternSwitchLabelSyntax WrapInCasePatternSwitchLabelSyntax ( VBSyntax . SelectBlockSyntax node , VBSyntax . ExpressionSyntax vbCase , ExpressionSyntax expression , bool treatAsBoolean = false , VBasic . SyntaxKind caseClauseKind = VBasic . SyntaxKind . CaseEqualsClause )
920943 {
921944 var typeInfo = _semanticModel . GetTypeInfo ( node . SelectStatement . Expression ) ;
922945
@@ -930,28 +953,48 @@ private CasePatternSwitchLabelSyntax WrapInCasePatternSwitchLabelSyntax(VBSyntax
930953 patternMatch = ValidSyntaxFactory . VarPattern ( varName ) ;
931954 ExpressionSyntax csLeft = ValidSyntaxFactory . IdentifierName ( varName ) , csRight = expression ;
932955 var caseTypeInfo = _semanticModel . GetTypeInfo ( vbCase ) ;
933- expression = EqualsAdjustedForStringComparison ( node , vbCase , typeInfo , csLeft , csRight , caseTypeInfo ) ;
956+ expression = ComparisonAdjustedForStringComparison ( node , vbCase , typeInfo , csLeft , csRight , caseTypeInfo , GetComparisonKind ( caseClauseKind ) ) ;
934957 }
935958
936959 var colonToken = SyntaxFactory . Token ( SyntaxKind . ColonToken ) ;
937960 return SyntaxFactory . CasePatternSwitchLabel ( patternMatch , SyntaxFactory . WhenClause ( expression ) , colonToken ) ;
938961 }
939962
940- private ExpressionSyntax EqualsAdjustedForStringComparison ( VBSyntax . SelectBlockSyntax node , VBSyntax . ExpressionSyntax vbCase , TypeInfo lhsTypeInfo , ExpressionSyntax csLeft , ExpressionSyntax csRight , TypeInfo rhsTypeInfo )
963+ private ComparisonKind GetComparisonKind ( VBasic . SyntaxKind caseClauseKind ) => caseClauseKind switch {
964+ VBasic . SyntaxKind . CaseLessThanClause => ComparisonKind . LessThan ,
965+ VBasic . SyntaxKind . CaseLessThanOrEqualClause => ComparisonKind . LessThanOrEqual ,
966+ VBasic . SyntaxKind . CaseEqualsClause => ComparisonKind . Equals ,
967+ VBasic . SyntaxKind . CaseNotEqualsClause => ComparisonKind . NotEquals ,
968+ VBasic . SyntaxKind . CaseGreaterThanOrEqualClause => ComparisonKind . GreaterThanOrEqual ,
969+ VBasic . SyntaxKind . CaseGreaterThanClause => ComparisonKind . GreaterThan ,
970+ _ => throw new ArgumentOutOfRangeException ( nameof ( caseClauseKind ) , caseClauseKind , null )
971+ } ;
972+
973+ private ExpressionSyntax ComparisonAdjustedForStringComparison ( VBSyntax . SelectBlockSyntax node , VBSyntax . ExpressionSyntax vbCase , TypeInfo lhsTypeInfo , ExpressionSyntax csLeft , ExpressionSyntax csRight , TypeInfo rhsTypeInfo , ComparisonKind comparisonKind )
941974 {
942975 var vbEquality = CommonConversions . VisualBasicEqualityComparison ;
943976 switch ( _visualBasicEqualityComparison . GetObjectEqualityType ( lhsTypeInfo , rhsTypeInfo ) ) {
944977 case VisualBasicEqualityComparison . RequiredType . Object :
945- return vbEquality . GetFullExpressionForVbObjectComparison ( csLeft , csRight ) ;
978+ return vbEquality . GetFullExpressionForVbObjectComparison ( csLeft , csRight , comparisonKind ) ;
946979 case VisualBasicEqualityComparison . RequiredType . StringOnly :
947980 // We know lhs isn't null, because we always coalesce it in the switch expression
948981 ( csLeft , csRight ) = vbEquality
949982 . AdjustForVbStringComparison ( node . SelectStatement . Expression , csLeft , lhsTypeInfo , true , vbCase , csRight , rhsTypeInfo , false ) ;
950983 break ;
951984 }
952- return SyntaxFactory . BinaryExpression ( SyntaxKind . EqualsExpression , csLeft , csRight ) ;
985+ return SyntaxFactory . BinaryExpression ( GetSyntaxKind ( comparisonKind ) , csLeft , csRight ) ;
953986 }
954987
988+ private CS . SyntaxKind GetSyntaxKind ( ComparisonKind comparisonKind ) => comparisonKind switch {
989+ ComparisonKind . LessThan => CS . SyntaxKind . LessThanExpression ,
990+ ComparisonKind . LessThanOrEqual => CS . SyntaxKind . LessThanOrEqualExpression ,
991+ ComparisonKind . Equals => CS . SyntaxKind . EqualsExpression ,
992+ ComparisonKind . NotEquals => CS . SyntaxKind . NotEqualsExpression ,
993+ ComparisonKind . GreaterThanOrEqual => CS . SyntaxKind . GreaterThanOrEqualExpression ,
994+ ComparisonKind . GreaterThan => CS . SyntaxKind . GreaterThanExpression ,
995+ _ => throw new ArgumentOutOfRangeException ( nameof ( comparisonKind ) , comparisonKind , null )
996+ } ;
997+
955998 public override async Task < SyntaxList < StatementSyntax > > VisitWithBlock ( VBSyntax . WithBlockSyntax node )
956999 {
9571000 var ( lhsExpression , prefixDeclarations , _) = await GetExpressionWithoutSideEffectsAsync ( node . WithStatement . Expression , "withBlock" ) ;
0 commit comments