Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(563)

Side by Side Diff: pkg/analysis_services/lib/src/refactoring/rename.dart

Issue 465733002: 'Rename Local Variable' refactoring implementation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 // This code was auto-generated, is not intended to be edited, and is subject to 5 // This code was auto-generated, is not intended to be edited, and is subject to
6 // significant change. Please see the README file for more information. 6 // significant change. Please see the README file for more information.
7 7
8 library services.src.refactoring.rename; 8 library services.src.refactoring.rename;
9 9
10 import 'dart:async';
11 import 'dart:collection';
12
13 import 'package:analysis_services/correction/change.dart';
10 import 'package:analysis_services/correction/status.dart'; 14 import 'package:analysis_services/correction/status.dart';
11 import 'package:analysis_services/refactoring/refactoring.dart'; 15 import 'package:analysis_services/refactoring/refactoring.dart';
12 import 'package:analysis_services/search/search_engine.dart'; 16 import 'package:analysis_services/search/search_engine.dart';
13 import 'package:analysis_services/src/correction/source_range.dart'; 17 import 'package:analysis_services/src/correction/source_range.dart';
14 import 'package:analysis_services/src/generated/change.dart';
15 import 'package:analysis_services/src/refactoring/refactoring.dart'; 18 import 'package:analysis_services/src/refactoring/refactoring.dart';
16 import 'package:analyzer/src/generated/element.dart'; 19 import 'package:analyzer/src/generated/element.dart';
17 import 'package:analyzer/src/generated/engine.dart'; 20 import 'package:analyzer/src/generated/engine.dart';
18 import 'package:analyzer/src/generated/source.dart'; 21 import 'package:analyzer/src/generated/source.dart';
19 22
20 23
21 /** 24 /**
22 * Returns the [Edit] to replace the given [SearchMatch] reference. 25 * Returns the [Edit] to replace the given [SearchMatch] reference.
23 */ 26 */
24 Edit createReferenceEdit(SourceReference reference, String newText) { 27 Edit createReferenceEdit(SourceReference reference, String newText) {
25 return new Edit.range(reference.range, newText); 28 return new Edit.range(reference.range, newText);
26 } 29 }
27 30
28 31
29 /** 32 /**
33 * Returns the file containing declaration of the given [Element].
34 */
35 String getElementFile(Element element) {
36 return element.source.fullName;
37 }
38
39
40 /**
41 * When a [Source] (a file) is used in more than one context, [SearchEngine]
42 * will return separate [SearchMatch]s for each context. But in rename
43 * refactorings we want to update each [Source] only once.
44 */
45 List<SourceReference> getSourceReferences(List<SearchMatch> matches) {
46 var uniqueReferences = new HashMap<SourceReference, SourceReference>();
47 for (SearchMatch match in matches) {
48 Element element = match.element;
49 MatchKind kind = match.kind;
50 String file = getElementFile(element);
51 SourceRange range = match.sourceRange;
52 SourceReference newReference = new SourceReference(kind, file, range);
53 SourceReference oldReference = uniqueReferences[newReference];
54 if (oldReference == null) {
55 uniqueReferences[newReference] = newReference;
56 oldReference = newReference;
57 }
58 }
59 return uniqueReferences.keys.toList();
60 }
61
62
63 /**
30 * Returns `true` if two given [Element]s are [LocalElement]s and have 64 * Returns `true` if two given [Element]s are [LocalElement]s and have
31 * intersecting with visibility ranges. 65 * intersecting with visibility ranges.
32 */ 66 */
33 bool haveIntersectingRanges(LocalElement localElement, Element element) { 67 bool haveIntersectingRanges(LocalElement localElement, Element element) {
34 if (element is! LocalElement) { 68 if (element is! LocalElement) {
35 return false; 69 return false;
36 } 70 }
37 LocalElement localElement2 = element as LocalElement; 71 LocalElement localElement2 = element as LocalElement;
38 Source localSource = localElement.source; 72 Source localSource = localElement.source;
39 Source localSource2 = localElement2.source; 73 Source localSource2 = localElement2.source;
40 SourceRange localRange = localElement.visibleRange; 74 SourceRange localRange = localElement.visibleRange;
41 SourceRange localRange2 = localElement2.visibleRange; 75 SourceRange localRange2 = localElement2.visibleRange;
42 return localSource2 == localSource && 76 return localSource2 == localSource &&
43 localRange != null && 77 localRange != null &&
44 localRange2 != null && 78 localRange2 != null &&
45 localRange2.intersects(localRange); 79 localRange2.intersects(localRange);
46 } 80 }
47 81
48 82
49 /** 83 /**
84 * Checks if [element] is defined in the library containing [source].
85 */
86 bool isDefinedInLibrary(Element element, AnalysisContext context, Source source)
87 {
88 // should be the same AnalysisContext
89 if (!isInContext(element, context)) {
90 return false;
91 }
92 // private elements are visible only in their library
93 List<Source> librarySourcesOfSource = context.getLibrariesContaining(source);
94 Source librarySourceOfElement = element.library.source;
95 return librarySourcesOfSource.contains(librarySourceOfElement);
96 }
97
98
99 /**
50 * Checks if the given [Element] is in the given [AnalysisContext]. 100 * Checks if the given [Element] is in the given [AnalysisContext].
51 */ 101 */
52 bool isInContext(Element element, AnalysisContext context) { 102 bool isInContext(Element element, AnalysisContext context) {
53 AnalysisContext elementContext = element.context; 103 AnalysisContext elementContext = element.context;
54 if (elementContext == context) { 104 if (elementContext == context) {
55 return true; 105 return true;
56 } 106 }
57 if (context is InstrumentedAnalysisContextImpl) { 107 if (context is InstrumentedAnalysisContextImpl) {
58 return elementContext == context.basis; 108 return elementContext == context.basis;
59 } 109 }
60 return false; 110 return false;
61 } 111 }
62 112
63 113
64 /** 114 /**
65 * Checks if [element] is defined in the library containing [source]. 115 * Checks if the given unqualified [SearchMatch] intersects with visibility
116 * range of [localElement].
66 */ 117 */
67 bool isDefinedInLibrary(Element element, AnalysisContext context, Source source) 118 bool isReferenceInLocalRange(LocalElement localElement, SearchMatch reference) {
68 { 119 if (reference.isQualified) {
69 // should be the same AnalysisContext
70 if (!isInContext(element, context)) {
71 return false; 120 return false;
72 } 121 }
73 // private elements are visible only in their library 122 Source localSource = localElement.source;
74 List<Source> librarySourcesOfSource = context.getLibrariesContaining(source); 123 Source referenceSource = reference.element.source;
75 Source librarySourceOfElement = element.library.source; 124 SourceRange localRange = localElement.visibleRange;
76 return librarySourcesOfSource.contains(librarySourceOfElement); 125 SourceRange referenceRange = reference.sourceRange;
126 return referenceSource == localSource &&
127 referenceRange.intersects(localRange);
77 } 128 }
78 129
79 130
80 /** 131 /**
81 * Checks if [element] is visible in the library containing [source]. 132 * Checks if [element] is visible in the library containing [source].
82 */ 133 */
83 bool isVisibleInLibrary(Element element, AnalysisContext context, Source source) 134 bool isVisibleInLibrary(Element element, AnalysisContext context, Source source)
84 { 135 {
85 // should be the same AnalysisContext 136 // should be the same AnalysisContext
86 if (!isInContext(element, context)) { 137 if (!isInContext(element, context)) {
87 return false; 138 return false;
88 } 139 }
89 // public elements are always visible 140 // public elements are always visible
90 if (element.isPublic) { 141 if (element.isPublic) {
91 return true; 142 return true;
92 } 143 }
93 // private elements are visible only in their library 144 // private elements are visible only in their library
94 return isDefinedInLibrary(element, context, source); 145 return isDefinedInLibrary(element, context, source);
95 } 146 }
96 147
97 148
98 /**
99 * Checks if the given unqualified [SearchMatch] intersects with visibility
100 * range of [localElement].
101 */
102 bool isReferenceInLocalRange(LocalElement localElement, SearchMatch reference) {
103 if (reference.isQualified) {
104 return false;
105 }
106 Source localSource = localElement.source;
107 Source referenceSource = reference.element.source;
108 SourceRange localRange = localElement.visibleRange;
109 SourceRange referenceRange = reference.sourceRange;
110 return referenceSource == localSource &&
111 referenceRange.intersects(localRange);
112 }
113
114 149
115 /** 150 /**
116 * An abstract implementation of [RenameRefactoring]. 151 * An abstract implementation of [RenameRefactoring].
117 */ 152 */
118 abstract class RenameRefactoringImpl extends RefactoringImpl implements 153 abstract class RenameRefactoringImpl extends RefactoringImpl implements
119 RenameRefactoring { 154 RenameRefactoring {
120 final SearchEngine searchEngine; 155 final SearchEngine searchEngine;
121 final Element element; 156 final Element element;
122 final AnalysisContext context; 157 final AnalysisContext context;
123 final String oldName; 158 final String oldName;
124 159
125 String newName; 160 String newName;
126 161
127 RenameRefactoringImpl(SearchEngine searchEngine, Element element) 162 RenameRefactoringImpl(SearchEngine searchEngine, Element element)
128 : searchEngine = searchEngine, 163 : searchEngine = searchEngine,
129 element = element, 164 element = element,
130 context = element.context, 165 context = element.context,
131 oldName = _getDisplayName(element); 166 oldName = _getDisplayName(element);
132 167
133 /** 168 /**
134 * Adds the "Update declaration" [Edit] to [sourceChange]. 169 * Adds the "Update declaration" [Edit] to [change].
135 */ 170 */
136 void addDeclarationEdit(SourceChange sourceChange, Element element) { 171 void addDeclarationEdit(Change change, Element element) {
172 String file = getElementFile(element);
137 Edit edit = new Edit.range(rangeElementName(element), newName); 173 Edit edit = new Edit.range(rangeElementName(element), newName);
138 sourceChange.addEdit(edit, "Update declaration"); 174 change.addEdit(file, edit);
139 } 175 }
140 176
141 /** 177 /**
142 * Adds an "Update reference" [Edit] to [sourceChange]. 178 * Adds an "Update reference" [Edit] to [change].
143 */ 179 */
144 void addReferenceEdit(SourceChange sourceChange, SourceReference reference) { 180 void addReferenceEdit(Change change, SourceReference reference) {
145 Edit edit = createReferenceEdit(reference, newName); 181 Edit edit = createReferenceEdit(reference, newName);
146 sourceChange.addEdit(edit, "Update reference"); 182 change.addEdit(reference.file, edit);
147 } 183 }
148 184
149 @override 185 @override
150 RefactoringStatus checkInitialConditions() { 186 Future<RefactoringStatus> checkInitialConditions() {
151 return new RefactoringStatus(); 187 var result = new RefactoringStatus();
188 return new Future.value(result);
152 } 189 }
153 190
154 @override 191 @override
155 RefactoringStatus checkNewName() { 192 RefactoringStatus checkNewName() {
156 RefactoringStatus result = new RefactoringStatus(); 193 RefactoringStatus result = new RefactoringStatus();
157 if (newName == oldName) { 194 if (newName == oldName) {
158 result.addFatalError( 195 result.addFatalError(
159 "The new name must be different than the current name."); 196 "The new name must be different than the current name.");
160 } 197 }
161 return result; 198 return result;
162 } 199 }
163 200
201 @override
202 bool requiresPreview() {
203 return false;
204 }
205
164 static String _getDisplayName(Element element) { 206 static String _getDisplayName(Element element) {
165 if (element is ImportElement) { 207 if (element is ImportElement) {
166 PrefixElement prefix = element.prefix; 208 PrefixElement prefix = element.prefix;
167 if (prefix != null) { 209 if (prefix != null) {
168 return prefix.displayName; 210 return prefix.displayName;
169 } 211 }
170 } 212 }
171 return element.displayName; 213 return element.displayName;
172 } 214 }
173 } 215 }
174 216
175 217
176 /** 218 /**
177 * The [SourceRange] in some [Source]. 219 * The [SourceRange] in some [Source].
178 */ 220 */
179 class SourceReference { 221 class SourceReference {
180 final MatchKind kind; 222 final MatchKind kind;
181 final Source source; 223 final String file;
182 final SourceRange range; 224 final SourceRange range;
183 225
184 SourceReference(this.kind, this.source, this.range); 226 SourceReference(this.kind, this.file, this.range);
185 227
186 @override 228 @override
187 int get hashCode { 229 int get hashCode {
188 int hash = source.hashCode; 230 int hash = file.hashCode;
189 hash = ((hash << 16) & 0xFFFFFFFF) + range.hashCode; 231 hash = ((hash << 16) & 0xFFFFFFFF) + range.hashCode;
190 return hash; 232 return hash;
191 } 233 }
192 234
193 @override 235 @override
194 bool operator ==(Object obj) { 236 bool operator ==(Object other) {
195 if (identical(obj, this)) { 237 if (identical(other, this)) {
196 return true; 238 return true;
197 } 239 }
198 if (obj is! SourceReference) { 240 if (other is SourceReference) {
199 return false; 241 return other.file == file && other.range == range;
200 } 242 }
201 SourceReference other = obj as SourceReference; 243 return false;
202 return other.source == source && other.range == range;
203 } 244 }
204 245
205 @override 246 @override
206 String toString() => '${source}@${range}'; 247 String toString() => '${file}@${range}';
207 } 248 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698