internal AP.ChangeInfo[] RemoveImports() { ScopeStatement targetStmt = null; if (!_allScopes) { var enclosingNodeWalker = new EnclosingNodeWalker(_ast, _index, _index); _ast.Walk(enclosingNodeWalker); targetStmt = enclosingNodeWalker.Target.Parents[enclosingNodeWalker.Target.Parents.Length - 1]; } var walker = new ImportWalker(targetStmt); _ast.Walk(walker); List<AP.ChangeInfo> changes = new List<AnalysisProtocol.ChangeInfo>(); 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(changes, 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 + proceedingLength; changes.Add( new AP.ChangeInfo() { start = start, length = length, newText = "" } ); changes.Add( new AP.ChangeInfo() { start = span.Start.Index, length = 0, newText = newCode } ); } } return changes.ToArray(); }
private Response FormatCode(AP.FormatCodeRequest request) { var projectFile = _projectFiles[request.fileId] as IPythonProjectEntry; int version; string code; var ast = projectFile.GetVerbatimAstAndCode( Project.LanguageVersion, request.bufferId, out version, out code ); if (ast != null) { var walker = new EnclosingNodeWalker(ast, request.startIndex, request.endIndex); ast.Walk(walker); if (walker.Target == null || !walker.Target.IsValidSelection) { return new AP.FormatCodeResponse() { changes = new AnalysisProtocol.ChangeInfo[0] }; } var body = walker.Target.GetNode(ast); int whitspaceStart = walker.Target.StartIncludingIndentation; int start; if (request.startIndex <= walker.Target.StartIncludingLeadingWhiteSpace) { // we've selected the leading comments, format them too... start = walker.Target.StartIncludingLeadingWhiteSpace; } else { // the user didn't have any comments selected, don't reformat them body.SetLeadingWhiteSpace(ast, body.GetIndentationLevel(ast)); start = walker.Target.StartIncludingIndentation; } int length = walker.Target.End - start; if (walker.Target.End < code.Length) { if (code[walker.Target.End] == '\r') { length++; if (walker.Target.End + 1 < code.Length && code[walker.Target.End + 1] == '\n') { length++; } } else if (code[walker.Target.End] == '\n') { length++; } } var selectedCode = code.Substring(start, length); return new AP.FormatCodeResponse() { startIndex = start, endIndex = walker.Target.End, version = version, changes = selectedCode.ReplaceByLines( body.ToCodeString(ast, request.options), request.newLine ).Select( x => new AP.ChangeInfo() { start = x.start + start, length = x.length, newText = x.newText } ).ToArray() }; } return new AP.FormatCodeResponse() { startIndex = 0, endIndex = 0, version = -1, changes = Array.Empty<AP.ChangeInfo>() }; }
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 }; }