public override void VisitForVariableBlockSyntax(ForVariableBlockSyntax syntax) => this.Build(() => base.VisitForVariableBlockSyntax(syntax), children => { Debug.Assert(children.Length == 5); ILinkedDocument openParen = children[0]; ILinkedDocument itemVariable = children[1]; ILinkedDocument comma = children[2]; ILinkedDocument indexVariable = children[3]; ILinkedDocument closeParen = children[4]; return(Spread(Concat(openParen, itemVariable, comma), Concat(indexVariable, closeParen))); });
protected override SyntaxBase ReplaceForSyntax(ForSyntax syntax) { syntax = (ForSyntax)base.ReplaceForSyntax(syntax); // look for range(0, length(<variable>)) if (!IsLoopIteratorExpression(semanticModel, syntax.Expression, out var arrayVariable)) { return(syntax); } if (syntax.VariableSection is not LocalVariableSyntax indexVariable) { return(syntax); } var arraySymbol = semanticModel.GetSymbolInfo(arrayVariable); var arrayIndexSymbol = semanticModel.GetSymbolInfo(indexVariable); if (arraySymbol is null || arrayIndexSymbol is null) { return(syntax); } var arrayAccesses = new HashSet <ArrayAccessSyntax>(); var independentIndexAccesses = new HashSet <VariableAccessSyntax>(); CallbackVisitor.Visit(syntax, child => { if (child is ArrayAccessSyntax arrayAccess) { if (semanticModel.GetSymbolInfo(arrayAccess.BaseExpression) == arraySymbol && semanticModel.GetSymbolInfo(arrayAccess.IndexExpression) == arrayIndexSymbol) { arrayAccesses.Add(arrayAccess); // we don't want to count the VariableAccessSyntax under this particular node, // so return false to skip visiting children. return(false); } } if (child is VariableAccessSyntax variableAccess) { var accessSymbol = semanticModel.GetSymbolInfo(variableAccess); if (accessSymbol == arrayIndexSymbol) { independentIndexAccesses.Add(variableAccess); } } return(true); }); if (!arrayAccesses.Any()) { // nothing to really simplify here return(syntax); } var itemVarName = GetUniqueVariableNameForNewScope(syntax, "item"); var forBody = CallbackRewriter.Rewrite(syntax.Body, child => { if (arrayAccesses.Contains(child)) { return(new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(itemVarName))); } return(child); }); SyntaxBase forVariableBlockSyntax; if (independentIndexAccesses.Any()) { forVariableBlockSyntax = new ForVariableBlockSyntax( SyntaxFactory.LeftParenToken, new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(itemVarName)), SyntaxFactory.CommaToken, new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(arrayIndexSymbol.Name)), SyntaxFactory.RightParenToken); } else { forVariableBlockSyntax = new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(itemVarName)); } var forExpression = new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(arraySymbol.Name)); return(new ForSyntax( syntax.OpenSquare, syntax.ForKeyword, forVariableBlockSyntax, syntax.InKeyword, forExpression, syntax.Colon, forBody, syntax.CloseSquare)); }