@@ -502,27 +502,27 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
502502 var stmt = node . ForStatement ;
503503 VariableDeclarationSyntax declaration = null ;
504504 ExpressionSyntax id ;
505- var controlVarSymbol = _semanticModel . GetSymbolInfo ( stmt . ControlVariable ) . Symbol ;
506- var controlVarType = controlVarSymbol ? . GetSymbolType ( ) ;
505+ var controlVarSymbol = _semanticModel . GetSymbolInfo ( stmt . ControlVariable ) . Symbol ?? ( _semanticModel . GetOperation ( stmt . ControlVariable ) as IVariableDeclaratorOperation ) ? . Symbol ;
506+
507+ // If missing semantic info, the compiler just guesses object, let's try to improve on that guess:
508+ var controlVarType = controlVarSymbol ? . GetSymbolType ( ) . Yield ( ) . Concat (
509+ new SyntaxNode [ ] { stmt . ControlVariable , stmt . FromValue , stmt . ToValue , stmt . StepClause ? . StepValue }
510+ . Select ( exp => _semanticModel . GetTypeInfo ( exp ) . Type )
511+ ) . FirstOrDefault ( t => t != null && t . SpecialType != SpecialType . System_Object ) ;
507512 var startValue = await stmt . FromValue . AcceptAsync < ExpressionSyntax > ( _expressionVisitor ) ;
508513 startValue = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( stmt . FromValue , startValue ? . SkipIntoParens ( ) , forceTargetType : controlVarType ) ;
509514
510515 var initializers = new List < ExpressionSyntax > ( ) ;
511- if ( stmt . ControlVariable is VBSyntax . VariableDeclaratorSyntax ) {
512- var v = ( VBSyntax . VariableDeclaratorSyntax ) stmt . ControlVariable ;
516+ var controlVarTypeSyntax = CommonConversions . GetTypeSyntax ( controlVarType ) ;
517+ if ( stmt . ControlVariable is VBSyntax . VariableDeclaratorSyntax v ) {
513518 declaration = ( await SplitVariableDeclarationsAsync ( v ) ) . Variables . Single ( ) . Decl ;
514519 declaration = declaration . WithVariables ( SyntaxFactory . SingletonSeparatedList ( declaration . Variables [ 0 ] . WithInitializer ( SyntaxFactory . EqualsValueClause ( startValue ) ) ) ) ;
515520 id = SyntaxFactory . IdentifierName ( declaration . Variables [ 0 ] . Identifier ) ;
516521 } else {
517522 id = await stmt . ControlVariable . AcceptAsync < ExpressionSyntax > ( _expressionVisitor ) ;
518-
519- // If missing semantic info, the compiler just guesses object. In this branch there was no explicit type, so let's try to improve on that guess:
520- controlVarType = controlVarType . Yield ( )
521- . Concat ( new [ ] { stmt . FromValue , stmt . ToValue , stmt . StepClause ? . StepValue } . Select ( exp => _semanticModel . GetTypeInfo ( exp ) . Type ) )
522- . FirstOrDefault ( t => t != null && t . SpecialType != SpecialType . System_Object ) ;
523-
523+
524524 if ( controlVarSymbol != null && controlVarSymbol . DeclaringSyntaxReferences . Any ( r => r . Span . OverlapsWith ( stmt . ControlVariable . Span ) ) ) {
525- declaration = CommonConversions . CreateVariableDeclarationAndAssignment ( controlVarSymbol . Name , startValue , CommonConversions . GetTypeSyntax ( controlVarType ) ) ;
525+ declaration = CommonConversions . CreateVariableDeclarationAndAssignment ( controlVarSymbol . Name , startValue , controlVarTypeSyntax ) ;
526526 } else {
527527 startValue = SyntaxFactory . AssignmentExpression ( SyntaxKind . SimpleAssignmentExpression , id , startValue ) ;
528528 initializers . Add ( startValue ) ;
@@ -538,18 +538,19 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
538538 // If it could evaluate differently or has side effects, it must be extracted as a variable
539539 if ( ! _semanticModel . GetConstantValue ( stmt . ToValue ) . HasValue ) {
540540 var loopToVariableName = GetUniqueVariableNameInScope ( node , "loopTo" ) ;
541- var toValueType = _semanticModel . GetTypeInfo ( stmt . ToValue ) . ConvertedType ;
542541 var toVariableId = SyntaxFactory . IdentifierName ( loopToVariableName ) ;
543542
544- // If that variable has the same type as the loop variable, we can explicitly declare the type and it inline
545- if ( controlVarType ? . Equals ( toValueType ) == true && declaration != null ) {
546- var loopToAssignment = CommonConversions . CreateVariableDeclarator ( loopToVariableName , csToValue ) ;
547- declaration = declaration . AddVariables ( loopToAssignment ) . WithType ( CommonConversions . GetTypeSyntax ( controlVarType ) ) ;
548- } else {
543+ var loopToAssignment = CommonConversions . CreateVariableDeclarator ( loopToVariableName , csToValue ) ;
544+ if ( initializers . Any ( ) ) {
549545 var loopEndDeclaration = SyntaxFactory . LocalDeclarationStatement (
550546 CommonConversions . CreateVariableDeclarationAndAssignment ( loopToVariableName , csToValue ) ) ;
551547 // Does not do anything about porting newline trivia upwards to maintain spacing above the loop
552548 preLoopStatements . Add ( loopEndDeclaration ) ;
549+ } else {
550+ declaration = declaration == null
551+ ? SyntaxFactory . VariableDeclaration ( controlVarTypeSyntax ,
552+ SyntaxFactory . SingletonSeparatedList ( loopToAssignment ) )
553+ : declaration . AddVariables ( loopToAssignment ) . WithType ( controlVarTypeSyntax ) ;
553554 }
554555
555556 csToValue = toVariableId ;
0 commit comments