public SyntaxNode ReplaceForeachDeconstructions(SyntaxNode root, SemanticModel model) { var loops = root .DescendantNodes() .OfType <ForEachVariableStatementSyntax>() .Where(forEach => forEach.Variable is TupleExpressionSyntax || forEach.Variable is DeclarationExpressionSyntax de && de.Designation is ParenthesizedVariableDesignationSyntax); if (loops.Any()) { Dictionary <ForEachVariableStatementSyntax, DeconstructionInfo> infos = new Dictionary <ForEachVariableStatementSyntax, DeconstructionInfo>(); foreach (var loop in loops) { try { var deconstructionInfo = model.GetDeconstructionInfo(loop); infos.Add(loop, deconstructionInfo); } catch (Exception e) { throw new ReplacerException(loop, e); } } var tempIndex = 0; root = root.ReplaceNodes(loops, (n1, n2) => { var variable = n2.Variable; string instance = "_d" + ++tempIndex; if (n1.Parent != null) { var info = LocalUsageGatherer.GatherInfo(model, n1.Parent); while (info.DirectlyOrIndirectlyUsedLocals.Any(s => s.Name == instance) || info.Names.Contains(instance)) { instance = "_d" + ++tempIndex; } } var newloop = SyntaxFactory.ForEachStatement(SyntaxFactory.IdentifierName("var"), SyntaxFactory.Identifier(instance), n2.Expression, n2.Statement) .WithLeadingTrivia(n2.GetLeadingTrivia()) .WithTrailingTrivia(n2.GetTrailingTrivia()); var deconstructionInfo = infos[n1]; var invocation = DeconstructionToMethod(variable, SyntaxFactory.IdentifierName(instance), deconstructionInfo); if (newloop.Statement is BlockSyntax b) { foreach (var statement in b.Statements) { try { if (statement.ContainsAnnotations) { var annotaions = statement.GetAnnotations("last_variable"); if (annotaions != null && annotaions.Any()) { newloop = newloop.InsertNodesAfter(statement, new[] { SyntaxFactory.ExpressionStatement(invocation) }); break; } } } catch (Exception e) { throw new ReplacerException(statement, e); } } } return(newloop.NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\n"))); }); } return(root); }
public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { bool needRewrite = false; List <InitializerInfo> initializerInfos = null; bool extensionMethodExists = false; bool isImplicitElementAccessSyntax = false; if (node.Initializer != null) { initializerInfos = new List <InitializerInfo>(); needRewrite = NeedRewriteInitializer(node.Initializer, initializerInfos, ref extensionMethodExists, ref isImplicitElementAccessSyntax); } node = (ObjectCreationExpressionSyntax)base.VisitObjectCreationExpression(node); if (needRewrite) { if (this.IsExpressionOfT) { if (isImplicitElementAccessSyntax) { var mapped = this.semanticModel.SyntaxTree.GetLineSpan(node.Span); throw new Exception(string.Format(CultureInfo.InvariantCulture, "{2} - {3}({0},{1}): {4}", mapped.StartLinePosition.Line + 1, mapped.StartLinePosition.Character + 1, "Index collection initializer is not supported inside Expression<T>", this.semanticModel.SyntaxTree.FilePath, node.ToString())); } if (extensionMethodExists) { var mapped = this.semanticModel.SyntaxTree.GetLineSpan(node.Span); throw new Exception(string.Format(CultureInfo.InvariantCulture, "{2} - {3}({0},{1}): {4}", mapped.StartLinePosition.Line + 1, mapped.StartLinePosition.Character + 1, "Extension method for collection initializer is not supported inside Expression<T>", this.semanticModel.SyntaxTree.FilePath, node.ToString())); } return(node); } var initializers = node.Initializer.Expressions; ExpressionSyntax[] args = new ExpressionSyntax[2]; var target = node.WithInitializer(null).WithoutTrivia(); if (target.ArgumentList == null) { target = target.WithArgumentList(SyntaxFactory.ArgumentList()); } args[0] = target; List <StatementSyntax> statements = new List <StatementSyntax>(); var parent = node.Parent; while (parent != null && !(parent is MethodDeclarationSyntax) && !(parent is ClassDeclarationSyntax)) { parent = parent.Parent; } string instance = "_o" + ++indexInstance; if (parent != null) { var info = LocalUsageGatherer.GatherInfo(this.semanticModel, parent); while (info.DirectlyOrIndirectlyUsedLocals.Any(s => s.Name == instance)) { instance = "_o" + ++indexInstance; } } SharpSixRewriter.ConvertInitializers(initializers, instance, statements, initializerInfos); statements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(instance).WithLeadingTrivia(SyntaxFactory.Space))); var body = SyntaxFactory.Block(statements); var lambda = SyntaxFactory.ParenthesizedLambdaExpression(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Parameter(SyntaxFactory.Identifier(instance)) })), body); args[1] = lambda; var methodIdentifier = SyntaxFactory.IdentifierName("Bridge.Script.CallFor"); var invocation = SyntaxFactory.InvocationExpression(methodIdentifier, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(args.Select(SyntaxFactory.Argument)))); return(invocation); } return(node); }
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.Kind == SymbolKind.Discard); } 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.Kind == SymbolKind.Discard); } return(false); }); var updatedMembers = new Dictionary <MemberAccessExpressionSyntax, string>(); foreach (var memberAccess in root.DescendantNodes().OfType <MemberAccessExpressionSyntax>()) { 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; } } 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 <VariableDeclaratorSyntax>( 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 <VariableDeclaratorSyntax>( 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) { var designation = de.Designation as SingleVariableDesignationSyntax; if (designation != null) { 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 <VariableDeclaratorSyntax>( 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("Bridge.Script.Discard"))); } outVars = root .DescendantNodes() .OfType <ArgumentSyntax>() .Where(arg => arg.Expression is DeclarationExpressionSyntax && arg.RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword); root = root.ReplaceNodes(outVars, (n1, n2) => { var designation = ((DeclarationExpressionSyntax)n2.Expression).Designation as SingleVariableDesignationSyntax; if (designation == null) { return(n2); } return(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(designation.Identifier)).WithRefKindKeyword(SyntaxFactory.Token(SyntaxKind.OutKeyword)).WithRefOrOutKeyword(SyntaxFactory.Token(SyntaxKind.OutKeyword)).NormalizeWhitespace()); }); foreach (var annotation in annotatedStatemnts.Keys) { var annotatedNode = root.GetAnnotatedNodes(annotation).First(); var varStatements = annotatedStatemnts[annotation]; 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()); } } var discardPatterns = root.DescendantNodes().OfType <IsPatternExpressionSyntax>().Where(pattern => pattern.Pattern is DeclarationPatternSyntax dp && dp.Designation.Kind() == SyntaxKind.DiscardDesignation); if (discardPatterns.Any()) { root = root.ReplaceNodes(discardPatterns, (n1, n2) => { return(SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression, SyntaxFactory.Token(SyntaxKind.TrueKeyword))); }); } foreach (var annotation in annotatedMembers.Keys) { var annotatedNode = root.GetAnnotatedNodes(annotation).First(); var name = annotatedMembers[annotation]; root = root.ReplaceNode(annotatedNode, ((MemberAccessExpressionSyntax)annotatedNode).WithName(SyntaxFactory.IdentifierName(name)).NormalizeWhitespace()); } return(root); }
public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { IMethodSymbol method = null; bool extensionMethodExists = false; if (node.Initializer != null) { foreach (var init in node.Initializer.Expressions) { var collectionInitializer = this.semanticModel.GetCollectionInitializerSymbolInfo(init).Symbol; var mInfo = collectionInitializer != null ? collectionInitializer as IMethodSymbol : null; if (mInfo != null) { if (mInfo.IsExtensionMethod) { extensionMethodExists = true; } method = mInfo; break; } } } node = (ObjectCreationExpressionSyntax)base.VisitObjectCreationExpression(node); bool isImplicitElementAccessSyntax = false; if (node.Initializer != null && (method != null || node.Initializer.Expressions.Any(init => { if (init.Kind() == SyntaxKind.SimpleAssignmentExpression) { var be = (AssignmentExpressionSyntax)init; if (be.Left is ImplicitElementAccessSyntax) { isImplicitElementAccessSyntax = true; return(true); } } return(false); }))) { if (this.IsExpressionOfT) { if (isImplicitElementAccessSyntax) { var mapped = this.semanticModel.SyntaxTree.GetLineSpan(node.Span); throw new Exception(string.Format(CultureInfo.InvariantCulture, "{2} - {3}({0},{1}): {4}", mapped.StartLinePosition.Line + 1, mapped.StartLinePosition.Character + 1, "Index collection initializer is not supported inside Expression<T>", this.semanticModel.SyntaxTree.FilePath, node.ToString())); } if (extensionMethodExists) { var mapped = this.semanticModel.SyntaxTree.GetLineSpan(node.Span); throw new Exception(string.Format(CultureInfo.InvariantCulture, "{2} - {3}({0},{1}): {4}", mapped.StartLinePosition.Line + 1, mapped.StartLinePosition.Character + 1, "Extension method for collection initializer is not supported inside Expression<T>", this.semanticModel.SyntaxTree.FilePath, node.ToString())); } return(node); } var initializers = node.Initializer.Expressions; ExpressionSyntax[] args = new ExpressionSyntax[2]; var target = node.WithInitializer(null).WithoutTrivia(); if (target.ArgumentList == null) { target = target.WithArgumentList(SyntaxFactory.ArgumentList()); } args[0] = target; List <StatementSyntax> statements = new List <StatementSyntax>(); var parent = node.Parent; while (parent != null && !(parent is MethodDeclarationSyntax) && !(parent is ClassDeclarationSyntax)) { parent = parent.Parent; } string instance = "_o" + ++indexInstance; if (parent != null) { var info = LocalUsageGatherer.GatherInfo(this.semanticModel, parent); while (info.DirectlyOrIndirectlyUsedLocals.Any(s => s.Name == instance)) { instance = "_o" + ++indexInstance; } } foreach (var init in initializers) { var collectionInitializer = this.semanticModel.GetCollectionInitializerSymbolInfo(init).Symbol; var mInfo = collectionInitializer != null ? collectionInitializer as IMethodSymbol : null; if (mInfo != null) { if (mInfo.IsStatic) { var ie = SyntaxHelper.GenerateStaticMethodCall(mInfo.Name, mInfo.ContainingType.FullyQualifiedName(), new[] { SyntaxFactory.Argument(SyntaxFactory.IdentifierName(instance)), SyntaxFactory.Argument(init.WithoutTrivia()) }, mInfo.TypeArguments.ToArray()); statements.Add(ie); } else { ArgumentSyntax[] arguments = null; if (init.Kind() == SyntaxKind.ComplexElementInitializerExpression) { var complexInit = (InitializerExpressionSyntax)init; arguments = new ArgumentSyntax[complexInit.Expressions.Count]; for (int i = 0; i < complexInit.Expressions.Count; i++) { arguments[i] = SyntaxFactory.Argument(complexInit.Expressions[i].WithoutTrivia()); } } else { arguments = new[] { SyntaxFactory.Argument(init.WithoutTrivia()) }; } var ie = SyntaxHelper.GenerateMethodCall(mInfo.Name, instance, arguments, mInfo.TypeArguments.ToArray()); statements.Add(ie); } } else { var be = (AssignmentExpressionSyntax)init; var indexerKeys = be.Left as ImplicitElementAccessSyntax; if (indexerKeys != null) { be = be.WithLeft(SyntaxFactory.ElementAccessExpression(SyntaxFactory.IdentifierName(instance), indexerKeys.ArgumentList.WithoutTrivia())); } else { var identifier = (IdentifierNameSyntax)be.Left; be = be.WithLeft(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(instance), SyntaxFactory.IdentifierName(identifier.Identifier.ValueText))); } be = be.WithRight(be.Right.WithoutTrivia()); be = be.WithoutTrivia(); statements.Add(SyntaxFactory.ExpressionStatement(be, SyntaxFactory.Token(SyntaxKind.SemicolonToken))); } } statements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(instance).WithLeadingTrivia(SyntaxFactory.Space))); var body = SyntaxFactory.Block(statements); var lambda = SyntaxFactory.ParenthesizedLambdaExpression(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Parameter(SyntaxFactory.Identifier(instance)) })), body); args[1] = lambda; var methodIdentifier = SyntaxFactory.IdentifierName("Bridge.Script.CallFor"); var invocation = SyntaxFactory.InvocationExpression(methodIdentifier, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(args.Select(SyntaxFactory.Argument)))); return(invocation); } return(node); }