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

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

Issue 956393002: Issue 20827. Import required type in 'Extract Method' refactoring. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 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
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/refactoring/extract_method_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_method; 5 library services.src.refactoring.extract_method;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:analysis_server/src/protocol_server.dart' hide Element; 9 import 'package:analysis_server/src/protocol_server.dart' hide Element;
10 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; 10 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
11 import 'package:analysis_server/src/services/correction/selection_analyzer.dart' ; 11 import 'package:analysis_server/src/services/correction/selection_analyzer.dart' ;
12 import 'package:analysis_server/src/services/correction/source_range.dart'; 12 import 'package:analysis_server/src/services/correction/source_range.dart';
13 import 'package:analysis_server/src/services/correction/statement_analyzer.dart' ; 13 import 'package:analysis_server/src/services/correction/statement_analyzer.dart' ;
14 import 'package:analysis_server/src/services/correction/status.dart'; 14 import 'package:analysis_server/src/services/correction/status.dart';
15 import 'package:analysis_server/src/services/correction/util.dart'; 15 import 'package:analysis_server/src/services/correction/util.dart';
16 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart '; 16 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart ';
17 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; 17 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
18 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da rt'; 18 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da rt';
19 import 'package:analysis_server/src/services/refactoring/rename_class_member.dar t'; 19 import 'package:analysis_server/src/services/refactoring/rename_class_member.dar t';
20 import 'package:analysis_server/src/services/refactoring/rename_unit_member.dart '; 20 import 'package:analysis_server/src/services/refactoring/rename_unit_member.dart ';
21 import 'package:analysis_server/src/services/search/element_visitors.dart'; 21 import 'package:analysis_server/src/services/search/element_visitors.dart';
22 import 'package:analysis_server/src/services/search/search_engine.dart'; 22 import 'package:analysis_server/src/services/search/search_engine.dart';
23 import 'package:analyzer/src/generated/ast.dart'; 23 import 'package:analyzer/src/generated/ast.dart';
24 import 'package:analyzer/src/generated/element.dart'; 24 import 'package:analyzer/src/generated/element.dart';
25 import 'package:analyzer/src/generated/java_core.dart'; 25 import 'package:analyzer/src/generated/java_core.dart';
26 import 'package:analyzer/src/generated/resolver.dart' show ExitDetector;
26 import 'package:analyzer/src/generated/scanner.dart'; 27 import 'package:analyzer/src/generated/scanner.dart';
27 import 'package:analyzer/src/generated/source.dart'; 28 import 'package:analyzer/src/generated/source.dart';
28 import 'package:analyzer/src/generated/resolver.dart' show ExitDetector;
29 29
30 30
31 const String _TOKEN_SEPARATOR = '\uFFFF'; 31 const String _TOKEN_SEPARATOR = '\uFFFF';
32 32
33 33
34 /** 34 /**
35 * Returns the "normalized" version of the given source, which is reconstructed 35 * Returns the "normalized" version of the given source, which is reconstructed
36 * from tokens, so ignores all the comments and spaces. 36 * from tokens, so ignores all the comments and spaces.
37 */ 37 */
38 String _getNormalizedSource(String src) { 38 String _getNormalizedSource(String src) {
(...skipping 21 matching lines...) Expand all
60 ExtractMethodRefactoring { 60 ExtractMethodRefactoring {
61 static const ERROR_EXITS = 61 static const ERROR_EXITS =
62 'Selected statements contain a return statement, but not all possible ' 62 'Selected statements contain a return statement, but not all possible '
63 'execuion flows exit. Semantics may not be preserved.'; 63 'execuion flows exit. Semantics may not be preserved.';
64 64
65 final SearchEngine searchEngine; 65 final SearchEngine searchEngine;
66 final CompilationUnit unit; 66 final CompilationUnit unit;
67 final int selectionOffset; 67 final int selectionOffset;
68 final int selectionLength; 68 final int selectionLength;
69 CompilationUnitElement unitElement; 69 CompilationUnitElement unitElement;
70 LibraryElement libraryElement;
70 SourceRange selectionRange; 71 SourceRange selectionRange;
71 CorrectionUtils utils; 72 CorrectionUtils utils;
73 Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
72 74
73 String returnType; 75 String returnType;
74 String name; 76 String name;
75 bool extractAll = true; 77 bool extractAll = true;
76 bool createGetter = false; 78 bool createGetter = false;
77 final List<String> names = <String>[]; 79 final List<String> names = <String>[];
78 final List<int> offsets = <int>[]; 80 final List<int> offsets = <int>[];
79 final List<int> lengths = <int>[]; 81 final List<int> lengths = <int>[];
80 82
81 Set<String> _usedNames = new Set<String>(); 83 Set<String> _usedNames = new Set<String>();
82 Set<String> _excludedNames = new Set<String>(); 84 Set<String> _excludedNames = new Set<String>();
83 List<RefactoringMethodParameter> _parameters = <RefactoringMethodParameter>[]; 85 List<RefactoringMethodParameter> _parameters = <RefactoringMethodParameter>[];
84 Map<String, RefactoringMethodParameter> _parametersMap = <String, 86 Map<String, RefactoringMethodParameter> _parametersMap = <String,
85 RefactoringMethodParameter>{}; 87 RefactoringMethodParameter>{};
86 Map<String, List<SourceRange>> _parameterReferencesMap = <String, 88 Map<String, List<SourceRange>> _parameterReferencesMap = <String,
87 List<SourceRange>>{}; 89 List<SourceRange>>{};
88 DartType _returnType; 90 DartType _returnType;
89 String _returnVariableName; 91 String _returnVariableName;
90 AstNode _parentMember; 92 AstNode _parentMember;
91 Expression _selectionExpression; 93 Expression _selectionExpression;
92 FunctionExpression _selectionFunctionExpression; 94 FunctionExpression _selectionFunctionExpression;
93 List<Statement> _selectionStatements; 95 List<Statement> _selectionStatements;
94 List<_Occurrence> _occurrences = []; 96 List<_Occurrence> _occurrences = [];
95 bool _staticContext = false; 97 bool _staticContext = false;
96 98
97 ExtractMethodRefactoringImpl(this.searchEngine, this.unit, 99 ExtractMethodRefactoringImpl(this.searchEngine, this.unit,
98 this.selectionOffset, this.selectionLength) { 100 this.selectionOffset, this.selectionLength) {
99 unitElement = unit.element; 101 unitElement = unit.element;
102 libraryElement = unitElement.library;
100 selectionRange = new SourceRange(selectionOffset, selectionLength); 103 selectionRange = new SourceRange(selectionOffset, selectionLength);
101 utils = new CorrectionUtils(unit); 104 utils = new CorrectionUtils(unit);
102 } 105 }
103 106
104 bool get canCreateGetter { 107 bool get canCreateGetter {
105 if (!parameters.isEmpty) { 108 if (!parameters.isEmpty) {
106 return false; 109 return false;
107 } 110 }
108 if (_selectionExpression != null) { 111 if (_selectionExpression != null) {
109 if (_selectionExpression is AssignmentExpression) { 112 if (_selectionExpression is AssignmentExpression) {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 } 210 }
208 return new Future.value(result); 211 return new Future.value(result);
209 } 212 }
210 213
211 @override 214 @override
212 RefactoringStatus checkName() { 215 RefactoringStatus checkName() {
213 return validateMethodName(name); 216 return validateMethodName(name);
214 } 217 }
215 218
216 @override 219 @override
217 Future<SourceChange> createChange() { 220 Future<SourceChange> createChange() async {
218 SourceChange change = new SourceChange(refactoringName); 221 SourceChange change = new SourceChange(refactoringName);
219 // replace occurrences with method invocation 222 // replace occurrences with method invocation
220 for (_Occurrence occurence in _occurrences) { 223 for (_Occurrence occurence in _occurrences) {
221 SourceRange range = occurence.range; 224 SourceRange range = occurence.range;
222 // may be replacement of duplicates disabled 225 // may be replacement of duplicates disabled
223 if (!extractAll && !occurence.isSelection) { 226 if (!extractAll && !occurence.isSelection) {
224 continue; 227 continue;
225 } 228 }
226 // prepare invocation source 229 // prepare invocation source
227 String invocationSource; 230 String invocationSource;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 // closure 305 // closure
303 if (_selectionFunctionExpression != null) { 306 if (_selectionFunctionExpression != null) {
304 declarationSource = '${name}${returnExpressionSource}'; 307 declarationSource = '${name}${returnExpressionSource}';
305 if (_selectionFunctionExpression.body is ExpressionFunctionBody) { 308 if (_selectionFunctionExpression.body is ExpressionFunctionBody) {
306 declarationSource += ';'; 309 declarationSource += ';';
307 } 310 }
308 } 311 }
309 // expression 312 // expression
310 if (_selectionExpression != null) { 313 if (_selectionExpression != null) {
311 // add return type 314 // add return type
312 Set<LibraryElement> librariesToImport = new Set<LibraryElement>(); 315 if (returnType.isNotEmpty) {
313 // TODO(scheglov) use librariesToImport 316 annotations += '$returnType ';
314 String returnTypeName =
315 utils.getExpressionTypeSource(_selectionExpression, librariesToImp ort);
316 if (returnTypeName != null && returnTypeName != 'dynamic') {
317 annotations += '${returnTypeName} ';
318 } 317 }
319 // just return expression 318 // just return expression
320 declarationSource = 319 declarationSource =
321 '${annotations}${signature} => ${returnExpressionSource};'; 320 '${annotations}${signature} => ${returnExpressionSource};';
322 } 321 }
323 // statements 322 // statements
324 if (_selectionStatements != null) { 323 if (_selectionStatements != null) {
325 if (returnType.isNotEmpty) { 324 if (returnType.isNotEmpty) {
326 annotations += returnType + ' '; 325 annotations += returnType + ' ';
327 } 326 }
328 declarationSource = '${annotations}${signature} {${eol}'; 327 declarationSource = '${annotations}${signature} {${eol}';
329 declarationSource += returnExpressionSource; 328 declarationSource += returnExpressionSource;
330 if (_returnVariableName != null) { 329 if (_returnVariableName != null) {
331 declarationSource += 330 declarationSource +=
332 '${prefix} return ${_returnVariableName};$eol'; 331 '${prefix} return ${_returnVariableName};$eol';
333 } 332 }
334 declarationSource += '${prefix}}'; 333 declarationSource += '${prefix}}';
335 } 334 }
336 } 335 }
337 // insert declaration 336 // insert declaration
338 if (declarationSource != null) { 337 if (declarationSource != null) {
339 int offset = _parentMember.end; 338 int offset = _parentMember.end;
340 SourceEdit edit = 339 SourceEdit edit =
341 new SourceEdit(offset, 0, '${eol}${eol}${prefix}${declarationSource} '); 340 new SourceEdit(offset, 0, '${eol}${eol}${prefix}${declarationSource} ');
342 doSourceChange_addElementEdit(change, unitElement, edit); 341 doSourceChange_addElementEdit(change, unitElement, edit);
343 } 342 }
344 } 343 }
345 // done 344 // done
346 return new Future.value(change); 345 addLibraryImports(change, libraryElement, librariesToImport);
346 return change;
347 } 347 }
348 348
349 @override 349 @override
350 bool requiresPreview() => false; 350 bool requiresPreview() => false;
351 351
352 /** 352 /**
353 * Adds a new reference to the parameter with the given name. 353 * Adds a new reference to the parameter with the given name.
354 */ 354 */
355 void _addParameterReference(String name, SourceRange range) { 355 void _addParameterReference(String name, SourceRange range) {
356 List<SourceRange> references = _parameterReferencesMap[name]; 356 List<SourceRange> references = _parameterReferencesMap[name];
(...skipping 20 matching lines...) Expand all
377 format("'{0}' is already used as a name in the selected code", param eter.name)); 377 format("'{0}' is already used as a name in the selected code", param eter.name));
378 return result; 378 return result;
379 } 379 }
380 } 380 }
381 return result; 381 return result;
382 } 382 }
383 383
384 /** 384 /**
385 * Checks if created method will shadow or will be shadowed by other elements. 385 * Checks if created method will shadow or will be shadowed by other elements.
386 */ 386 */
387 Future<RefactoringStatus> _checkPossibleConflicts() { 387 Future<RefactoringStatus> _checkPossibleConflicts() async {
388 RefactoringStatus result = new RefactoringStatus(); 388 RefactoringStatus result = new RefactoringStatus();
389 AstNode parent = _parentMember.parent; 389 AstNode parent = _parentMember.parent;
390 // top-level function 390 // top-level function
391 if (parent is CompilationUnit) { 391 if (parent is CompilationUnit) {
392 LibraryElement libraryElement = parent.element.library; 392 LibraryElement libraryElement = parent.element.library;
393 return validateCreateFunction(searchEngine, libraryElement, name); 393 return validateCreateFunction(searchEngine, libraryElement, name);
394 } 394 }
395 // method of class 395 // method of class
396 if (parent is ClassDeclaration) { 396 if (parent is ClassDeclaration) {
397 ClassElement classElement = parent.element; 397 ClassElement classElement = parent.element;
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 String originalSource = utils.getText(range.offset, range.length); 505 String originalSource = utils.getText(range.offset, range.length);
506 _SourcePattern pattern = new _SourcePattern(); 506 _SourcePattern pattern = new _SourcePattern();
507 List<SourceEdit> replaceEdits = <SourceEdit>[]; 507 List<SourceEdit> replaceEdits = <SourceEdit>[];
508 unit.accept(new _GetSourcePatternVisitor(range, pattern, replaceEdits)); 508 unit.accept(new _GetSourcePatternVisitor(range, pattern, replaceEdits));
509 replaceEdits = replaceEdits.reversed.toList(); 509 replaceEdits = replaceEdits.reversed.toList();
510 String source = SourceEdit.applySequence(originalSource, replaceEdits); 510 String source = SourceEdit.applySequence(originalSource, replaceEdits);
511 pattern.normalizedSource = _getNormalizedSource(source); 511 pattern.normalizedSource = _getNormalizedSource(source);
512 return pattern; 512 return pattern;
513 } 513 }
514 514
515 String _getTypeCode(DartType type) {
516 return utils.getTypeSource(type, librariesToImport);
517 }
518
515 /** 519 /**
516 * Initializes [createGetter] flag. 520 * Initializes [createGetter] flag.
517 */ 521 */
518 void _initializeGetter() { 522 void _initializeGetter() {
519 createGetter = false; 523 createGetter = false;
520 // maybe we cannot at all 524 // maybe we cannot at all
521 if (!canCreateGetter) { 525 if (!canCreateGetter) {
522 return; 526 return;
523 } 527 }
524 // OK, just expression 528 // OK, just expression
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 sb.toString().trim())); 623 sb.toString().trim()));
620 } 624 }
621 // done 625 // done
622 return result; 626 return result;
623 } 627 }
624 628
625 void _initializeReturnType() { 629 void _initializeReturnType() {
626 if (_returnType == null) { 630 if (_returnType == null) {
627 returnType = 'void'; 631 returnType = 'void';
628 } else { 632 } else {
629 Set<LibraryElement> librariesToImport = new Set<LibraryElement>(); 633 returnType = _getTypeCode(_returnType);
630 // TODO(scheglov) use librariesToImport
631 returnType = utils.getTypeSource(_returnType, librariesToImport);
632 } 634 }
633 if (returnType == 'dynamic') { 635 if (returnType == 'dynamic') {
634 returnType = ''; 636 returnType = '';
635 } 637 }
636 } 638 }
637 639
638 /** 640 /**
639 * Checks if the given [VariableElement] is declared in [selectionRange]. 641 * Checks if the given [VariableElement] is declared in [selectionRange].
640 */ 642 */
641 bool _isDeclaredInSelection(VariableElement element) { 643 bool _isDeclaredInSelection(VariableElement element) {
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 return null; 1027 return null;
1026 } 1028 }
1027 // if declared outside, add parameter 1029 // if declared outside, add parameter
1028 if (!ref._isDeclaredInSelection(variableElement)) { 1030 if (!ref._isDeclaredInSelection(variableElement)) {
1029 String variableName = variableElement.displayName; 1031 String variableName = variableElement.displayName;
1030 // add parameter 1032 // add parameter
1031 RefactoringMethodParameter parameter = 1033 RefactoringMethodParameter parameter =
1032 ref._parametersMap[variableName]; 1034 ref._parametersMap[variableName];
1033 if (parameter == null) { 1035 if (parameter == null) {
1034 DartType parameterType = node.bestType; 1036 DartType parameterType = node.bestType;
1035 Set<LibraryElement> librariesToImport = new Set<LibraryElement>(); 1037 String parameterTypeCode = ref._getTypeCode(parameterType);
1036 // TODO(scheglov) use librariesToImport
1037 String parameterTypeName =
1038 ref.utils.getTypeSource(parameterType, librariesToImport);
1039 parameter = new RefactoringMethodParameter( 1038 parameter = new RefactoringMethodParameter(
1040 RefactoringMethodParameterKind.REQUIRED, 1039 RefactoringMethodParameterKind.REQUIRED,
1041 parameterTypeName, 1040 parameterTypeCode,
1042 variableName, 1041 variableName,
1043 id: variableName); 1042 id: variableName);
1044 ref._parameters.add(parameter); 1043 ref._parameters.add(parameter);
1045 ref._parametersMap[variableName] = parameter; 1044 ref._parametersMap[variableName] = parameter;
1046 } 1045 }
1047 // add reference to parameter 1046 // add reference to parameter
1048 ref._addParameterReference(variableName, nodeRange); 1047 ref._addParameterReference(variableName, nodeRange);
1049 } 1048 }
1050 // remember, if assigned and used after selection 1049 // remember, if assigned and used after selection
1051 if (isLeftHandOfAssignment(node) && 1050 if (isLeftHandOfAssignment(node) &&
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
1181 return false; 1180 return false;
1182 } 1181 }
1183 for (int i = 0; i < parameterTypes.length; i++) { 1182 for (int i = 0; i < parameterTypes.length; i++) {
1184 if (other.parameterTypes[i] != parameterTypes[i]) { 1183 if (other.parameterTypes[i] != parameterTypes[i]) {
1185 return false; 1184 return false;
1186 } 1185 }
1187 } 1186 }
1188 return true; 1187 return true;
1189 } 1188 }
1190 } 1189 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/refactoring/extract_method_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698