@@ -37,6 +37,7 @@ class NodesVisitor : VBasic.VisualBasicSyntaxVisitor<CSharpSyntaxNode>
3737 private static readonly Type ExtensionAttributeType = typeof ( ExtensionAttribute ) ;
3838 private readonly TypeConversionAnalyzer _typeConversionAnalyzer ;
3939 public CommentConvertingNodesVisitor TriviaConvertingVisitor { get ; }
40+ private bool _optionCompareText = false ;
4041
4142 private CommonConversions CommonConversions { get ; }
4243
@@ -106,6 +107,9 @@ public override CSharpSyntaxNode VisitCompilationUnit(VBSyntax.CompilationUnitSy
106107 var options = ( VBasic . VisualBasicCompilationOptions ) _semanticModel . Compilation . Options ;
107108 var importsClauses = options . GlobalImports . Select ( gi => gi . Clause ) . Concat ( node . Imports . SelectMany ( imp => imp . ImportsClauses ) ) . ToList ( ) ;
108109
110+ _optionCompareText = node . Options . Any ( x => x . NameKeyword . ValueText . Equals ( "Compare" , StringComparison . OrdinalIgnoreCase ) &&
111+ x . ValueKeyword . ValueText . Equals ( "Text" , StringComparison . OrdinalIgnoreCase ) ) ;
112+
109113 var attributes = SyntaxFactory . List ( node . Attributes . SelectMany ( a => a . AttributeLists ) . SelectMany ( ConvertAttribute ) ) ;
110114 var sourceAndConverted = node . Members . Select ( m => ( Source : m , Converted : ConvertMember ( m ) ) ) . ToReadOnlyCollection ( ) ;
111115 var convertedMembers = string . IsNullOrEmpty ( options . RootNamespace )
@@ -1675,10 +1679,11 @@ public override CSharpSyntaxNode VisitBinaryExpression(VBSyntax.BinaryExpression
16751679 var lhs = _typeConversionAnalyzer . AddExplicitConversion ( node . Left , ( ExpressionSyntax ) node . Left . Accept ( TriviaConvertingVisitor ) ) ;
16761680 var rhs = _typeConversionAnalyzer . AddExplicitConversion ( node . Right , ( ExpressionSyntax ) node . Right . Accept ( TriviaConvertingVisitor ) ) ;
16771681
1682+ var stringType = _semanticModel . Compilation . GetTypeByMetadataName ( "System.String" ) ;
1683+ var lhsTypeInfo = _semanticModel . GetTypeInfo ( node . Left ) ;
1684+ var rhsTypeInfo = _semanticModel . GetTypeInfo ( node . Right ) ;
1685+
16781686 if ( node . IsKind ( VBasic . SyntaxKind . ConcatenateExpression ) ) {
1679- var stringType = _semanticModel . Compilation . GetTypeByMetadataName ( "System.String" ) ;
1680- var lhsTypeInfo = _semanticModel . GetTypeInfo ( node . Left ) ;
1681- var rhsTypeInfo = _semanticModel . GetTypeInfo ( node . Right ) ;
16821687 if ( lhsTypeInfo . Type . SpecialType != SpecialType . System_String &&
16831688 lhsTypeInfo . ConvertedType . SpecialType != SpecialType . System_String &&
16841689 rhsTypeInfo . Type . SpecialType != SpecialType . System_String &&
@@ -1687,13 +1692,48 @@ public override CSharpSyntaxNode VisitBinaryExpression(VBSyntax.BinaryExpression
16871692 }
16881693 }
16891694
1695+ if ( node . IsKind ( VBasic . SyntaxKind . EqualsExpression , VBasic . SyntaxKind . NotEqualsExpression ) ) {
1696+ if ( lhsTypeInfo . ConvertedType ? . SpecialType == SpecialType . System_String &&
1697+ rhsTypeInfo . ConvertedType ? . SpecialType == SpecialType . System_String ) {
1698+ bool lhsEmpty = lhs is LiteralExpressionSyntax les &&
1699+ ( les . IsKind ( SyntaxKind . NullLiteralExpression ) ||
1700+ ( les . IsKind ( SyntaxKind . StringLiteralExpression ) && string . IsNullOrEmpty ( les . Token . ValueText ) ) ) ;
1701+ bool lhsLiteral = lhs is LiteralExpressionSyntax && lhs . IsKind ( SyntaxKind . StringLiteralExpression ) ;
1702+ bool rhsEmpty = rhs is LiteralExpressionSyntax res &&
1703+ ( res . IsKind ( SyntaxKind . NullLiteralExpression ) ||
1704+ ( res . IsKind ( SyntaxKind . StringLiteralExpression ) && string . IsNullOrEmpty ( res . Token . ValueText ) ) ) ;
1705+ bool rhsLiteral = rhs is LiteralExpressionSyntax && rhs . IsKind ( SyntaxKind . StringLiteralExpression ) ;
1706+
1707+ if ( lhsEmpty || rhsEmpty ) {
1708+ var arg = lhsEmpty ? rhs : lhs ;
1709+ var nullOrEmpty = SyntaxFactory . InvocationExpression (
1710+ SyntaxFactory . MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression , SyntaxFactory . IdentifierName ( "string" ) , SyntaxFactory . IdentifierName ( "IsNullOrEmpty" ) ) ,
1711+ SyntaxFactory . ArgumentList ( SyntaxFactory . SeparatedList ( new [ ] { SyntaxFactory . Argument ( arg ) } ) ) ) ;
1712+ return node . IsKind ( VBasic . SyntaxKind . EqualsExpression ) ? ( CSharpSyntaxNode ) nullOrEmpty : SyntaxFactory . PrefixUnaryExpression ( SyntaxKind . LogicalNotExpression , nullOrEmpty ) ;
1713+ } else if ( ! _optionCompareText && ( lhsLiteral || rhsLiteral ) ) {
1714+ // If either side is a literal, and we're in binary comparison mode, we can use normal comparison logic
1715+ } else {
1716+ _extraUsingDirectives . Add ( "Microsoft.VisualBasic.CompilerServices" ) ;
1717+ var textCompare = SyntaxFactory . Argument ( SyntaxFactory . NameColon ( "TextCompare" ) ,
1718+ default ( SyntaxToken ) ,
1719+ _optionCompareText ? SyntaxFactory . LiteralExpression ( SyntaxKind . TrueLiteralExpression ) : SyntaxFactory . LiteralExpression ( SyntaxKind . FalseLiteralExpression ) ) ;
1720+ var compareString = SyntaxFactory . InvocationExpression (
1721+ SyntaxFactory . MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression , SyntaxFactory . IdentifierName ( "Operators" ) , SyntaxFactory . IdentifierName ( "CompareString" ) ) ,
1722+ SyntaxFactory . ArgumentList ( SyntaxFactory . SeparatedList ( new [ ] { SyntaxFactory . Argument ( lhs ) , SyntaxFactory . Argument ( rhs ) , textCompare } ) ) ) ;
1723+ lhs = compareString ;
1724+ rhs = SyntaxFactory . LiteralExpression ( SyntaxKind . NumericLiteralExpression , SyntaxFactory . Literal ( 0 ) ) ;
1725+ }
1726+ }
1727+ }
1728+
16901729 if ( node . IsKind ( VBasic . SyntaxKind . ExponentiateExpression ,
16911730 VBasic . SyntaxKind . ExponentiateAssignmentStatement ) ) {
16921731 return SyntaxFactory . InvocationExpression (
16931732 SyntaxFactory . ParseExpression ( $ "{ nameof ( Math ) } .{ nameof ( Math . Pow ) } ") ,
16941733 ExpressionSyntaxExtensions . CreateArgList ( lhs , rhs ) ) ;
16951734 }
16961735
1736+
16971737 var kind = VBasic . VisualBasicExtensions . Kind ( node ) . ConvertToken ( TokenContext . Local ) ;
16981738 var op = SyntaxFactory . Token ( CSharpUtil . GetExpressionOperatorTokenKind ( kind ) ) ;
16991739
0 commit comments