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

Side by Side Diff: pkg/analysis_server/lib/src/services/refactoring/extract_local.dart

Issue 1502183007: Extract Local refactoring: provide a linked edit group for the name. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years 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
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/refactoring/extract_local_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 library services.src.refactoring.extract_local; 5 library services.src.refactoring.extract_local;
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;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 String stringLiteralPart; 52 String stringLiteralPart;
53 final List<SourceRange> occurrences = <SourceRange>[]; 53 final List<SourceRange> occurrences = <SourceRange>[];
54 final Map<Element, int> elementIds = <Element, int>{}; 54 final Map<Element, int> elementIds = <Element, int>{};
55 Set<String> excludedVariableNames = new Set<String>(); 55 Set<String> excludedVariableNames = new Set<String>();
56 56
57 ExtractLocalRefactoringImpl( 57 ExtractLocalRefactoringImpl(
58 this.unit, this.selectionOffset, this.selectionLength) { 58 this.unit, this.selectionOffset, this.selectionLength) {
59 unitElement = unit.element; 59 unitElement = unit.element;
60 selectionRange = new SourceRange(selectionOffset, selectionLength); 60 selectionRange = new SourceRange(selectionOffset, selectionLength);
61 utils = new CorrectionUtils(unit); 61 utils = new CorrectionUtils(unit);
62 file = unitElement.source.fullName;
62 } 63 }
63 64
64 @override 65 @override
65 String get refactoringName => 'Extract Local Variable'; 66 String get refactoringName => 'Extract Local Variable';
66 67
67 String get _declarationKeyword { 68 String get _declarationKeyword {
68 if (_isPartOfConstantExpression(rootExpression)) { 69 if (_isPartOfConstantExpression(rootExpression)) {
69 return "const"; 70 return "const";
70 } else { 71 } else {
71 return "var"; 72 return "var";
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 @override 111 @override
111 Future<SourceChange> createChange() { 112 Future<SourceChange> createChange() {
112 SourceChange change = new SourceChange(refactoringName); 113 SourceChange change = new SourceChange(refactoringName);
113 // prepare occurrences 114 // prepare occurrences
114 List<SourceRange> occurrences; 115 List<SourceRange> occurrences;
115 if (extractAll) { 116 if (extractAll) {
116 occurrences = this.occurrences; 117 occurrences = this.occurrences;
117 } else { 118 } else {
118 occurrences = [selectionRange]; 119 occurrences = [selectionRange];
119 } 120 }
121 occurrences.sort((a, b) => a.offset - b.offset);
120 // If the whole expression of a statement is selected, like '1 + 2', 122 // If the whole expression of a statement is selected, like '1 + 2',
121 // then convert it into a variable declaration statement. 123 // then convert it into a variable declaration statement.
122 if (wholeStatementExpression && occurrences.length == 1) { 124 if (wholeStatementExpression && occurrences.length == 1) {
123 String keyword = _declarationKeyword; 125 String keyword = _declarationKeyword;
124 String declarationSource = '$keyword $name = '; 126 String declarationSource = '$keyword $name = ';
125 SourceEdit edit = 127 SourceEdit edit =
126 new SourceEdit(singleExpression.offset, 0, declarationSource); 128 new SourceEdit(singleExpression.offset, 0, declarationSource);
127 doSourceChange_addElementEdit(change, unitElement, edit); 129 doSourceChange_addElementEdit(change, unitElement, edit);
128 return new Future.value(change); 130 return new Future.value(change);
129 } 131 }
132 // prepare positions
133 List<Position> positions = <Position>[];
134 int occurrencesShift = 0;
135 void addPosition(int offset) {
136 positions.add(new Position(file, offset));
137 }
130 // add variable declaration 138 // add variable declaration
131 { 139 {
132 String declarationSource; 140 String declarationCode;
141 int nameOffsetInDeclarationCode;
133 if (stringLiteralPart != null) { 142 if (stringLiteralPart != null) {
134 declarationSource = "var $name = '$stringLiteralPart';"; 143 declarationCode = 'var ';
144 nameOffsetInDeclarationCode = declarationCode.length;
145 declarationCode += "$name = '$stringLiteralPart';";
135 } else { 146 } else {
136 String keyword = _declarationKeyword; 147 String keyword = _declarationKeyword;
137 String initializerSource = utils.getRangeText(selectionRange); 148 String initializerCode = utils.getRangeText(selectionRange);
138 declarationSource = "$keyword $name = $initializerSource;"; 149 declarationCode = '$keyword ';
150 nameOffsetInDeclarationCode = declarationCode.length;
151 declarationCode += '$name = $initializerCode;';
139 } 152 }
140 String eol = utils.endOfLine;
141 // prepare location for declaration 153 // prepare location for declaration
142 AstNode target = _findDeclarationTarget(occurrences); 154 AstNode target = _findDeclarationTarget(occurrences);
155 String eol = utils.endOfLine;
143 // insert variable declaration 156 // insert variable declaration
144 if (target is Statement) { 157 if (target is Statement) {
145 String prefix = utils.getNodePrefix(target); 158 String prefix = utils.getNodePrefix(target);
146 SourceEdit edit = 159 SourceEdit edit =
147 new SourceEdit(target.offset, 0, declarationSource + eol + prefix); 160 new SourceEdit(target.offset, 0, declarationCode + eol + prefix);
148 doSourceChange_addElementEdit(change, unitElement, edit); 161 doSourceChange_addElementEdit(change, unitElement, edit);
162 addPosition(edit.offset + nameOffsetInDeclarationCode);
163 occurrencesShift = edit.replacement.length;
149 } else if (target is ExpressionFunctionBody) { 164 } else if (target is ExpressionFunctionBody) {
150 String prefix = utils.getNodePrefix(target.parent); 165 String prefix = utils.getNodePrefix(target.parent);
151 String indent = utils.getIndent(1); 166 String indent = utils.getIndent(1);
152 String declStatement = prefix + indent + declarationSource + eol;
153 String exprStatement = prefix + indent + 'return ';
154 Expression expr = target.expression; 167 Expression expr = target.expression;
155 doSourceChange_addElementEdit( 168 {
156 change, 169 String code = '{' + eol + prefix + indent;
157 unitElement, 170 addPosition(
158 new SourceEdit(target.offset, expr.offset - target.offset, 171 target.offset + code.length + nameOffsetInDeclarationCode);
159 '{' + eol + declStatement + exprStatement)); 172 code += declarationCode + eol;
173 code += prefix + indent + 'return ';
174 SourceEdit edit =
175 new SourceEdit(target.offset, expr.offset - target.offset, code);
176 occurrencesShift = target.offset + code.length - expr.offset;
177 doSourceChange_addElementEdit(change, unitElement, edit);
178 }
160 doSourceChange_addElementEdit(change, unitElement, 179 doSourceChange_addElementEdit(change, unitElement,
161 new SourceEdit(expr.end, 0, ';' + eol + prefix + '}')); 180 new SourceEdit(expr.end, 0, ';' + eol + prefix + '}'));
162 } 181 }
163 } 182 }
164 // prepare replacement 183 // prepare replacement
165 String occurrenceReplacement = name; 184 String occurrenceReplacement = name;
166 if (stringLiteralPart != null) { 185 if (stringLiteralPart != null) {
167 occurrenceReplacement = "\${$name}"; 186 occurrenceReplacement = "\${$name}";
187 occurrencesShift += 2;
168 } 188 }
169 // replace occurrences with variable reference 189 // replace occurrences with variable reference
170 for (SourceRange range in occurrences) { 190 for (SourceRange range in occurrences) {
171 SourceEdit edit = newSourceEdit_range(range, occurrenceReplacement); 191 SourceEdit edit = newSourceEdit_range(range, occurrenceReplacement);
192 addPosition(range.offset + occurrencesShift);
193 occurrencesShift += name.length - range.length;
172 doSourceChange_addElementEdit(change, unitElement, edit); 194 doSourceChange_addElementEdit(change, unitElement, edit);
173 } 195 }
196 // add the linked group
197 change.addLinkedEditGroup(new LinkedEditGroup(
198 positions,
199 name.length,
200 names
201 .map((name) => new LinkedEditSuggestion(
202 name, LinkedEditSuggestionKind.VARIABLE))
203 .toList()));
174 // done 204 // done
175 return new Future.value(change); 205 return new Future.value(change);
176 } 206 }
177 207
178 @override 208 @override
179 bool requiresPreview() => false; 209 bool requiresPreview() => false;
180 210
181 /** 211 /**
182 * Checks if [selectionRange] selects [Expression] which can be extracted, and 212 * Checks if [selectionRange] selects [Expression] which can be extracted, and
183 * location of this [Expression] in AST allows extracting. 213 * location of this [Expression] in AST allows extracting.
184 */ 214 */
185 RefactoringStatus _checkSelection() { 215 RefactoringStatus _checkSelection() {
186 String selectionStr; 216 String selectionStr;
187 // exclude whitespaces 217 // exclude whitespaces
188 { 218 {
189 selectionStr = utils.getRangeText(selectionRange); 219 selectionStr = utils.getRangeText(selectionRange);
190 int numLeading = countLeadingWhitespaces(selectionStr); 220 int numLeading = countLeadingWhitespaces(selectionStr);
191 int numTrailing = countTrailingWhitespaces(selectionStr); 221 int numTrailing = countTrailingWhitespaces(selectionStr);
192 int offset = selectionRange.offset + numLeading; 222 int offset = selectionRange.offset + numLeading;
193 int end = selectionRange.end - numTrailing; 223 int end = selectionRange.end - numTrailing;
194 selectionRange = new SourceRange(offset, end - offset); 224 selectionRange = new SourceRange(offset, end - offset);
195 } 225 }
196 // get covering node 226 // get covering node
197 AstNode coveringNode = new NodeLocator( 227 AstNode coveringNode =
198 selectionRange.offset, selectionRange.end).searchWithin(unit); 228 new NodeLocator(selectionRange.offset, selectionRange.end)
229 .searchWithin(unit);
199 // compute covering expressions 230 // compute covering expressions
200 for (AstNode node = coveringNode; 231 for (AstNode node = coveringNode;
201 node is Expression || node is ArgumentList; 232 node is Expression || node is ArgumentList;
202 node = node.parent) { 233 node = node.parent) {
203 AstNode parent = node.parent; 234 AstNode parent = node.parent;
204 // skip ArgumentList 235 // skip ArgumentList
205 if (node is ArgumentList) { 236 if (node is ArgumentList) {
206 continue; 237 continue;
207 } 238 }
208 // skip AssignmentExpression 239 // skip AssignmentExpression
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 660
630 _TokenLocalElementVisitor(this.map); 661 _TokenLocalElementVisitor(this.map);
631 662
632 visitSimpleIdentifier(SimpleIdentifier node) { 663 visitSimpleIdentifier(SimpleIdentifier node) {
633 Element element = node.staticElement; 664 Element element = node.staticElement;
634 if (element is LocalVariableElement) { 665 if (element is LocalVariableElement) {
635 map[node.token] = element; 666 map[node.token] = element;
636 } 667 }
637 } 668 }
638 } 669 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/refactoring/extract_local_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698