public SyntaxNode Replace(SyntaxNode root, SemanticModel model, Func <SyntaxNode, Tuple <SyntaxTree, SemanticModel> > updater, SharpSixRewriter rewriter) { var discards = root .DescendantNodes() .OfType <DiscardDesignationSyntax>(); var outVars = root .DescendantNodes() .OfType <ArgumentSyntax>() .Where(arg => arg.Expression is DeclarationExpressionSyntax && arg.RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword); var outDiscardVars = root .DescendantNodes() .OfType <ArgumentSyntax>() .Where(arg => { if (arg.Expression is IdentifierNameSyntax ins && ins.Identifier.ValueText == DISCARD_IDENTIFIER) { var si = model.GetSymbolInfo(arg.Expression); return(si.Symbol == null || si.Symbol is IDiscardSymbol); } return(false); }); var discardAssigments = root .DescendantNodes() .OfType <AssignmentExpressionSyntax>() .Where(assignment => { if (assignment.Left is IdentifierNameSyntax ins && ins.Identifier.ValueText == DISCARD_IDENTIFIER) { var si = model.GetSymbolInfo(assignment.Left); return(si.Symbol == null || si.Symbol is IDiscardSymbol); } return(false); }); var updatedMembers = new Dictionary <MemberAccessExpressionSyntax, string>(); foreach (var memberAccess in root.DescendantNodes().OfType <MemberAccessExpressionSyntax>()) { try { var symbol = model.GetSymbolInfo(memberAccess).Symbol; if (symbol != null && symbol is IFieldSymbol && symbol.ContainingType.IsTupleType) { var field = symbol as IFieldSymbol; var tupleField = field.CorrespondingTupleField; updatedMembers[memberAccess] = tupleField.Name; } } catch (Exception E) { Console.WriteLine(E); } } var updatedStatements = new Dictionary <StatementSyntax, List <LocalDeclarationStatementSyntax> >(); var updatedDiscards = new Dictionary <DiscardDesignationSyntax, string>(); var updatedDiscardVars = new Dictionary <ArgumentSyntax, string>(); var tempIndex = 0; foreach (var discard in discards) { try { var noLocal = false; var parentTuple = discard.GetParent <TupleExpressionSyntax>(); if (parentTuple != null && parentTuple.Parent is AssignmentExpressionSyntax ae && ae.Left == parentTuple) { noLocal = true; } var typeInfo = model.GetTypeInfo(discard.Parent); var beforeStatement = discard.Ancestors().OfType <StatementSyntax>().FirstOrDefault(); if (beforeStatement != null) { if (typeInfo.Type != null) { string instance = DISCARD_VARIABLE + ++tempIndex; if (beforeStatement.Parent != null) { var info = LocalUsageGatherer.GatherInfo(model, beforeStatement.Parent); while (info.DirectlyOrIndirectlyUsedLocals.Any(s => s.Name == instance) || info.Names.Contains(instance)) { instance = DISCARD_VARIABLE + ++tempIndex; } } if (!noLocal) { var locals = updatedStatements.ContainsKey(beforeStatement) ? updatedStatements[beforeStatement] : new List <LocalDeclarationStatementSyntax>(); var varDecl = SyntaxFactory.VariableDeclaration(SyntaxHelper.GenerateTypeSyntax(typeInfo.Type, model, discard.Parent.GetLocation().SourceSpan.Start, rewriter)).WithVariables(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(instance)) )); var local = SyntaxFactory.LocalDeclarationStatement(varDecl).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\n")); locals.Add(local); updatedStatements[beforeStatement] = locals; } updatedDiscards[discard] = instance; } else if (discard.Parent is DeclarationPatternSyntax && !(discard.Parent.Parent is IsPatternExpressionSyntax)) { string instance = DISCARD_VARIABLE + ++tempIndex; if (beforeStatement.Parent != null) { var info = LocalUsageGatherer.GatherInfo(model, beforeStatement.Parent); while (info.DirectlyOrIndirectlyUsedLocals.Any(s => s.Name == instance) || info.Names.Contains(instance)) { instance = DISCARD_VARIABLE + ++tempIndex; } } updatedDiscards[discard] = instance; } } } catch (Exception e) { throw new ReplacerException(discard, e); } } foreach (var discardVar in outDiscardVars) { try { var typeInfo = model.GetTypeInfo(discardVar.Expression); if (typeInfo.Type != null) { var beforeStatement = discardVar.Ancestors().OfType <StatementSyntax>().FirstOrDefault(); if (beforeStatement != null) { string instance = DISCARD_VARIABLE + ++tempIndex; if (beforeStatement.Parent != null) { var info = LocalUsageGatherer.GatherInfo(model, beforeStatement.Parent); while (info.DirectlyOrIndirectlyUsedLocals.Any(s => s.Name == instance) || info.Names.Contains(instance)) { instance = DISCARD_VARIABLE + ++tempIndex; } } var locals = updatedStatements.ContainsKey(beforeStatement) ? updatedStatements[beforeStatement] : new List <LocalDeclarationStatementSyntax>(); var varDecl = SyntaxFactory.VariableDeclaration(SyntaxHelper.GenerateTypeSyntax(typeInfo.Type, model, discardVar.Expression.GetLocation().SourceSpan.Start, rewriter)).WithVariables(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(instance)) )); var local = SyntaxFactory.LocalDeclarationStatement(varDecl).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\n")); locals.Add(local); updatedStatements[beforeStatement] = locals; updatedDiscardVars[discardVar] = instance; } } } catch (Exception e) { throw new ReplacerException(discardVar, e); } } foreach (var outVar in outVars) { try { if (((DeclarationExpressionSyntax)outVar.Expression).Designation.Kind() == SyntaxKind.DiscardDesignation) { continue; } var typeInfo = model.GetTypeInfo(outVar.Expression); if (typeInfo.Type != null) { var beforeStatement = outVar.Ancestors().OfType <StatementSyntax>().FirstOrDefault(); if (beforeStatement != null) { if (outVar.Expression is DeclarationExpressionSyntax de) { if (de.Designation is SingleVariableDesignationSyntax designation) { var locals = updatedStatements.ContainsKey(beforeStatement) ? updatedStatements[beforeStatement] : new List <LocalDeclarationStatementSyntax>(); var varDecl = SyntaxFactory.VariableDeclaration(SyntaxHelper.GenerateTypeSyntax(typeInfo.Type, model, outVar.Expression.GetLocation().SourceSpan.Start, rewriter)).WithVariables(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(designation.Identifier.ValueText)) )); locals.Add(SyntaxFactory.LocalDeclarationStatement(varDecl).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\n"))); updatedStatements[beforeStatement] = locals; } } } } } catch (Exception e) { throw new ReplacerException(outVar, e); } } var annotatedStatemnts = new Dictionary <SyntaxAnnotation, List <LocalDeclarationStatementSyntax> >(); var annotatedDiscards = new Dictionary <SyntaxAnnotation, string>(); var annotatedDiscardVars = new Dictionary <SyntaxAnnotation, string>(); var annotatedAssigments = new List <SyntaxAnnotation>(); var annotatedMembers = new Dictionary <SyntaxAnnotation, string>(); var keys = updatedStatements.Keys.Cast <SyntaxNode>() .Concat(updatedDiscards.Keys.Cast <SyntaxNode>()) .Concat(updatedDiscardVars.Keys.Cast <SyntaxNode>()) .Concat(discardAssigments) .Concat(updatedMembers.Keys.Cast <SyntaxNode>()); root = root.ReplaceNodes(keys, (n1, n2) => { var annotation = new SyntaxAnnotation(); if (n1 is AssignmentExpressionSyntax) { annotatedAssigments.Add(annotation); } else if (n1 is DiscardDesignationSyntax) { annotatedDiscards[annotation] = updatedDiscards[(DiscardDesignationSyntax)n1]; } else if (n1 is ArgumentSyntax) { annotatedDiscardVars[annotation] = updatedDiscardVars[(ArgumentSyntax)n1]; } else if (n1 is MemberAccessExpressionSyntax) { annotatedMembers[annotation] = updatedMembers[(MemberAccessExpressionSyntax)n1]; } else { annotatedStatemnts[annotation] = updatedStatements[(StatementSyntax)n1]; } n2 = n2.WithAdditionalAnnotations(annotation); return(n2); }); foreach (var annotation in annotatedDiscards.Keys) { var annotatedNode = root.GetAnnotatedNodes(annotation).First(); var name = annotatedDiscards[annotation]; root = root.ReplaceNode(annotatedNode, SyntaxFactory.SingleVariableDesignation(SyntaxFactory.Identifier(name)).NormalizeWhitespace()); } foreach (var annotation in annotatedDiscardVars.Keys) { var annotatedNode = root.GetAnnotatedNodes(annotation).First(); var name = annotatedDiscardVars[annotation]; root = root.ReplaceNode(annotatedNode, ((ArgumentSyntax)annotatedNode).WithExpression(SyntaxFactory.IdentifierName(name))); } foreach (var annotation in annotatedAssigments) { var annotatedNode = root.GetAnnotatedNodes(annotation).First(); root = root.ReplaceNode(annotatedNode, ((AssignmentExpressionSyntax)annotatedNode).WithLeft(SyntaxFactory.IdentifierName("H5.Script.Discard"))); } outVars = root .DescendantNodes() .OfType <ArgumentSyntax>() .Where(arg => arg.Expression is DeclarationExpressionSyntax && arg.RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword); root = root.ReplaceNodes(outVars, (n1, n2) => { if (!(((DeclarationExpressionSyntax)n2.Expression).Designation is SingleVariableDesignationSyntax designation)) { return(n2); } return(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(designation.Identifier)).WithRefKindKeyword(SyntaxFactory.Token(SyntaxKind.OutKeyword)).WithRefOrOutKeyword(SyntaxFactory.Token(SyntaxKind.OutKeyword)).NormalizeWhitespace()); });
public SyntaxNode InsertVariables(SyntaxNode root, SemanticModel model, SharpSixRewriter rewriter) { var tuples = root .DescendantNodes() .OfType <TupleExpressionSyntax>() .Where(e => e.Parent is AssignmentExpressionSyntax ae && ae.Left == e || e.Parent is ForEachVariableStatementSyntax fe && fe.Variable == e); var updatedStatements = new Dictionary <StatementSyntax, List <LocalDeclarationStatementSyntax> >(); foreach (var tuple in tuples) { try { var beforeStatement = tuple.Ancestors().OfType <StatementSyntax>().FirstOrDefault(); if (beforeStatement != null) { foreach (var arg in tuple.Arguments) { if (arg.Expression is DeclarationExpressionSyntax de) { if (de.Designation is SingleVariableDesignationSyntax designation) { var locals = updatedStatements.ContainsKey(beforeStatement) ? updatedStatements[beforeStatement] : new List <LocalDeclarationStatementSyntax>(); var typeInfo = model.GetTypeInfo(de).Type; var varDecl = SyntaxFactory.VariableDeclaration(SyntaxHelper.GenerateTypeSyntax(typeInfo, model, arg.Expression.GetLocation().SourceSpan.Start, rewriter)).WithVariables(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(designation.Identifier.ValueText)) )); locals.Add(SyntaxFactory.LocalDeclarationStatement(varDecl).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\n"))); updatedStatements[beforeStatement] = locals; } } } } } catch (Exception e) { throw new ReplacerException(tuple, e); } } var parenthesized = root .DescendantNodes() .OfType <ParenthesizedVariableDesignationSyntax>() .Where(e => e.Parent is DeclarationExpressionSyntax && e.Parent.Parent is AssignmentExpressionSyntax ae && ae.Left == e.Parent || e.Parent is DeclarationExpressionSyntax && e.Parent.Parent is ForEachVariableStatementSyntax fe && fe.Variable == e.Parent); foreach (var p in parenthesized) { try { var beforeStatement = p.Ancestors().OfType <StatementSyntax>().FirstOrDefault(); var declaration = (DeclarationExpressionSyntax)p.Parent; if (beforeStatement != null) { var typeInfo = model.GetTypeInfo(declaration).Type; List <TypeSyntax> types = new List <TypeSyntax>(); if (typeInfo.IsTupleType) { var elements = ((INamedTypeSymbol)typeInfo).TupleElements; foreach (var el in elements) { types.Add(SyntaxHelper.GenerateTypeSyntax(el.Type, model, declaration.GetLocation().SourceSpan.Start, rewriter)); } } else { continue; } int idx = 0; foreach (var v in p.Variables) { if (v is SingleVariableDesignationSyntax designation) { var locals = updatedStatements.ContainsKey(beforeStatement) ? updatedStatements[beforeStatement] : new List <LocalDeclarationStatementSyntax>(); var varDecl = SyntaxFactory.VariableDeclaration(types[idx++]).WithVariables(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(designation.Identifier.ValueText)) )); locals.Add(SyntaxFactory.LocalDeclarationStatement(varDecl).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\n"))); updatedStatements[beforeStatement] = locals; } } } } catch (Exception e) { throw new ReplacerException(p, e); } } var annotated = new Dictionary <SyntaxAnnotation, List <LocalDeclarationStatementSyntax> >(); root = root.ReplaceNodes(updatedStatements.Keys, (n1, n2) => { var annotation = new SyntaxAnnotation(); annotated[annotation] = updatedStatements[n1]; n2 = n2.WithAdditionalAnnotations(annotation); return(n2); }); foreach (var annotation in annotated.Keys) { var annotatedNode = root.GetAnnotatedNodes(annotation).First(); var varStatements = annotated[annotation]; if (annotatedNode is ForEachVariableStatementSyntax fe) { varStatements[varStatements.Count - 1] = varStatements.Last().WithAdditionalAnnotations(new SyntaxAnnotation("last_variable")); var list = new List <StatementSyntax>(varStatements); if (fe.Statement is BlockSyntax b) { list.AddRange(b.Statements); } else { list.Add(fe.Statement); } root = root.ReplaceNode(annotatedNode, fe.WithStatement(SyntaxFactory.Block(list)).NormalizeWhitespace()); } else if (annotatedNode.Parent is BlockSyntax || !(annotatedNode is StatementSyntax)) { root = root.InsertNodesBefore(annotatedNode, varStatements); } else { var list = new List <StatementSyntax>(varStatements); list.Add((StatementSyntax)annotatedNode); root = root.ReplaceNode(annotatedNode, SyntaxFactory.Block(list).NormalizeWhitespace()); } } return(root); }