Chromium Code Reviews| Index: pkg/analysis_server/lib/src/edit/edit_domain.dart |
| diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart |
| index 260f67f6ed971bb69dab98b71c0c4da3d0137cfc..4e3c02634576efd814ab3b9e57f7f80546d2dece 100644 |
| --- a/pkg/analysis_server/lib/src/edit/edit_domain.dart |
| +++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart |
| @@ -26,8 +26,11 @@ import 'package:analyzer/src/generated/engine.dart' as engine; |
| import 'package:analyzer/src/generated/error.dart' as engine; |
| import 'package:analyzer/src/generated/parser.dart' as engine; |
| import 'package:analyzer/src/generated/source.dart'; |
| +import 'package:analyzer/task/dart.dart'; |
| import 'package:dart_style/dart_style.dart'; |
| +int test_resetCount = 0; |
| + |
| bool test_simulateRefactoringException_change = false; |
| bool test_simulateRefactoringException_final = false; |
| bool test_simulateRefactoringException_init = false; |
| @@ -376,7 +379,7 @@ class _RefactoringManager { |
| final AnalysisServer server; |
| final SearchEngine searchEngine; |
| - StreamSubscription onAnalysisStartedSubscription; |
| + StreamSubscription subscriptionToReset; |
| RefactoringKind kind; |
| String file; |
| @@ -392,7 +395,6 @@ class _RefactoringManager { |
| EditGetRefactoringResult result; |
| _RefactoringManager(this.server, this.searchEngine) { |
| - onAnalysisStartedSubscription = server.onAnalysisStarted.listen(_reset); |
| _reset(); |
| } |
| @@ -422,7 +424,8 @@ class _RefactoringManager { |
| * Cancels processing of the current request and cleans up. |
| */ |
| void cancel() { |
| - onAnalysisStartedSubscription.cancel(); |
| + subscriptionToReset?.cancel(); |
| + subscriptionToReset = null; |
| server.sendResponse(new Response.refactoringRequestCancelled(request)); |
| request = null; |
| } |
| @@ -492,6 +495,29 @@ class _RefactoringManager { |
| }); |
| } |
| + /** |
| + * Perform enough analysis to be able to perform refactoring of the given |
| + * [kind] in the given [file]. |
| + */ |
| + Future<Null> _analyzeForRefactoring(String file, RefactoringKind kind) async { |
| + // "Extract Local" and "Inline Local" refactorings need only local analysis. |
| + if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE || |
| + kind == RefactoringKind.INLINE_LOCAL_VARIABLE) { |
| + ContextSourcePair pair = server.getContextSourcePair(file); |
| + engine.AnalysisContext context = pair.context; |
| + Source source = pair.source; |
| + if (context != null && source != null) { |
| + if (context.computeResult(source, SOURCE_KIND) == SourceKind.LIBRARY) { |
| + await context.computeResolvedCompilationUnitAsync(source, source); |
| + return; |
| + } |
| + } |
| + } |
| + // A refactoring for which we cannot optimize analysis. |
| + // So, wait for full analysis. |
| + await server.onAnalysisComplete; |
| + } |
| + |
| void _checkForReset_afterCreateChange() { |
| if (test_simulateRefactoringReset_afterCreateChange) { |
| _reset(); |
| @@ -525,7 +551,7 @@ class _RefactoringManager { |
| */ |
| Future _init( |
| RefactoringKind kind, String file, int offset, int length) async { |
| - await server.onAnalysisComplete; |
| + await _analyzeForRefactoring(file, kind); |
| // check if we can continue with the existing Refactoring instance |
| if (this.kind == kind && |
| this.file == file && |
| @@ -548,6 +574,7 @@ class _RefactoringManager { |
| if (elements.isNotEmpty) { |
| Element element = elements[0]; |
| if (element is ExecutableElement) { |
| + _resetOnAnalysisStarted(); |
| refactoring = |
| new ConvertGetterToMethodRefactoring(searchEngine, element); |
| } |
| @@ -558,6 +585,7 @@ class _RefactoringManager { |
| if (elements.isNotEmpty) { |
| Element element = elements[0]; |
| if (element is ExecutableElement) { |
| + _resetOnAnalysisStarted(); |
| refactoring = |
| new ConvertMethodToGetterRefactoring(searchEngine, element); |
| } |
| @@ -566,6 +594,7 @@ class _RefactoringManager { |
| if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) { |
| List<CompilationUnit> units = server.getResolvedCompilationUnits(file); |
| if (units.isNotEmpty) { |
| + _resetOnFileResolutionChanged(file); |
| refactoring = new ExtractLocalRefactoring(units[0], offset, length); |
| feedback = new ExtractLocalVariableFeedback( |
| <String>[], <int>[], <int>[], |
| @@ -576,6 +605,7 @@ class _RefactoringManager { |
| if (kind == RefactoringKind.EXTRACT_METHOD) { |
| List<CompilationUnit> units = server.getResolvedCompilationUnits(file); |
| if (units.isNotEmpty) { |
| + _resetOnAnalysisStarted(); |
| refactoring = new ExtractMethodRefactoring( |
| searchEngine, units[0], offset, length); |
| feedback = new ExtractMethodFeedback(offset, length, '', <String>[], |
| @@ -585,6 +615,7 @@ class _RefactoringManager { |
| if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) { |
| List<CompilationUnit> units = server.getResolvedCompilationUnits(file); |
| if (units.isNotEmpty) { |
| + _resetOnFileResolutionChanged(file); |
| refactoring = |
| new InlineLocalRefactoring(searchEngine, units[0], offset); |
| } |
| @@ -592,11 +623,13 @@ class _RefactoringManager { |
| if (kind == RefactoringKind.INLINE_METHOD) { |
| List<CompilationUnit> units = server.getResolvedCompilationUnits(file); |
| if (units.isNotEmpty) { |
| + _resetOnAnalysisStarted(); |
| refactoring = |
| new InlineMethodRefactoring(searchEngine, units[0], offset); |
| } |
| } |
| if (kind == RefactoringKind.MOVE_FILE) { |
| + _resetOnAnalysisStarted(); |
| ContextSourcePair contextSource = server.getContextSourcePair(file); |
| engine.AnalysisContext context = contextSource.context; |
| Source source = contextSource.source; |
| @@ -619,6 +652,7 @@ class _RefactoringManager { |
| element = constructor.staticElement; |
| } |
| // do create the refactoring |
| + _resetOnAnalysisStarted(); |
| refactoring = new RenameRefactoring(searchEngine, element); |
| feedback = |
| new RenameFeedback(node.offset, node.length, 'kind', 'oldName'); |
| @@ -676,7 +710,8 @@ class _RefactoringManager { |
| } |
| } |
| - void _reset([engine.AnalysisContext context]) { |
| + void _reset() { |
| + test_resetCount++; |
| kind = null; |
| offset = null; |
| length = null; |
| @@ -685,6 +720,28 @@ class _RefactoringManager { |
| initStatus = new RefactoringStatus(); |
| optionsStatus = new RefactoringStatus(); |
| finalStatus = new RefactoringStatus(); |
| + subscriptionToReset?.cancel(); |
| + subscriptionToReset = null; |
| + } |
| + |
| + void _resetOnAnalysisStarted() { |
| + subscriptionToReset = server.onAnalysisStarted.listen((_) => _reset()); |
|
Brian Wilkerson
2016/08/22 23:32:23
Should we assert that `subscriptionToReset` is nul
scheglov
2016/08/23 01:55:28
Well, we need to at least cancel the current subsc
|
| + } |
| + |
| + /** |
| + * We're performing a refactoring that affects only the given [file]. |
| + * So, when the [file] resolution is changed, we need to reset refactoring. |
| + * But when any other file is changed or analyzer, we can continue. |
| + */ |
| + void _resetOnFileResolutionChanged(String file) { |
| + engine.AnalysisContext context = server.getAnalysisContext(file); |
| + subscriptionToReset = |
| + context?.onResultChanged(RESOLVED_UNIT)?.listen((event) { |
| + Source targetSource = event.target.source; |
| + if (targetSource?.fullName == file) { |
| + _reset(); |
| + } |
| + }); |
| } |
| void _sendResultResponse() { |