Exemplo n.º 1
0
        public void ResetDocumentBuffer()
        {
            var doc = new DocumentBuffer();

            doc.Reset(0, "");

            Assert.AreEqual("", doc.Text.ToString());

            doc.Update(new[] { new DocumentChangeSet(0, 1, new[] {
                    DocumentChange.Insert("text", SourceLocation.MinValue)
                }) });

            Assert.AreEqual("text", doc.Text.ToString());

            try {
                doc.Update(new[] { new DocumentChangeSet(1, 0, new[] {
                        DocumentChange.Delete(SourceLocation.MinValue, SourceLocation.MinValue.AddColumns(4))
                    }) });
                Assert.Fail("expected InvalidOperationException");
            } catch (InvalidOperationException) {
            }
            Assert.AreEqual("text", doc.Text.ToString());
            Assert.AreEqual(1, doc.Version);

            doc.Update(new[] { new DocumentChangeSet(1, 0, new[] {
                    new DocumentChange {
                        WholeBuffer = true
                    }
                }) });

            Assert.AreEqual("", doc.Text.ToString());
            Assert.AreEqual(0, doc.Version);
        }
Exemplo n.º 2
0
        public async Task MultiPartDocument()
        {
            var s = await CreateServer();

            var mod = await AddModule(s, "x = 1", "mod");

            var modP2 = new Uri(mod, "#2");
            var modP3 = new Uri(mod, "#3");

            await AssertCompletion(s, mod, new[] { "x" }, Enumerable.Empty <string>());

            Assert.AreEqual(Tuple.Create("y = 2", 1), await ApplyChange(s, modP2, DocumentChange.Insert("y = 2", SourceLocation.MinValue)));
            await s.WaitForCompleteAnalysisAsync();

            await AssertCompletion(s, modP2, new[] { "x", "y" }, Enumerable.Empty <string>());

            Assert.AreEqual(Tuple.Create("z = 3", 1), await ApplyChange(s, modP3, DocumentChange.Insert("z = 3", SourceLocation.MinValue)));
            await s.WaitForCompleteAnalysisAsync();

            await AssertCompletion(s, modP3, new[] { "x", "y", "z" }, Enumerable.Empty <string>());
            await AssertCompletion(s, mod, new[] { "x", "y", "z" }, Enumerable.Empty <string>());

            await ApplyChange(s, mod, DocumentChange.Delete(SourceLocation.MinValue, SourceLocation.MinValue.AddColumns(5)));

            await s.WaitForCompleteAnalysisAsync();

            await AssertCompletion(s, modP2, new[] { "y", "z" }, new[] { "x" });
            await AssertCompletion(s, modP3, new[] { "y", "z" }, new[] { "x" });
        }
        public async Task ApplyChanges()
        {
            var s = await CreateServer();

            var m = await AddModule(s, "", "mod");

            Assert.AreEqual(Tuple.Create("x", 1), await ApplyChange(s, m, DocumentChange.Insert("x", new SourceLocation(1, 1))));
            Assert.AreEqual(Tuple.Create("", 2), await ApplyChange(s, m, DocumentChange.Delete(new SourceLocation(1, 1), new SourceLocation(1, 2))));
            Assert.AreEqual(Tuple.Create("y", 3), await ApplyChange(s, m, DocumentChange.Insert("y", new SourceLocation(1, 1))));
        }
        public async Task UpdateDocumentBuffer()
        {
            var s = await CreateServer();

            var mod = await AddModule(s, "");

            Assert.AreEqual(Tuple.Create("test", 1), await ApplyChange(s, mod, DocumentChange.Insert("test", SourceLocation.MinValue)));
            Assert.AreEqual(Tuple.Create("", 0), await ApplyChange(s, mod, 1, 0, new DocumentChange {
                WholeBuffer = true
            }));
            Assert.AreEqual(Tuple.Create("test", 1), await ApplyChange(s, mod, DocumentChange.Insert("test", SourceLocation.MinValue)));
        }
Exemplo n.º 5
0
        public void BasicDocumentBuffer()
        {
            var doc = new DocumentBuffer();

            doc.Reset(0, @"def f(x):
    return

def g(y):
    return y * 2
");

            doc.Update(new DocumentChangeSet(0, 1, new[] {
                // We *should* batch adjacent insertions, but we should also
                // work fine even if we don't. Note that the insertion point
                // tracks backwards with previous insertions in the same version.
                // If each of these were in its own array, the location would
                // have to change for each.
                DocumentChange.Insert(")", new SourceLocation(2, 11)),
                DocumentChange.Insert("x", new SourceLocation(2, 11)),
                DocumentChange.Insert("(", new SourceLocation(2, 11)),
                DocumentChange.Insert("g", new SourceLocation(2, 11)),
                DocumentChange.Insert(" ", new SourceLocation(2, 11))
            }));

            doc.Text.Should().Contain("return g(x)");
            Assert.AreEqual(1, doc.Version);

            doc.Update(new[] {
                new DocumentChangeSet(1, 2, new [] {
                    DocumentChange.Delete(new SourceLocation(2, 14), new SourceLocation(2, 15))
                }),
                new DocumentChangeSet(2, 3, new [] {
                    DocumentChange.Insert("x * 2", new SourceLocation(2, 14))
                })
            });

            doc.Text.Should().Contain("return g(x * 2)");

            doc.Update(new DocumentChangeSet(3, 4, new[] {
                DocumentChange.Replace(new SourceLocation(2, 18), new SourceLocation(2, 19), "300")
            }));

            doc.Text.Should().Contain("return g(x * 300)");

            doc.Update(new DocumentChangeSet(4, 5, new[] {
                // Changes are out of order, but we should fix that automatically
                DocumentChange.Delete(new SourceLocation(2, 13), new SourceLocation(2, 22)),
                DocumentChange.Insert("#", new SourceLocation(2, 7))
            }));
            doc.Text.Should().Contain("re#turn g");
        }
        public void ResetDocumentBuffer()
        {
            var doc = new DocumentBuffer();

            doc.SetContent(string.Empty);
            Assert.AreEqual(string.Empty, doc.Text);

            doc.Update(new[] {
                DocumentChange.Insert("text", SourceLocation.MinValue)
            });

            Assert.AreEqual("text", doc.Text);
            Assert.AreEqual(1, doc.Version);
        }
        public void InsertTopToBottom()
        {
            var doc = new DocumentBuffer();

            doc.SetContent(@"linelinelineline");
            doc.Update(new[] {
                DocumentChange.Insert("\n", new SourceLocation(1, 1)),
                DocumentChange.Insert("1\n", new SourceLocation(2, 5)),
                DocumentChange.Insert("2\r", new SourceLocation(3, 5)),
                DocumentChange.Insert("3\r\n", new SourceLocation(4, 5)),
                DocumentChange.Insert("4\r\n", new SourceLocation(5, 5)),
            });
            Assert.AreEqual("\nline1\nline2\rline3\r\nline4\r\n", doc.Text);
        }
Exemplo n.º 8
0
        private void ReplaceLines(List <DocumentChange> edits, int startOldLine, int endOldLine, int startNewLine, int endNewLine)
        {
            int oldLineCount = endOldLine - startOldLine;
            int newLineCount = endNewLine - startNewLine;

            // replace one line at a time instead of all of the lines at once so that we preserve breakpoints
            int excessNewLineStart = startNewLine - startOldLine;

            for (int i = startOldLine; i < endOldLine && i < (endNewLine - startNewLine + startOldLine); i++)
            {
                edits.Add(
                    DocumentChange.Replace(
                        _oldLines[i].SourceExtent,
                        GetNewText(startNewLine + i - startOldLine)
                        )
                    );
                excessNewLineStart = startNewLine + i - startOldLine + 1;
            }

            if (oldLineCount > newLineCount)
            {
                // we end up w/ less lines, we need to delete some text
                edits.Add(
                    DocumentChange.Delete(new SourceSpan(
                                              _oldLines[endOldLine - (oldLineCount - newLineCount)].SourceStart,
                                              _oldLines[endOldLine - 1].SourceEndIncludingLineBreak
                                              ))
                    );
            }
            else if (oldLineCount < newLineCount)
            {
                // we end up w/ more lines, we need to insert some text
                edits.Add(
                    DocumentChange.Insert(
                        string.Join(
                            _newLine,
                            _newLines.Skip(excessNewLineStart).Take(endNewLine - excessNewLineStart).Select(x => GetNewText(x.LineNo))
                            ) + _newLine,
                        _oldLines[endOldLine - 1].SourceEndIncludingLineBreak
                        )
                    );
            }
        }
Exemplo n.º 9
0
        private DocumentChange Insert(int oldStart, int newStart, int newEnd)
        {
            var newSource  = _newLines[newStart].Source;
            var insertText = new StringBuilder();

            for (var i = newStart; i < newEnd; i++)
            {
                insertText
                .Append(newSource, _newLines[i].Info.Start, _newLines[i].Info.Length)
                .Append(_newLine);
            }

            insertText.Append(newSource, _newLines[newEnd].Info.Start, _newLines[newEnd].Info.Length);
            if (oldStart < _oldLines.Length)
            {
                insertText.Append(_newLine);
                return(DocumentChange.Insert(insertText.ToString(), _oldLines[oldStart].Info.SourceStart));
            }

            // If inserting after the last line, line break should be added before the inserted text
            insertText.Insert(0, _newLine);
            return(DocumentChange.Insert(insertText.ToString(), _oldLines[_oldLines.Length - 1].Info.SourceEndIncludingLineBreak));
        }
        public void InsertMultipleDisjoint()
        {
            var doc = new DocumentBuffer();

            doc.SetContent(@"
line
line
line
line
");
            doc.Update(new[] {
                DocumentChange.Insert("4", new SourceLocation(5, 5)),
                DocumentChange.Insert("3", new SourceLocation(4, 5)),
                DocumentChange.Insert("2", new SourceLocation(3, 5)),
                DocumentChange.Insert("1", new SourceLocation(2, 5)),
            });
            Assert.AreEqual(@"
line1
line2
line3
line4
", doc.Text);
        }
        public void ReplaceAllDocumentBuffer()
        {
            var doc = new DocumentBuffer();

            doc.SetContent(string.Empty);
            Assert.AreEqual(string.Empty, doc.Text);

            doc.Update(new[] {
                DocumentChange.ReplaceAll("text")
            });

            Assert.AreEqual("text", doc.Text);
            Assert.AreEqual(1, doc.Version);

            doc.Update(new[] {
                DocumentChange.ReplaceAll("abcdef")
            });

            Assert.AreEqual(@"abcdef", doc.Text);
            Assert.AreEqual(2, doc.Version);

            doc.Update(new[] {
                DocumentChange.Insert("text", SourceLocation.MinValue),
                DocumentChange.ReplaceAll("1234")
            });

            Assert.AreEqual(@"1234", doc.Text);
            Assert.AreEqual(3, doc.Version);

            doc.Update(new[] {
                DocumentChange.ReplaceAll("1234"),
                DocumentChange.Insert("text", SourceLocation.MinValue)
            });

            Assert.AreEqual(@"text1234", doc.Text);
            Assert.AreEqual(4, doc.Version);
        }
Exemplo n.º 12
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 = Strings.ExtractMethodInvalidTargetSelected
                });
            }

            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 = Strings.ExtractMethodInvalidExpressionSelected
                });
            }

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

            // check for things we cannot handle
            string failureReason;

            if (!IsValidExtraction(walker.Target, out failureReason))
            {
                return(new AP.ExtractMethodResponse()
                {
                    // Note: this returns the unformatted error
                    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.Count - 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();
            HashSet <PythonVariable> readByFollowingCodeBeforeInit = null;
            var parentNode = walker.Target.Parents[walker.Target.Parents.Count - 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 = Strings.ExtractMethodAssignsVariablesAndReturns
                });
            }

            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();

            var changes = new List <DocumentChange>();

            var callChange   = DocumentChange.Replace(walker.Target.StartIncludingIndentation, walker.Target.End, newMethod.Call);
            var methodChange = DocumentChange.Insert(newMethod.Method, walker.Target.InsertLocations[targetScope]);

            if (callChange.ReplacedSpan.Start < methodChange.ReplacedSpan.Start)
            {
                changes.Add(callChange);
                changes.Add(methodChange);
            }
            else
            {
                changes.Add(methodChange);
                changes.Add(callChange);
            }

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

            for (int i = 0; i < walker.Target.Parents.Count; 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.Select(AP.ChangeInfo.FromDocumentChange).ToArray(),
                methodBody = newMethod.Method,
                variables = outputCollector._inputVars.Select(x => x.Name).ToArray(),
                scopes = scopes.ToArray(),
                wasExpanded = expanded,
                startLine = walker.Target.StartIncludingIndentation.Line,
                startCol = walker.Target.StartIncludingIndentation.Column,
                endLine = walker.Target.End.Line,
                endCol = walker.Target.End.Column,
                version = version
            });
        }