コード例 #1
0
        private static bool IsValidExtraction(IExtractMethodInput input, SelectionTarget target)
        {
            if (target.Parents[target.Parents.Length - 1] is ClassDefinition)
            {
                input.CannotExtract("Cannot extract statements from a class definition");
                return(false);
            }

            string invalidExtractMsg = target.InvalidExtractionMessage;

            if (invalidExtractMsg != null)
            {
                input.CannotExtract(invalidExtractMsg);
                return(false);
            }

            var breakContinueWalker = new ContinueBreakWalker();

            target.Walk(breakContinueWalker);
            if (breakContinueWalker.ContainsBreak)
            {
                input.CannotExtract("The selection contains a \"break\" statement, but not the enclosing loop");
                return(false);
            }
            else if (breakContinueWalker.ContainsContinue)
            {
                input.CannotExtract("The selection contains a \"continue\" statement, but not the enclosing loop");
                return(false);
            }

            var yieldWalker = new YieldWalker();

            target.Walk(yieldWalker);
            if (yieldWalker.ContainsYield)
            {
                input.CannotExtract("Cannot extract code containing \"yield\" expression");
                return(false);
            }

            var importStarWalker = new ImportStarWalker();

            target.Walk(importStarWalker);
            if (importStarWalker.ContainsImportStar)
            {
                input.CannotExtract("Cannot extract method containing from ... import * statement");
                return(false);
            }

            var returnWalker = new ReturnWalker();

            target.Walk(returnWalker);
            if (returnWalker.ContainsReturn && !returnWalker.Returns)
            {
                input.CannotExtract("When the selection contains a return statement, all code paths must be terminated by a return statement too.");
                return(false);
            }
            target.ContainsReturn = returnWalker.ContainsReturn;

            return(true);
        }
コード例 #2
0
ファイル: MethodExtractor.cs プロジェクト: zhangjinxing/PTVS
        public async Task <bool> ExtractMethod(IExtractMethodInput input)
        {
            var analyzer = _view.GetAnalyzerAtCaret(_serviceProvider);

            if (analyzer == null)
            {
                return(false);
            }

            var buffer      = _view.GetPythonBufferAtCaret();
            var snapshot    = buffer.CurrentSnapshot;
            var projectFile = _view.GetAnalysisAtCaret(_serviceProvider);

            if (projectFile == null)
            {
                return(false);
            }

            // extract once to validate the selection
            var extractInfo = await analyzer.ExtractMethodAsync(
                projectFile,
                buffer,
                _view,
                "method_name",
                null,
                null
                );

            if (extractInfo == null)
            {
                return(false);
            }

            var extract = extractInfo.Data;

            if (extract.cannotExtractMsg != null)
            {
                input.CannotExtract(extract.cannotExtractMsg);
                return(false);
            }

            if (extract.wasExpanded && !input.ShouldExpandSelection())
            {
                return(false);
            }

            if (extract.startIndex != null && extract.endIndex != null)
            {
                var selectionSpan = _view.BufferGraph.MapUpToBuffer(
                    new SnapshotSpan(
                        snapshot,
                        Span.FromBounds(extract.startIndex.Value, extract.endIndex.Value)
                        ),
                    SpanTrackingMode.EdgeInclusive,
                    _view.TextBuffer
                    );

                foreach (var span in selectionSpan)
                {
                    _view.Selection.Select(span, false);
                    break;
                }
            }

            var info = input.GetExtractionInfo(new ExtractedMethodCreator(analyzer, projectFile, _view, buffer, extract));

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

            // extract again to get the final result...
            extractInfo = await analyzer.ExtractMethodAsync(
                projectFile,
                buffer,
                _view,
                info.Name,
                info.Parameters,
                info.TargetScope?.Scope.id
                );

            if (extractInfo == null)
            {
                return(false);
            }

            VsProjectAnalyzer.ApplyChanges(
                extractInfo.Data.changes,
                buffer,
                extractInfo.GetTracker(extractInfo.Data.version)
                );

            return(true);
        }
コード例 #3
0
ファイル: MethodExtractor.cs プロジェクト: xyongy/PTVS
        public async Task <bool> ExtractMethod(IExtractMethodInput input)
        {
            var buffer = _view.GetPythonBufferAtCaret();
            var bi     = _services.GetBufferInfo(buffer);
            var entry  = bi?.AnalysisEntry;

            if (entry?.Analyzer == null)
            {
                return(false);
            }

            var snapshot = buffer.CurrentSnapshot;

            // extract once to validate the selection
            var extract = await entry.Analyzer.ExtractMethodAsync(
                bi,
                _view,
                "method_name",
                null,
                null
                );

            if (extract == null)
            {
                return(false);
            }

            if (extract.cannotExtractMsg != null)
            {
                input.CannotExtract(extract.cannotExtractMsg);
                return(false);
            }

            if (extract.wasExpanded && !input.ShouldExpandSelection())
            {
                return(false);
            }

            if (extract.startLine > 0 && extract.endLine > 0)
            {
                var selectionSpan = _view.BufferGraph.MapUpToBuffer(
                    new SourceSpan(
                        new SourceLocation(extract.startLine, extract.startCol),
                        new SourceLocation(extract.endLine, extract.endCol)
                        ).ToSnapshotSpan(snapshot),
                    SpanTrackingMode.EdgeInclusive,
                    _view.TextBuffer
                    );

                foreach (var span in selectionSpan)
                {
                    _view.Selection.Select(span, false);
                    break;
                }
            }

            var info = input.GetExtractionInfo(new ExtractedMethodCreator(bi, _view, extract));

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

            // extract again to get the final result...
            extract = await entry.Analyzer.ExtractMethodAsync(
                bi,
                _view,
                info.Name,
                info.Parameters,
                info.TargetScope?.Scope.id
                );

            if (extract == null)
            {
                return(false);
            }

            VsProjectAnalyzer.ApplyChanges(
                extract.changes,
                buffer,
                bi.LocationTracker,
                extract.version
                );

            return(true);
        }
コード例 #4
0
ファイル: MethodExtractor.cs プロジェクト: rkhjjs/VSGenero
        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);
        }
コード例 #5
0
ファイル: MethodExtractor.cs プロジェクト: wenh123/PTVS
        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;
        }
コード例 #6
0
ファイル: MethodExtractor.cs プロジェクト: wenh123/PTVS
        private static bool IsValidExtraction(IExtractMethodInput input, SelectionTarget target) {
            if (target.Parents[target.Parents.Length - 1] is ClassDefinition) {
                input.CannotExtract("Cannot extract statements from a class definition");
                return false;
            }

            string invalidExtractMsg = target.InvalidExtractionMessage;
            if (invalidExtractMsg != null) {
                input.CannotExtract(invalidExtractMsg);
                return false;
            }

            var breakContinueWalker = new ContinueBreakWalker();
            target.Walk(breakContinueWalker);
            if (breakContinueWalker.ContainsBreak) {
                input.CannotExtract("The selection contains a \"break\" statement, but not the enclosing loop");
                return false;
            } else if (breakContinueWalker.ContainsContinue) {
                input.CannotExtract("The selection contains a \"continue\" statement, but not the enclosing loop");
                return false;
            }

            var yieldWalker = new YieldWalker();
            target.Walk(yieldWalker);
            if (yieldWalker.ContainsYield) {
                input.CannotExtract("Cannot extract code containing \"yield\" expression");
                return false;
            }

            var importStarWalker = new ImportStarWalker();
            target.Walk(importStarWalker);
            if (importStarWalker.ContainsImportStar) {
                input.CannotExtract("Cannot extract method containing from ... import * statement");
                return false;
            }

            var returnWalker = new ReturnWalker();
            target.Walk(returnWalker);
            if (returnWalker.ContainsReturn && !returnWalker.Returns) {
                input.CannotExtract("When the selection contains a return statement, all code paths must be terminated by a return statement too.");
                return false;
            }
            target.ContainsReturn = returnWalker.ContainsReturn;

            return true;
        }
コード例 #7
0
        public async Task <bool> ExtractMethod(IExtractMethodInput input)
        {
            var analyzer    = _view.GetAnalyzer(_serviceProvider);
            var projectFile = _view.TextBuffer.GetAnalysisEntry();

            // extract once to validate the selection
            var extractInfo = await analyzer.ExtractMethodAsync(
                projectFile,
                _view.TextBuffer,
                _view,
                "method_name",
                null,
                null
                );

            if (extractInfo == null)
            {
                return(false);
            }

            var extract = extractInfo.Data;

            if (extract.cannotExtractMsg != null)
            {
                input.CannotExtract(extract.cannotExtractMsg);
                return(false);
            }

            if (extract.wasExpanded && !input.ShouldExpandSelection())
            {
                return(false);
            }

            if (extract.startIndex != null && extract.endIndex != null)
            {
                _view.Selection.Select(
                    new SnapshotSpan(
                        _view.TextBuffer.CurrentSnapshot,
                        Span.FromBounds(extract.startIndex.Value, extract.endIndex.Value)
                        ),
                    false
                    );
            }

            var info = input.GetExtractionInfo(new ExtractedMethodCreator(analyzer, projectFile, _view, extract));

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

            // extract again to get the final result...
            extractInfo = await analyzer.ExtractMethodAsync(
                projectFile,
                _view.TextBuffer,
                _view,
                info.Name,
                info.Parameters,
                info.TargetScope?.Scope.id
                );

            if (extractInfo == null)
            {
                return(false);
            }

            VsProjectAnalyzer.ApplyChanges(
                extractInfo.Data.changes,
                _view.TextBuffer,
                extractInfo.GetTracker(extractInfo.Data.version)
                );

            return(true);
        }
コード例 #8
0
ファイル: MethodExtractor.cs プロジェクト: jsschultz/PTVS
        public async Task<bool> ExtractMethod(IExtractMethodInput input) {
            var analyzer = _view.GetAnalyzerAtCaret(_serviceProvider);
            if (analyzer == null) {
                return false;
            }

            var buffer = _view.GetPythonBufferAtCaret();
            var snapshot = buffer.CurrentSnapshot;
            var projectFile = _view.GetAnalysisAtCaret(_serviceProvider);
            if (projectFile == null) {
                return false;
            }
            
            // extract once to validate the selection
            var extractInfo = await analyzer.ExtractMethodAsync(
                projectFile,
                buffer,
                _view,
                "method_name",
                null,
                null
            );
            if (extractInfo == null) {
                return false;
            }

            var extract = extractInfo.Data;
            if (extract.cannotExtractMsg != null) {
                input.CannotExtract(extract.cannotExtractMsg);
                return false;
            }

            if (extract.wasExpanded && !input.ShouldExpandSelection()) {
                return false;
            }

            if (extract.startIndex != null && extract.endIndex != null) {
                var selectionSpan = _view.BufferGraph.MapUpToBuffer(
                    new SnapshotSpan(
                        snapshot,
                        Span.FromBounds(extract.startIndex.Value, extract.endIndex.Value)
                    ),
                    SpanTrackingMode.EdgeInclusive,
                    _view.TextBuffer
                );

                foreach (var span in selectionSpan) {
                    _view.Selection.Select(span, false);
                    break;
                }
            }

            var info = input.GetExtractionInfo(new ExtractedMethodCreator(analyzer, projectFile, _view, buffer, extract));
            if (info == null) {
                // user cancelled extract method
                return false;
            }

            // extract again to get the final result...
            extractInfo = await analyzer.ExtractMethodAsync(
                projectFile,
                buffer,
                _view,
                info.Name,
                info.Parameters,
                info.TargetScope?.Scope.id
            );

            if (extractInfo == null) {
                return false;
            }

            VsProjectAnalyzer.ApplyChanges(
                extractInfo.Data.changes,
                buffer,
                extractInfo.GetTracker(extractInfo.Data.version)
            );

            return true;
        }