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