| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library services.src.refactoring; | 5 library services.src.refactoring; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:analysis_server/src/protocol_server.dart' hide Element; | 10 import 'package:analysis_server/src/protocol_server.dart' hide Element; |
| 11 import 'package:analysis_server/src/services/correction/status.dart'; | 11 import 'package:analysis_server/src/services/correction/status.dart'; |
| 12 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; | 12 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; |
| 13 import 'package:analysis_server/src/services/search/search_engine.dart'; | 13 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 14 import 'package:analyzer/dart/element/element.dart'; | 14 import 'package:analyzer/dart/element/element.dart'; |
| 15 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 15 import 'package:analyzer/src/generated/source.dart'; | 16 import 'package:analyzer/src/generated/source.dart'; |
| 16 | 17 |
| 17 /** | 18 /** |
| 19 * Return a new [SourceReference] instance for the given [match]. |
| 20 */ |
| 21 SourceReference getSourceReference(SearchMatch match) { |
| 22 return new SourceReference(match); |
| 23 } |
| 24 |
| 25 /** |
| 18 * When a [Source] (a file) is used in more than one context, [SearchEngine] | 26 * When a [Source] (a file) is used in more than one context, [SearchEngine] |
| 19 * will return separate [SearchMatch]s for each context. But in rename | 27 * will return separate [SearchMatch]s for each context. But in rename |
| 20 * refactorings we want to update each [Source] only once. | 28 * refactorings we want to update each [Source] only once. |
| 21 */ | 29 */ |
| 22 List<SourceReference> getSourceReferences(List<SearchMatch> matches) { | 30 List<SourceReference> getSourceReferences(List<SearchMatch> matches) { |
| 23 var uniqueReferences = new HashMap<SourceReference, SourceReference>(); | 31 var uniqueReferences = new HashMap<SourceReference, SourceReference>(); |
| 24 for (SearchMatch match in matches) { | 32 for (SearchMatch match in matches) { |
| 25 Element element = match.element; | 33 SourceReference newReference = getSourceReference(match); |
| 26 String file = element.source.fullName; | |
| 27 SourceRange range = match.sourceRange; | |
| 28 SourceReference newReference = new SourceReference( | |
| 29 file, range, element, match.isResolved, match.isQualified); | |
| 30 SourceReference oldReference = uniqueReferences[newReference]; | 34 SourceReference oldReference = uniqueReferences[newReference]; |
| 31 if (oldReference == null) { | 35 if (oldReference == null) { |
| 32 uniqueReferences[newReference] = newReference; | 36 uniqueReferences[newReference] = newReference; |
| 33 oldReference = newReference; | 37 oldReference = newReference; |
| 34 } | 38 } |
| 35 } | 39 } |
| 36 return uniqueReferences.keys.toList(); | 40 return uniqueReferences.keys.toList(); |
| 37 } | 41 } |
| 38 | 42 |
| 39 /** | 43 /** |
| 40 * Abstract implementation of [Refactoring]. | 44 * Abstract implementation of [Refactoring]. |
| 41 */ | 45 */ |
| 42 abstract class RefactoringImpl implements Refactoring { | 46 abstract class RefactoringImpl implements Refactoring { |
| 43 final List<String> potentialEditIds = <String>[]; | 47 final List<String> potentialEditIds = <String>[]; |
| 44 | 48 |
| 45 @override | 49 @override |
| 46 Future<RefactoringStatus> checkAllConditions() async { | 50 Future<RefactoringStatus> checkAllConditions() async { |
| 47 RefactoringStatus result = new RefactoringStatus(); | 51 RefactoringStatus result = new RefactoringStatus(); |
| 48 result.addStatus(await checkInitialConditions()); | 52 result.addStatus(await checkInitialConditions()); |
| 49 if (result.hasFatalError) { | 53 if (result.hasFatalError) { |
| 50 return result; | 54 return result; |
| 51 } | 55 } |
| 52 result.addStatus(await checkFinalConditions()); | 56 result.addStatus(await checkFinalConditions()); |
| 53 return result; | 57 return result; |
| 54 } | 58 } |
| 55 } | 59 } |
| 56 | 60 |
| 57 /** | 61 /** |
| 58 * The [SourceRange] in some [Source]. | 62 * The [SourceRange] in some [Source]. |
| 63 * |
| 64 * TODO(scheglov) inline this class as SearchMatch |
| 59 */ | 65 */ |
| 60 class SourceReference { | 66 class SourceReference { |
| 61 final String file; | 67 final SearchMatch _match; |
| 62 final SourceRange range; | |
| 63 final Element element; | |
| 64 final bool isResolved; | |
| 65 final bool isQualified; | |
| 66 | 68 |
| 67 SourceReference( | 69 SourceReference(this._match); |
| 68 this.file, this.range, this.element, this.isResolved, this.isQualified); | 70 |
| 71 AnalysisContext get context => _match.context; |
| 72 |
| 73 Element get element => _match.element; |
| 74 |
| 75 /** |
| 76 * The full path of the file containing the match. |
| 77 */ |
| 78 String get file => _match.file; |
| 69 | 79 |
| 70 @override | 80 @override |
| 71 int get hashCode { | 81 int get hashCode { |
| 72 int hash = file.hashCode; | 82 int hash = file.hashCode; |
| 73 hash = ((hash << 16) & 0xFFFFFFFF) + range.hashCode; | 83 hash = ((hash << 16) & 0xFFFFFFFF) + range.hashCode; |
| 74 return hash; | 84 return hash; |
| 75 } | 85 } |
| 76 | 86 |
| 87 bool get isResolved => _match.isResolved; |
| 88 |
| 89 SourceRange get range => _match.sourceRange; |
| 90 |
| 91 Source get unitSource => _match.unitSource; |
| 92 |
| 77 @override | 93 @override |
| 78 bool operator ==(Object other) { | 94 bool operator ==(Object other) { |
| 79 if (identical(other, this)) { | 95 if (identical(other, this)) { |
| 80 return true; | 96 return true; |
| 81 } | 97 } |
| 82 if (other is SourceReference) { | 98 if (other is SourceReference) { |
| 83 return other.file == file && other.range == range; | 99 return other.file == file && other.range == range; |
| 84 } | 100 } |
| 85 return false; | 101 return false; |
| 86 } | 102 } |
| 87 | 103 |
| 88 /** | 104 /** |
| 89 * Adds the [SourceEdit] to replace this reference. | 105 * Adds the [SourceEdit] to replace this reference. |
| 90 */ | 106 */ |
| 91 void addEdit(SourceChange change, String newText, {String id}) { | 107 void addEdit(SourceChange change, String newText, {String id}) { |
| 92 SourceEdit edit = createEdit(newText, id: id); | 108 SourceEdit edit = createEdit(newText, id: id); |
| 93 doSourceChange_addElementEdit(change, element, edit); | 109 doSourceChange_addSourceEdit(change, context, unitSource, edit); |
| 94 } | 110 } |
| 95 | 111 |
| 96 /** | 112 /** |
| 97 * Returns the [SourceEdit] to replace this reference. | 113 * Returns the [SourceEdit] to replace this reference. |
| 98 */ | 114 */ |
| 99 SourceEdit createEdit(String newText, {String id}) { | 115 SourceEdit createEdit(String newText, {String id}) { |
| 100 return newSourceEdit_range(range, newText, id: id); | 116 return newSourceEdit_range(range, newText, id: id); |
| 101 } | 117 } |
| 102 | 118 |
| 103 @override | 119 @override |
| 104 String toString() => '$file@$range'; | 120 String toString() => '$file@$range'; |
| 105 } | 121 } |
| OLD | NEW |