Exemple #1
0
 public OuterVariableWalker(PythonAst root, SelectionTarget target, InnerVariableWalker inputCollector, HashSet <PythonVariable> readBeforeInitialized, HashSet <PythonVariable> readByFollowingCodeBeforeInit, HashSet <PythonVariable> outputVars)
 {
     _root                          = root;
     _target                        = target;
     _inputCollector                = inputCollector;
     _readBeforeInitialized         = readBeforeInitialized;
     _readByFollowingCodeBeforeInit = readByFollowingCodeBeforeInit;
     _outputVars                    = outputVars;
     _define                        = new DefineWalker(this);
 }
Exemple #2
0
 public DefineWalker(InnerVariableWalker collector)
 {
     _collector = collector;
 }
Exemple #3
0
        public AP.ExtractMethodResponse ExtractMethod(AP.ExtractMethodRequest input, int version)
        {
            // tighten up the selection so that we don't expand into any enclosing nodes because we overlap w/ their white space...
            var selectionStart = input.startIndex;

            while (selectionStart < _code.Length &&
                   Char.IsWhiteSpace(_code[selectionStart]))
            {
                selectionStart++;
            }

            var selectionEnd = input.endIndex;

            if (selectionEnd == _code.Length)
            {
                selectionEnd -= 1;
            }
            while (selectionEnd >= 0 && Char.IsWhiteSpace(_code[selectionEnd]))
            {
                selectionEnd -= 1;
            }

            var walker = new EnclosingNodeWalker(_ast, selectionStart, selectionEnd);

            _ast.Walk(walker);

            Debug.Assert(walker.Target != null);
            if (walker.Target == null)
            {
                return(new AP.ExtractMethodResponse()
                {
                    cannotExtractMsg = "Invalid target selected"
                });
            }

            bool expanded = false;

            // expand the selection if we aren't currently covering a full expression/statement
            if (!walker.Target.IsValidSelection)
            {
                return(new AP.ExtractMethodResponse()
                {
                    cannotExtractMsg = "Invalid expression selected"
                });
            }

            expanded = WasSelectionExpanded(walker.Target, selectionStart, selectionEnd);

            // check for things we cannot handle
            string failureReason;

            if (!IsValidExtraction(walker.Target, out failureReason))
            {
                return(new AP.ExtractMethodResponse()
                {
                    cannotExtractMsg = failureReason
                });
            }

            // get the variables which are read by the selected statement(s)
            var varCollector = new InnerVariableWalker(_ast);

            walker.Target.Walk(varCollector);

            // Walk the target to understand flow control and definite assignment to further understand
            // what we need to flow in.  For example if a variable is assigned to both in the un-extracted
            // and extracted code but it's definitely assigned in the extracted code then we don't need
            // to flow the variable in.

            // Run flow checker, first on any nested scopes...
            foreach (ScopeStatement scope in varCollector._scopes)
            {
                FlowChecker.Check(scope);
            }

            // then on our extracted code
            var parent = walker.Target.Parents[walker.Target.Parents.Length - 1];
            HashSet <PythonVariable> readBeforeInit;
            FlowChecker extractedChecker = null;

            if (parent.ScopeVariables != null)
            {
                extractedChecker = new FlowChecker(parent);

                walker.Target.Walk(extractedChecker);
                readBeforeInit = extractedChecker.ReadBeforeInitializedVariables;
            }
            else
            {
                readBeforeInit = new HashSet <PythonVariable>();
            }

            // then on code which follows our extracted body
            var afterStmts = walker.Target.GetStatementsAfter(_ast);
            HashSet <PythonVariable> readByFollowingCodeBeforeInit = null;
            var parentNode = walker.Target.Parents[walker.Target.Parents.Length - 1];
            var outputVars = new HashSet <PythonVariable>();

            if (parentNode.ScopeVariables != null)
            {
                var checker = new FlowChecker(parentNode);

                foreach (var afterStmt in afterStmts)
                {
                    afterStmt.Walk(checker);
                }

                readByFollowingCodeBeforeInit = checker.ReadBeforeInitializedVariables;

                foreach (var variable in varCollector._allWrittenVariables)
                {
                    if (variable != null && variable.Scope is PythonAst)
                    {
                        // global variable assigned to in outer scope, and left with
                        // a valid value (not deleted) from the extracted code.  We
                        // need to pass the value back out and assign to it in the
                        // global scope.
                        if (!checker.IsInitialized(variable) &&
                            extractedChecker.IsAssigned(variable))
                        {
                            outputVars.Add(variable);
                        }
                    }
                }
            }

            // collect any nested scopes, and see if they read any free variables
            var scopeCollector = new ScopeCollector();

            foreach (var afterStmt in afterStmts)
            {
                afterStmt.Walk(scopeCollector);
            }

            foreach (var scope in scopeCollector._scopes)
            {
                if (scope.FreeVariables != null)
                {
                    foreach (var freeVar in scope.FreeVariables)
                    {
                        if (varCollector._allWrittenVariables.Contains(freeVar))
                        {
                            // we've assigned to a variable accessed from an inner
                            // scope, we need to get the value of the variable back out.
                            outputVars.Add(freeVar);
                        }
                    }
                }
            }


            // discover any variables which are consumed and need to be available as outputs...
            var outputCollector = new OuterVariableWalker(_ast, walker.Target, varCollector, readBeforeInit, readByFollowingCodeBeforeInit, outputVars);

            _ast.Walk(outputCollector);

            if (outputCollector._outputVars.Count > 0 &&
                walker.Target.ContainsReturn)
            {
                return(new AP.ExtractMethodResponse()
                {
                    cannotExtractMsg = "Cannot extract method that assigns to variables and returns"
                });
            }

            var targetScope = walker.Target.Parents[input.scope ?? 0];
            var creator     = new OutOfProcExtractedMethodCreator(
                _ast,
                walker.Target.Parents,
                outputCollector._inputVars,
                outputCollector._outputVars,
                walker.Target,
                input.indentSize,
                !input.convertTabsToSpaces,
                input.newLine,
                input.name,
                input.parameters ?? new string[0],
                walker.Target.Parents[input.scope ?? 0]
                );

            // get the new method body...
            var newMethod = creator.GetExtractionResult();

            List <AP.ChangeInfo> changes = new List <AP.ChangeInfo>();

            changes.Add(
                new AP.ChangeInfo()
            {
                start   = walker.Target.StartIncludingIndentation,
                length  = walker.Target.End - walker.Target.StartIncludingIndentation,
                newText = ""
            }
                );

            changes.Add(
                new AP.ChangeInfo()
            {
                start   = walker.Target.InsertLocations[targetScope],
                newText = newMethod.Method
            }
                );

            changes.Add(
                new AP.ChangeInfo()
            {
                start   = walker.Target.StartIncludingIndentation,
                newText = newMethod.Call
            }
                );

            List <AP.ScopeInfo> scopes = new List <AP.ScopeInfo>();

            for (int i = 0; i < walker.Target.Parents.Length; i++)
            {
                var scope     = walker.Target.Parents[i];
                var scopeInfo = new AP.ScopeInfo()
                {
                    name      = scope.Name,
                    id        = i,
                    type      = GetScopeType(scope),
                    variables = GetScopeVariables(scope, outputCollector._inputVars)
                };
                scopes.Add(scopeInfo);
            }

            return(new AP.ExtractMethodResponse()
            {
                changes = changes.ToArray(),
                methodBody = newMethod.Method,
                variables = outputCollector._inputVars.Select(x => x.Name).ToArray(),
                scopes = scopes.ToArray(),
                wasExpanded = expanded,
                startIndex = walker.Target.StartIncludingIndentation,
                endIndex = walker.Target.End,
                version = version
            });
        }
Exemple #4
0
 public DefineWalker(InnerVariableWalker collector) {
     _collector = collector;
 }
Exemple #5
0
 public OuterVariableWalker(PythonAst root, SelectionTarget target, InnerVariableWalker inputCollector, HashSet<PythonVariable> readBeforeInitialized, HashSet<PythonVariable> readByFollowingCodeBeforeInit, HashSet<PythonVariable> outputVars) {
     _root = root;
     _target = target;
     _inputCollector = inputCollector;
     _readBeforeInitialized = readBeforeInitialized;
     _readByFollowingCodeBeforeInit = readByFollowingCodeBeforeInit;
     _outputVars = outputVars;
     _define = new DefineWalker(this);
 }
Exemple #6
0
        public bool ExtractMethod(IExtractMethodInput input) {
            // tighten up the selection so that we don't expand into any enclosing nodes because we overlap w/ their white space...
            var selectionStart = _view.Selection.Start.Position;
            while (selectionStart.Position < _view.TextBuffer.CurrentSnapshot.Length && Char.IsWhiteSpace(selectionStart.GetChar())) {
                selectionStart += 1;
            }

            var selectionEnd = _view.Selection.End.Position;
            if (selectionEnd.Position == _view.TextBuffer.CurrentSnapshot.Length) {
                selectionEnd -= 1;
            }
            while (selectionEnd.Position >= 0 && Char.IsWhiteSpace(selectionEnd.GetChar())) {
                selectionEnd -= 1;
            }

            var walker = new EnclosingNodeWalker(_ast, selectionStart, selectionEnd);
            _ast.Walk(walker);

            Debug.Assert(walker.Target != null);
            if (walker.Target == null) {
                return false;
            }
            // expand the selection if we aren't currently covering a full expression/statement
            if (!walker.Target.IsValidSelection ||
                (WasSelectionExpanded(walker.Target, selectionStart, selectionEnd) && !input.ShouldExpandSelection())) {
                return false;
            }

            _view.Selection.Select(
                new SnapshotSpan(
                    _view.TextBuffer.CurrentSnapshot,
                    Span.FromBounds(
                        walker.Target.StartIncludingIndentation,
                        walker.Target.End
                    )
                ),
                false
            );

            // check for things we cannot handle
            if (!IsValidExtraction(input, walker.Target)) {
                return false;
            }

            // get the variables which are read by the selected statement(s)
            var varCollector = new InnerVariableWalker(_ast);
            walker.Target.Walk(varCollector);

            // Walk the target to understand flow control and definite assignment to further understand
            // what we need to flow in.  For example if a variable is assigned to both in the un-extracted
            // and extracted code but it's definitely assigned in the extracted code then we don't need
            // to flow the variable in.

            // Run flow checker, first on any nested scopes...
            foreach (ScopeStatement scope in varCollector._scopes) {
                FlowChecker.Check(scope);
            }

            // then on our extracted code
            var parent = walker.Target.Parents[walker.Target.Parents.Length - 1];
            HashSet<PythonVariable> readBeforeInit;
            FlowChecker extractedChecker = null;
            if (parent.ScopeVariables != null) {
                extractedChecker = new FlowChecker(parent);

                walker.Target.Walk(extractedChecker);
                readBeforeInit = extractedChecker.ReadBeforeInitializedVariables;
            } else {
                readBeforeInit = new HashSet<PythonVariable>();
            }

            // then on code which follows our extracted body
            var afterStmts = walker.Target.GetStatementsAfter(_ast);
            HashSet<PythonVariable> readByFollowingCodeBeforeInit = null;
            var parentNode = walker.Target.Parents[walker.Target.Parents.Length - 1];
            var outputVars = new HashSet<PythonVariable>();
            if (parentNode.ScopeVariables != null) {
                var checker = new FlowChecker(parentNode);

                foreach (var afterStmt in afterStmts) {
                    afterStmt.Walk(checker);
                }

                readByFollowingCodeBeforeInit = checker.ReadBeforeInitializedVariables;

                foreach (var variable in varCollector._allWrittenVariables) {
                    if (variable != null && variable.Scope is PythonAst) {
                        // global variable assigned to in outer scope, and left with
                        // a valid value (not deleted) from the extracted code.  We
                        // need to pass the value back out and assign to it in the
                        // global scope.
                        if (!checker.IsInitialized(variable) &&
                            extractedChecker.IsAssigned(variable)) {
                            outputVars.Add(variable);
                        }
                    }
                }
            }

            // collect any nested scopes, and see if they read any free variables
            var scopeCollector = new ScopeCollector();
            foreach (var afterStmt in afterStmts) {
                afterStmt.Walk(scopeCollector);
            }

            foreach (var scope in scopeCollector._scopes) {
                if (scope.FreeVariables != null) {
                    foreach (var freeVar in scope.FreeVariables) {
                        if (varCollector._allWrittenVariables.Contains(freeVar)) {
                            // we've assigned to a variable accessed from an inner
                            // scope, we need to get the value of the variable back out.
                            outputVars.Add(freeVar);
                        }
                    }
                }
            }


            // discover any variables which are consumed and need to be available as outputs...
            var outputCollector = new OuterVariableWalker(_ast, walker.Target, varCollector, readBeforeInit, readByFollowingCodeBeforeInit, outputVars);
            _ast.Walk(outputCollector);

            if (outputCollector._outputVars.Count > 0 &&
                walker.Target.ContainsReturn) {
                input.CannotExtract("Cannot extract method that assigns to variables and returns");
                return false;
            }

            var creator = new ExtractedMethodCreator(
                _ast,
                walker.Target.Parents,
                outputCollector._inputVars,
                outputCollector._outputVars,
                walker.Target,
                _view.Options.GetIndentSize(),
                !_view.Options.IsConvertTabsToSpacesEnabled(),
                _view.Options.GetNewLineCharacter()
            );

            var info = input.GetExtractionInfo(creator);
            if (info == null) {
                // user cancelled extract method
                return false;
            }

            // get the new method body...
            var newMethod = creator.GetExtractionResult(info);

            // generate the call site.
            using (var edit = _view.TextBuffer.CreateEdit()) {
                // delete the selected code
                int start = _view.Selection.Start.Position;
                edit.Delete(Span.FromBounds(_view.Selection.Start.Position, _view.Selection.End.Position));

                // insert the newly generated method
                edit.Insert(walker.Target.InsertLocations[info.TargetScope], newMethod.Method);

                // insert the call to the new method
                edit.Insert(start, newMethod.Call);

                edit.Apply();
            }

            return true;
        }
        public AP.ExtractMethodResponse ExtractMethod(AP.ExtractMethodRequest input, int version) {
            // tighten up the selection so that we don't expand into any enclosing nodes because we overlap w/ their white space...
            var selectionStart = input.startIndex;
            while (selectionStart < _code.Length &&
                Char.IsWhiteSpace(_code[selectionStart])) {
                selectionStart++;
            }

            var selectionEnd = input.endIndex;
            if (selectionEnd == _code.Length) {
                selectionEnd -= 1;
            }
            while (selectionEnd >= 0 && Char.IsWhiteSpace(_code[selectionEnd])) {
                selectionEnd -= 1;
            }

            var walker = new EnclosingNodeWalker(_ast, selectionStart, selectionEnd);
            _ast.Walk(walker);

            Debug.Assert(walker.Target != null);
            if (walker.Target == null) {
                return new AP.ExtractMethodResponse() {
                    cannotExtractMsg = "Invalid target selected"
                };
            }

            bool expanded = false;
            // expand the selection if we aren't currently covering a full expression/statement
            if (!walker.Target.IsValidSelection) {
                return new AP.ExtractMethodResponse() {
                    cannotExtractMsg = "Invalid expression selected"
                };
            }

            expanded = WasSelectionExpanded(walker.Target, selectionStart, selectionEnd);

            // check for things we cannot handle
            string failureReason;
            if (!IsValidExtraction(walker.Target, out failureReason)) {
                return new AP.ExtractMethodResponse() {
                    cannotExtractMsg = failureReason
                };
            }

            // get the variables which are read by the selected statement(s)
            var varCollector = new InnerVariableWalker(_ast);
            walker.Target.Walk(varCollector);

            // Walk the target to understand flow control and definite assignment to further understand
            // what we need to flow in.  For example if a variable is assigned to both in the un-extracted
            // and extracted code but it's definitely assigned in the extracted code then we don't need
            // to flow the variable in.

            // Run flow checker, first on any nested scopes...
            foreach (ScopeStatement scope in varCollector._scopes) {
                FlowChecker.Check(scope);
            }

            // then on our extracted code
            var parent = walker.Target.Parents[walker.Target.Parents.Length - 1];
            HashSet<PythonVariable> readBeforeInit;
            FlowChecker extractedChecker = null;
            if (parent.ScopeVariables != null) {
                extractedChecker = new FlowChecker(parent);

                walker.Target.Walk(extractedChecker);
                readBeforeInit = extractedChecker.ReadBeforeInitializedVariables;
            } else {
                readBeforeInit = new HashSet<PythonVariable>();
            }

            // then on code which follows our extracted body
            var afterStmts = walker.Target.GetStatementsAfter(_ast);
            HashSet<PythonVariable> readByFollowingCodeBeforeInit = null;
            var parentNode = walker.Target.Parents[walker.Target.Parents.Length - 1];
            var outputVars = new HashSet<PythonVariable>();
            if (parentNode.ScopeVariables != null) {
                var checker = new FlowChecker(parentNode);

                foreach (var afterStmt in afterStmts) {
                    afterStmt.Walk(checker);
                }

                readByFollowingCodeBeforeInit = checker.ReadBeforeInitializedVariables;

                foreach (var variable in varCollector._allWrittenVariables) {
                    if (variable != null && variable.Scope is PythonAst) {
                        // global variable assigned to in outer scope, and left with
                        // a valid value (not deleted) from the extracted code.  We
                        // need to pass the value back out and assign to it in the
                        // global scope.
                        if (!checker.IsInitialized(variable) &&
                            extractedChecker.IsAssigned(variable)) {
                            outputVars.Add(variable);
                        }
                    }
                }
            }

            // collect any nested scopes, and see if they read any free variables
            var scopeCollector = new ScopeCollector();
            foreach (var afterStmt in afterStmts) {
                afterStmt.Walk(scopeCollector);
            }

            foreach (var scope in scopeCollector._scopes) {
                if (scope.FreeVariables != null) {
                    foreach (var freeVar in scope.FreeVariables) {
                        if (varCollector._allWrittenVariables.Contains(freeVar)) {
                            // we've assigned to a variable accessed from an inner
                            // scope, we need to get the value of the variable back out.
                            outputVars.Add(freeVar);
                        }
                    }
                }
            }


            // discover any variables which are consumed and need to be available as outputs...
            var outputCollector = new OuterVariableWalker(_ast, walker.Target, varCollector, readBeforeInit, readByFollowingCodeBeforeInit, outputVars);
            _ast.Walk(outputCollector);

            if (outputCollector._outputVars.Count > 0 &&
                walker.Target.ContainsReturn) {
                return new AP.ExtractMethodResponse() {
                    cannotExtractMsg = "Cannot extract method that assigns to variables and returns"
                };
            }

            var targetScope = walker.Target.Parents[input.scope ?? 0];
            var creator = new OutOfProcExtractedMethodCreator(
                _ast,
                walker.Target.Parents,
                outputCollector._inputVars,
                outputCollector._outputVars,
                walker.Target,
                input.indentSize,
                !input.convertTabsToSpaces,
                input.newLine,
                input.name,
                input.parameters ?? new string[0],
                walker.Target.Parents[input.scope ?? 0]
            );

            // get the new method body...
            var newMethod = creator.GetExtractionResult();

            List<AP.ChangeInfo> changes = new List<AP.ChangeInfo>();

            changes.Add(
                new AP.ChangeInfo() {
                    start = walker.Target.StartIncludingIndentation,
                    length = walker.Target.End - walker.Target.StartIncludingIndentation,
                    newText = ""
                }
            );

            changes.Add(
                new AP.ChangeInfo() {
                    start = walker.Target.InsertLocations[targetScope],
                    newText = newMethod.Method
                }
            );

            changes.Add(
                new AP.ChangeInfo() {
                    start = walker.Target.StartIncludingIndentation,
                    newText = newMethod.Call
                }
            );

            List<AP.ScopeInfo> scopes = new List<AP.ScopeInfo>();
            for(int i = 0; i<walker.Target.Parents.Length; i++) {
                var scope = walker.Target.Parents[i];
                var scopeInfo = new AP.ScopeInfo() {
                    name = scope.Name,
                    id = i,
                    type = GetScopeType(scope),
                    variables = GetScopeVariables(scope, outputCollector._inputVars)
                };
                scopes.Add(scopeInfo);
            }

            return new AP.ExtractMethodResponse() { 
                changes = changes.ToArray(),
                methodBody = newMethod.Method,
                variables = outputCollector._inputVars.Select(x => x.Name).ToArray(),
                scopes = scopes.ToArray(),
                wasExpanded = expanded,
                startIndex = walker.Target.StartIncludingIndentation,
                endIndex = walker.Target.End,
                version = version
            };
        }
Exemple #8
0
        public bool ExtractMethod(IExtractMethodInput input)
        {
            // tighten up the selection so that we don't expand into any enclosing nodes because we overlap w/ their white space...
            var selectionStart = _view.Selection.Start.Position;

            while (selectionStart.Position < _view.TextBuffer.CurrentSnapshot.Length && Char.IsWhiteSpace(selectionStart.GetChar()))
            {
                selectionStart += 1;
            }

            var selectionEnd = _view.Selection.End.Position;

            if (selectionEnd.Position == _view.TextBuffer.CurrentSnapshot.Length)
            {
                selectionEnd -= 1;
            }
            while (selectionEnd.Position >= 0 && Char.IsWhiteSpace(selectionEnd.GetChar()))
            {
                selectionEnd -= 1;
            }

            var walker = new EnclosingNodeWalker(_ast, selectionStart, selectionEnd);

            _ast.Walk(walker);

            Debug.Assert(walker.Target != null);
            if (walker.Target == null)
            {
                return(false);
            }
            // expand the selection if we aren't currently covering a full expression/statement
            if (!walker.Target.IsValidSelection ||
                (WasSelectionExpanded(walker.Target, selectionStart, selectionEnd) && !input.ShouldExpandSelection()))
            {
                return(false);
            }

            _view.Selection.Select(
                new SnapshotSpan(
                    _view.TextBuffer.CurrentSnapshot,
                    Span.FromBounds(
                        walker.Target.StartIncludingIndentation,
                        walker.Target.End
                        )
                    ),
                false
                );

            // check for things we cannot handle
            if (!IsValidExtraction(input, walker.Target))
            {
                return(false);
            }

            // get the variables which are read by the selected statement(s)
            var varCollector = new InnerVariableWalker(_ast);

            walker.Target.Walk(varCollector);

            // Walk the target to understand flow control and definite assignment to further understand
            // what we need to flow in.  For example if a variable is assigned to both in the un-extracted
            // and extracted code but it's definitely assigned in the extracted code then we don't need
            // to flow the variable in.

            // Run flow checker, first on any nested scopes...
            foreach (ScopeStatement scope in varCollector._scopes)
            {
                FlowChecker.Check(scope);
            }

            // then on our extracted code
            var parent = walker.Target.Parents[walker.Target.Parents.Length - 1];
            HashSet <PythonVariable> readBeforeInit;
            FlowChecker extractedChecker = null;

            if (parent.ScopeVariables != null)
            {
                extractedChecker = new FlowChecker(parent);

                walker.Target.Walk(extractedChecker);
                readBeforeInit = extractedChecker.ReadBeforeInitializedVariables;
            }
            else
            {
                readBeforeInit = new HashSet <PythonVariable>();
            }

            // then on code which follows our extracted body
            var afterStmts = walker.Target.GetStatementsAfter(_ast);
            HashSet <PythonVariable> readByFollowingCodeBeforeInit = null;
            var parentNode = walker.Target.Parents[walker.Target.Parents.Length - 1];
            var outputVars = new HashSet <PythonVariable>();

            if (parentNode.ScopeVariables != null)
            {
                var checker = new FlowChecker(parentNode);

                foreach (var afterStmt in afterStmts)
                {
                    afterStmt.Walk(checker);
                }

                readByFollowingCodeBeforeInit = checker.ReadBeforeInitializedVariables;

                foreach (var variable in varCollector._allWrittenVariables)
                {
                    if (variable != null && variable.Scope is PythonAst)
                    {
                        // global variable assigned to in outer scope, and left with
                        // a valid value (not deleted) from the extracted code.  We
                        // need to pass the value back out and assign to it in the
                        // global scope.
                        if (!checker.IsInitialized(variable) &&
                            extractedChecker.IsAssigned(variable))
                        {
                            outputVars.Add(variable);
                        }
                    }
                }
            }

            // collect any nested scopes, and see if they read any free variables
            var scopeCollector = new ScopeCollector();

            foreach (var afterStmt in afterStmts)
            {
                afterStmt.Walk(scopeCollector);
            }

            foreach (var scope in scopeCollector._scopes)
            {
                if (scope.FreeVariables != null)
                {
                    foreach (var freeVar in scope.FreeVariables)
                    {
                        if (varCollector._allWrittenVariables.Contains(freeVar))
                        {
                            // we've assigned to a variable accessed from an inner
                            // scope, we need to get the value of the variable back out.
                            outputVars.Add(freeVar);
                        }
                    }
                }
            }


            // discover any variables which are consumed and need to be available as outputs...
            var outputCollector = new OuterVariableWalker(_ast, walker.Target, varCollector, readBeforeInit, readByFollowingCodeBeforeInit, outputVars);

            _ast.Walk(outputCollector);

            if (outputCollector._outputVars.Count > 0 &&
                walker.Target.ContainsReturn)
            {
                input.CannotExtract("Cannot extract method that assigns to variables and returns");
                return(false);
            }

            var creator = new ExtractedMethodCreator(
                _ast,
                walker.Target.Parents,
                outputCollector._inputVars,
                outputCollector._outputVars,
                walker.Target,
                _view.Options.GetIndentSize(),
                !_view.Options.IsConvertTabsToSpacesEnabled(),
                _view.Options.GetNewLineCharacter()
                );

            var info = input.GetExtractionInfo(creator);

            if (info == null)
            {
                // user cancelled extract method
                return(false);
            }

            // get the new method body...
            var newMethod = creator.GetExtractionResult(info);

            // generate the call site.
            using (var edit = _view.TextBuffer.CreateEdit()) {
                // delete the selected code
                int start = _view.Selection.Start.Position;
                edit.Delete(Span.FromBounds(_view.Selection.Start.Position, _view.Selection.End.Position));

                // insert the newly generated method
                edit.Insert(walker.Target.InsertLocations[info.TargetScope], newMethod.Method);

                // insert the call to the new method
                edit.Insert(start, newMethod.Call);

                edit.Apply();
            }

            return(true);
        }