Пример #1
0
        CodeAction CreateFromExpression(RefactoringContext context, Expression expression)
        {
            var resolveResult = context.Resolve(expression);

            if (resolveResult.IsError)
            {
                return(null);
            }

            return(new CodeAction(context.TranslateString("Extract method"), script => {
                string methodName = "NewMethod";
                var method = new MethodDeclaration {
                    ReturnType = context.CreateShortType(resolveResult.Type),
                    Name = methodName,
                    Body = new BlockStatement {
                        new ReturnStatement(expression.Clone())
                    }
                };
                if (!StaticVisitor.UsesNotStaticMember(context, expression))
                {
                    method.Modifiers |= Modifiers.Static;
                }

                var usedVariables = VariableLookupVisitor.Analyze(context, expression);

                var inExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);

                usedVariables.Sort((l, r) => l.Region.Begin.CompareTo(r.Region.Begin));
                var target = new IdentifierExpression(methodName);
                var invocation = new InvocationExpression(target);
                foreach (var variable in usedVariables)
                {
                    Expression argumentExpression = new IdentifierExpression(variable.Name);

                    var mod = ParameterModifier.None;
                    if (inExtractedRegion.GetStatus(variable) == VariableState.Changed)
                    {
                        mod = ParameterModifier.Ref;
                        argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
                    }

                    method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(variable.Type), variable.Name, mod));
                    invocation.Arguments.Add(argumentExpression);
                }

                script
                .InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method)
                .ContinueScript(delegate {
                    script.Replace(expression, invocation);
                    script.Link(target, method.NameToken);
                });
            }, expression));
        }
        CodeAction CreateFromStatements(RefactoringContext context, List <Statement> statements)
        {
            if (!(statements [0].Parent is Statement))
            {
                return(null);
            }

            return(new CodeAction(context.TranslateString("Extract method"), script => {
                string methodName = "NewMethod";
                var method = new MethodDeclaration()
                {
                    ReturnType = new PrimitiveType("void"),
                    Name = methodName,
                    Body = new BlockStatement()
                };
                bool usesNonStaticMember = false;
                foreach (Statement node in statements)
                {
                    usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node);
                    method.Body.Add(node.Clone());
                }
                if (!usesNonStaticMember)
                {
                    method.Modifiers |= Modifiers.Static;
                }

                var target = new IdentifierExpression(methodName);
                var invocation = new InvocationExpression(target);

                var usedVariables = VariableLookupVisitor.Analyze(context, statements);

                var extractedCodeAnalysis = new DefiniteAssignmentAnalysis((Statement)statements [0].Parent, context.Resolver, context.CancellationToken);
                var lastStatement = statements [statements.Count - 1];
                extractedCodeAnalysis.SetAnalyzedRange(statements [0], lastStatement);
                var statusAfterMethod = new List <Tuple <IVariable, DefiniteAssignmentStatus> >();

                foreach (var variable in usedVariables)
                {
                    extractedCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
                    statusAfterMethod.Add(Tuple.Create(variable, extractedCodeAnalysis.GetStatusAfter(lastStatement)));
                }
                var stmt = statements [0].GetParent <BlockStatement>();
                while (stmt.GetParent <BlockStatement> () != null)
                {
                    stmt = stmt.GetParent <BlockStatement>();
                }

                var wholeCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
                var statusBeforeMethod = new Dictionary <IVariable, DefiniteAssignmentStatus>();
                foreach (var variable in usedVariables)
                {
                    wholeCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
                    statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
                }

                var afterCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
                var statusAtEnd = new Dictionary <IVariable, DefiniteAssignmentStatus>();
                afterCodeAnalysis.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);

                foreach (var variable in usedVariables)
                {
                    afterCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
                    statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
                }
                var beforeVisitor = new VariableLookupVisitor(context);
                beforeVisitor.SetAnalyzedRange(stmt, statements [0], true, false);
                stmt.AcceptVisitor(beforeVisitor);
                var afterVisitor = new VariableLookupVisitor(context);
                afterVisitor.SetAnalyzedRange(lastStatement, stmt, false, true);
                stmt.AcceptVisitor(afterVisitor);

                foreach (var status in statusAfterMethod)
                {
                    if (!beforeVisitor.UsedVariables.Contains(status.Item1) && !afterVisitor.UsedVariables.Contains(status.Item1))
                    {
                        continue;
                    }
                    Expression argumentExpression = new IdentifierExpression(status.Item1.Name);

                    ParameterModifier mod;
                    switch (status.Item2)
                    {
                    case DefiniteAssignmentStatus.AssignedAfterTrueExpression:
                    case DefiniteAssignmentStatus.AssignedAfterFalseExpression:
                    case DefiniteAssignmentStatus.PotentiallyAssigned:
                        mod = ParameterModifier.Ref;
                        argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
                        break;

                    case DefiniteAssignmentStatus.DefinitelyAssigned:
                        if (statusBeforeMethod [status.Item1] != DefiniteAssignmentStatus.PotentiallyAssigned)
                        {
                            goto case DefiniteAssignmentStatus.PotentiallyAssigned;
                        }
                        mod = ParameterModifier.Out;
                        argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
                        break;

//						case DefiniteAssignmentStatus.Unassigned:
                    default:
                        mod = ParameterModifier.None;
                        break;
                    }
                    method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod));
                    invocation.Arguments.Add(argumentExpression);
                }

                foreach (var node in statements.Skip(1))
                {
                    script.Remove(node);
                }
                script.Replace(statements [0], new ExpressionStatement(invocation));
                script.InsertWithCursor(context.TranslateString("Extract method"), method, Script.InsertPosition.Before);
                //script.Link(target, method.NameToken);
            }));
        }
Пример #3
0
        CodeAction CreateFromStatements(RefactoringContext context, List <AstNode> statements)
        {
            if (!(statements [0].Parent is Statement))
            {
                return(null);
            }

            return(new CodeAction(context.TranslateString("Extract method"), script => {
                string methodName = "NewMethod";
                var method = new MethodDeclaration()
                {
                    ReturnType = new PrimitiveType("void"),
                    Name = methodName,
                    Body = new BlockStatement()
                };
                bool usesNonStaticMember = false;
                foreach (var node in statements)
                {
                    usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node);
                    if (node is Statement)
                    {
                        method.Body.Add((Statement)node.Clone());
                    }
                    else
                    {
                        method.Body.AddChildUnsafe(node.Clone(), node.Role);
                    }
                }
                if (!usesNonStaticMember)
                {
                    method.Modifiers |= Modifiers.Static;
                }

                var target = new IdentifierExpression(methodName);
                var invocation = new InvocationExpression(target);

                var usedVariables = VariableLookupVisitor.Analyze(context, statements);

                var inExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);
                var lastStatement = statements [statements.Count - 1];

                var stmt = statements [0].GetParent <BlockStatement>();
                while (stmt.GetParent <BlockStatement> () != null)
                {
                    stmt = stmt.GetParent <BlockStatement>();
                }

                inExtractedRegion.SetAnalyzedRange(statements [0], lastStatement);
                stmt.AcceptVisitor(inExtractedRegion);

                var beforeExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);
                beforeExtractedRegion.SetAnalyzedRange(statements [0].Parent, statements [0], true, false);
                stmt.AcceptVisitor(beforeExtractedRegion);

                var afterExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);
                afterExtractedRegion.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);
                stmt.AcceptVisitor(afterExtractedRegion);
                usedVariables.Sort((l, r) => l.Region.Begin.CompareTo(r.Region.Begin));

                IVariable generatedReturnVariable = null;
                foreach (var variable in usedVariables)
                {
                    if ((variable is IParameter) || beforeExtractedRegion.Has(variable) || !afterExtractedRegion.Has(variable))
                    {
                        continue;
                    }
                    generatedReturnVariable = variable;
                    method.ReturnType = context.CreateShortType(variable.Type);
                    method.Body.Add(new ReturnStatement(new IdentifierExpression(variable.Name)));
                    break;
                }

                int parameterOutCount = 0;
                foreach (var variable in usedVariables)
                {
                    if (!(variable is IParameter) && !beforeExtractedRegion.Has(variable) && !afterExtractedRegion.Has(variable))
                    {
                        continue;
                    }
                    if (variable == generatedReturnVariable)
                    {
                        continue;
                    }
                    Expression argumentExpression = new IdentifierExpression(variable.Name);

                    ParameterModifier mod = ParameterModifier.None;
                    if (inExtractedRegion.GetStatus(variable) == VariableState.Changed)
                    {
                        if (beforeExtractedRegion.GetStatus(variable) == VariableState.None)
                        {
                            mod = ParameterModifier.Out;
                            argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
                            parameterOutCount++;
                        }
                        else
                        {
                            mod = ParameterModifier.Ref;
                            argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
                        }
                    }

                    method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(variable.Type), variable.Name, mod));
                    invocation.Arguments.Add(argumentExpression);
                }

                ParameterDeclaration parameterToTransform = null;
                bool transformParameterToReturn = method.ReturnType is PrimitiveType &&
                                                  ((PrimitiveType)method.ReturnType).Keyword == "void" &&
                                                  parameterOutCount == 1;
                if (transformParameterToReturn)
                {
                    parameterToTransform = method.Parameters.First(p => p.ParameterModifier == ParameterModifier.Out);
                    parameterToTransform.Remove();
                    var argumentExpression = invocation.Arguments.OfType <DirectionExpression>().First(a => a.FieldDirection == FieldDirection.Out);
                    argumentExpression.Remove();
                    method.ReturnType = parameterToTransform.Type.Clone();
                    var argumentDecl = new VariableDeclarationStatement(parameterToTransform.Type.Clone(), parameterToTransform.Name);
                    method.Body.InsertChildBefore(method.Body.First(), argumentDecl, BlockStatement.StatementRole);
                    method.Body.Add(new ReturnStatement(new IdentifierExpression(parameterToTransform.Name)));
                }

                script
                .InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method)
                .ContinueScript(delegate {
                    foreach (var node in statements.Skip(1))
                    {
                        if (node is NewLineNode)
                        {
                            continue;
                        }
                        script.Remove(node);
                    }
                    foreach (var variable in usedVariables)
                    {
                        if ((variable is IParameter) || beforeExtractedRegion.Has(variable) || !afterExtractedRegion.Has(variable))
                        {
                            continue;
                        }
                        if (variable == generatedReturnVariable)
                        {
                            continue;
                        }
                        script.InsertBefore(statements [0], new VariableDeclarationStatement(context.CreateShortType(variable.Type), variable.Name));
                    }
                    Statement invocationStatement;

                    if (generatedReturnVariable != null)
                    {
                        invocationStatement = new VariableDeclarationStatement(new SimpleType("var"), generatedReturnVariable.Name, invocation);
                    }
                    else if (transformParameterToReturn)
                    {
                        invocationStatement = new AssignmentExpression(new IdentifierExpression(parameterToTransform.Name), invocation);
                    }
                    else
                    {
                        invocationStatement = invocation;
                    }

                    script.Replace(statements [0], invocationStatement);


                    script.Link(target, method.NameToken);
                });
            }, statements.First().StartLocation, statements.Last().EndLocation));
        }
        CodeAction CreateFromStatements(RefactoringContext context, List <Statement> statements)
        {
            if (!(statements [0].Parent is Statement))
            {
                return(null);
            }

            return(new CodeAction(context.TranslateString("Extract method"), script =>
            {
                string methodName = "NewMethod";
                var method = new MethodDeclaration()
                {
                    ReturnType = new PrimitiveType("void"),
                    Name = methodName,
                    Body = new BlockStatement()
                };
                bool usesNonStaticMember = false;
                foreach (Statement node in statements)
                {
                    usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node);
                    method.Body.Add(node.Clone());
                }
                if (!usesNonStaticMember)
                {
                    method.Modifiers |= Modifiers.Static;
                }

                var target = new IdentifierExpression(methodName);
                var invocation = new InvocationExpression(target);

                var usedVariables = VariableLookupVisitor.Analyze(context, statements);

                var inExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);
                var lastStatement = statements [statements.Count - 1];

                var stmt = statements [0].GetParent <BlockStatement>();
                while (stmt.GetParent <BlockStatement> () != null)
                {
                    stmt = stmt.GetParent <BlockStatement>();
                }

                inExtractedRegion.SetAnalyzedRange(statements [0], lastStatement);
                stmt.AcceptVisitor(inExtractedRegion);

                var beforeExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);
                beforeExtractedRegion.SetAnalyzedRange(statements [0].Parent, statements [0], true, false);
                stmt.AcceptVisitor(beforeExtractedRegion);

                var afterExtractedRegion = new VariableUsageAnalyzation(context, usedVariables);
                afterExtractedRegion.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);
                stmt.AcceptVisitor(afterExtractedRegion);
                usedVariables.Sort((l, r) => l.Region.Begin.CompareTo(r.Region.Begin));

                IVariable generatedReturnVariable = null;
                foreach (var variable in usedVariables)
                {
                    if ((variable is IParameter) || beforeExtractedRegion.Has(variable) || !afterExtractedRegion.Has(variable))
                    {
                        continue;
                    }
                    generatedReturnVariable = variable;
                    method.ReturnType = context.CreateShortType(variable.Type);
                    method.Body.Add(new ReturnStatement(new IdentifierExpression(variable.Name)));
                    break;
                }

                foreach (var variable in usedVariables)
                {
                    if (!(variable is IParameter) && !beforeExtractedRegion.Has(variable) && !afterExtractedRegion.Has(variable))
                    {
                        continue;
                    }
                    if (variable == generatedReturnVariable)
                    {
                        continue;
                    }
                    Expression argumentExpression = new IdentifierExpression(variable.Name);

                    ParameterModifier mod = ParameterModifier.None;
                    if (inExtractedRegion.GetStatus(variable) == VariableState.Changed)
                    {
                        if (beforeExtractedRegion.GetStatus(variable) == VariableState.None)
                        {
                            mod = ParameterModifier.Out;
                            argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
                        }
                        else
                        {
                            mod = ParameterModifier.Ref;
                            argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
                        }
                    }

                    method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(variable.Type), variable.Name, mod));
                    invocation.Arguments.Add(argumentExpression);
                }
                var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
                Action <Task> replaceStatements = delegate {
                    foreach (var node in statements.Skip(1))
                    {
                        script.Remove(node);
                    }
                    foreach (var variable in usedVariables)
                    {
                        if ((variable is IParameter) || beforeExtractedRegion.Has(variable) || !afterExtractedRegion.Has(variable))
                        {
                            continue;
                        }
                        if (variable == generatedReturnVariable)
                        {
                            continue;
                        }
                        script.InsertBefore(statements [0], new VariableDeclarationStatement(context.CreateShortType(variable.Type), variable.Name));
                    }
                    AstNode invocationStatement;

                    if (generatedReturnVariable != null)
                    {
                        invocationStatement = new VariableDeclarationStatement(new SimpleType("var"), generatedReturnVariable.Name, invocation);
                    }
                    else
                    {
                        invocationStatement = new ExpressionStatement(invocation);
                    }
                    script.Replace(statements [0], invocationStatement);


                    script.Link(target, method.NameToken);
                };

                if (task.IsCompleted)
                {
                    replaceStatements(null);
                }
                else
                {
                    task.ContinueWith(replaceStatements, TaskScheduler.FromCurrentSynchronizationContext());
                }
            }));
        }