Ejemplo n.º 1
0
        public void FormatCode(SnapshotSpan span, bool selectResult)
        {
            var snapshot = _view.TextBuffer.CurrentSnapshot;

            var ast = _view.GetAnalyzer().ParseFile(snapshot);

            var walker = new EnclosingNodeWalker(ast, span.Start, span.End);
            ast.Walk(walker);

            if (!walker.Target.IsValidSelection) {
                return;
            }

            var body = walker.Target.GetNode(ast);

            ITrackingSpan selectionSpan = null;
            if (selectResult) {
                selectionSpan = _view.TextBuffer.CurrentSnapshot.CreateTrackingSpan(span.Span, SpanTrackingMode.EdgeInclusive);
            }

            _view.ReplaceByLines(
                body.ToCodeString(ast, _format),
                Span.FromBounds(walker.Target.Start, walker.Target.End)
            );

            if (selectResult) {
                _view.Selection.Select(selectionSpan.GetSpan(_view.TextBuffer.CurrentSnapshot), false);
            }
        }
Ejemplo n.º 2
0
        internal void RemoveImports()
        {
            ScopeStatement targetStmt = null;
            if (!_allScopes) {
                var enclosingNodeWalker = new EnclosingNodeWalker(_ast, _view.Caret.Position.BufferPosition, _view.Caret.Position.BufferPosition + 1);
                _ast.Walk(enclosingNodeWalker);
                targetStmt = enclosingNodeWalker.Target.Parents[enclosingNodeWalker.Target.Parents.Length - 1];
            }

            var walker = new ImportWalker(targetStmt);
            _ast.Walk(walker);

            using (var edit = _view.TextBuffer.CreateEdit()) {
                foreach (var removeInfo in walker.GetToRemove()) {
                    // see if we're removing some or all of the
                    //var node = removeInfo.Node;
                    var removing = removeInfo.ToRemove;
                    var removed = removeInfo.Statement;
                    UpdatedStatement updatedStatement = removed.InitialStatement;

                    int removeCount = 0;
                    for (int i = 0, curRemoveIndex = 0; i < removed.NameCount; i++) {
                        if (removed.IsRemoved(i, removing)) {
                            removeCount++;
                            updatedStatement = updatedStatement.RemoveName(_ast, curRemoveIndex);
                        } else {
                            curRemoveIndex++;
                        }
                    }

                    var span = removed.Node.GetSpan(_ast);
                    if (removeCount == removed.NameCount) {
                        removeInfo.SiblingCount.Value--;

                        DeleteStatement(edit, span, removeInfo.SiblingCount.Value == 0);
                    } else {
                        var newCode = updatedStatement.ToCodeString(_ast);

                        int proceedingLength = (removed.Node.GetLeadingWhiteSpace(_ast) ?? "").Length;
                        int start = span.Start.Index - proceedingLength;
                        int length = span.Length + removed.Node.GetTrailingWhitespace(_ast).Length + proceedingLength;

                        edit.Delete(start, length);
                        edit.Insert(span.Start.Index, newCode);
                    }
                }

                edit.Apply();
            }
        }
Ejemplo n.º 3
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);
            // 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.Start,
                        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<JVariable> readBeforeInit;
            if (parent.ScopeVariables != null) {
                var flowChecker = new FlowChecker(parent);

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

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

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

                readByFollowingCodeBeforeInit = checker.ReadBeforeInitializedVariables;
            }

            // discover any variables which are consumed and need to be available as outputs...
            var outputCollector = new OuterVariableWalker(_ast, walker.Target, varCollector, readBeforeInit, readByFollowingCodeBeforeInit);
            _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()
            );

            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;
        }