Chromium Code Reviews| 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.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'; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 | 70 |
| 71 String returnType; | 71 String returnType; |
| 72 String name; | 72 String name; |
| 73 bool extractAll = true; | 73 bool extractAll = true; |
| 74 bool canCreateGetter = false; | 74 bool canCreateGetter = false; |
| 75 bool createGetter = false; | 75 bool createGetter = false; |
| 76 final List<String> names = <String>[]; | 76 final List<String> names = <String>[]; |
| 77 final List<int> offsets = <int>[]; | 77 final List<int> offsets = <int>[]; |
| 78 final List<int> lengths = <int>[]; | 78 final List<int> lengths = <int>[]; |
| 79 | 79 |
| 80 Set<String> _usedNames = new Set<String>(); | 80 /** |
| 81 * The map of local names to their visibility ranges. | |
| 82 */ | |
| 83 Map<String, List<SourceRange>> _localNames = <String, List<SourceRange>>{}; | |
| 84 | |
| 85 /** | |
| 86 * The set of names that are referenced without any qualifier. | |
| 87 */ | |
| 88 Set<String> _unqualifiedNames = new Set<String>(); | |
| 89 | |
| 81 Set<String> _excludedNames = new Set<String>(); | 90 Set<String> _excludedNames = new Set<String>(); |
| 82 List<RefactoringMethodParameter> _parameters = <RefactoringMethodParameter>[]; | 91 List<RefactoringMethodParameter> _parameters = <RefactoringMethodParameter>[]; |
| 83 Map<String, RefactoringMethodParameter> _parametersMap = | 92 Map<String, RefactoringMethodParameter> _parametersMap = |
| 84 <String, RefactoringMethodParameter>{}; | 93 <String, RefactoringMethodParameter>{}; |
| 85 Map<String, List<SourceRange>> _parameterReferencesMap = | 94 Map<String, List<SourceRange>> _parameterReferencesMap = |
| 86 <String, List<SourceRange>>{}; | 95 <String, List<SourceRange>>{}; |
| 87 DartType _returnType; | 96 DartType _returnType; |
| 88 String _returnVariableName; | 97 String _returnVariableName; |
| 89 AstNode _parentMember; | 98 AstNode _parentMember; |
| 90 Expression _selectionExpression; | 99 Expression _selectionExpression; |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 RefactoringStatus result = new RefactoringStatus(); | 358 RefactoringStatus result = new RefactoringStatus(); |
| 350 for (RefactoringMethodParameter parameter in _parameters) { | 359 for (RefactoringMethodParameter parameter in _parameters) { |
| 351 result.addStatus(validateParameterName(parameter.name)); | 360 result.addStatus(validateParameterName(parameter.name)); |
| 352 for (RefactoringMethodParameter other in _parameters) { | 361 for (RefactoringMethodParameter other in _parameters) { |
| 353 if (!identical(parameter, other) && other.name == parameter.name) { | 362 if (!identical(parameter, other) && other.name == parameter.name) { |
| 354 result.addError( | 363 result.addError( |
| 355 format("Parameter '{0}' already exists", parameter.name)); | 364 format("Parameter '{0}' already exists", parameter.name)); |
| 356 return result; | 365 return result; |
| 357 } | 366 } |
| 358 } | 367 } |
| 359 if (_usedNames.contains(parameter.name)) { | 368 // TODO |
|
Brian Wilkerson
2015/04/03 21:00:41
Remove or expand (explain what needs to be done).
| |
| 369 if (_isParameterNameConflictWithBody(parameter)) { | |
| 360 result.addError(format( | 370 result.addError(format( |
| 361 "'{0}' is already used as a name in the selected code", | 371 "'{0}' is already used as a name in the selected code", |
| 362 parameter.name)); | 372 parameter.name)); |
| 363 return result; | 373 return result; |
| 364 } | 374 } |
| 375 // List<SourceRange> usedRanges = _usedNames[parameter.name]; | |
| 376 // if (_usedNames.contains(parameter.name)) { | |
| 377 // result.addError(format( | |
| 378 // "'{0}' is already used as a name in the selected code", | |
| 379 // parameter.name)); | |
| 380 // return result; | |
| 381 // } | |
| 365 } | 382 } |
| 366 return result; | 383 return result; |
| 367 } | 384 } |
| 368 | 385 |
| 369 /** | 386 /** |
| 370 * Checks if created method will shadow or will be shadowed by other elements. | 387 * Checks if created method will shadow or will be shadowed by other elements. |
| 371 */ | 388 */ |
| 372 Future<RefactoringStatus> _checkPossibleConflicts() async { | 389 Future<RefactoringStatus> _checkPossibleConflicts() async { |
| 373 RefactoringStatus result = new RefactoringStatus(); | 390 RefactoringStatus result = new RefactoringStatus(); |
| 374 AstNode parent = _parentMember.parent; | 391 AstNode parent = _parentMember.parent; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 621 | 638 |
| 622 /** | 639 /** |
| 623 * Checks if it is OK to extract the node with the given [SourceRange]. | 640 * Checks if it is OK to extract the node with the given [SourceRange]. |
| 624 */ | 641 */ |
| 625 bool _isExtractable(SourceRange range) { | 642 bool _isExtractable(SourceRange range) { |
| 626 _ExtractMethodAnalyzer analyzer = new _ExtractMethodAnalyzer(unit, range); | 643 _ExtractMethodAnalyzer analyzer = new _ExtractMethodAnalyzer(unit, range); |
| 627 utils.unit.accept(analyzer); | 644 utils.unit.accept(analyzer); |
| 628 return analyzer.status.isOK; | 645 return analyzer.status.isOK; |
| 629 } | 646 } |
| 630 | 647 |
| 648 bool _isParameterNameConflictWithBody(RefactoringMethodParameter parameter) { | |
| 649 String id = parameter.id; | |
| 650 String name = parameter.name; | |
| 651 // TODO | |
|
Brian Wilkerson
2015/04/03 21:00:41
ditto
| |
| 652 List<SourceRange> parameterRanges = _parameterReferencesMap[id]; | |
| 653 List<SourceRange> otherRanges = _localNames[name]; | |
| 654 for (SourceRange parameterRange in parameterRanges) { | |
| 655 if (otherRanges != null) { | |
| 656 for (SourceRange otherRange in otherRanges) { | |
| 657 if (parameterRange.intersects(otherRange)) { | |
| 658 return true; | |
| 659 } | |
| 660 } | |
| 661 } | |
| 662 } | |
| 663 if (_unqualifiedNames.contains(name)) { | |
| 664 return true; | |
| 665 } | |
| 666 return false; | |
| 667 } | |
| 668 | |
| 631 /** | 669 /** |
| 632 * Checks if [element] is referenced after [selectionRange]. | 670 * Checks if [element] is referenced after [selectionRange]. |
| 633 */ | 671 */ |
| 634 bool _isUsedAfterSelection(VariableElement element) { | 672 bool _isUsedAfterSelection(VariableElement element) { |
| 635 var visitor = new _IsUsedAfterSelectionVisitor(this, element); | 673 var visitor = new _IsUsedAfterSelectionVisitor(this, element); |
| 636 _parentMember.accept(visitor); | 674 _parentMember.accept(visitor); |
| 637 return visitor.result; | 675 return visitor.result; |
| 638 } | 676 } |
| 639 | 677 |
| 640 /** | 678 /** |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 966 // next statement | 1004 // next statement |
| 967 if (found) { | 1005 if (found) { |
| 968 beginStatementIndex += selectionCount; | 1006 beginStatementIndex += selectionCount; |
| 969 } else { | 1007 } else { |
| 970 beginStatementIndex++; | 1008 beginStatementIndex++; |
| 971 } | 1009 } |
| 972 } | 1010 } |
| 973 } | 1011 } |
| 974 } | 1012 } |
| 975 | 1013 |
| 976 class _InitializeParametersVisitor extends GeneralizingAstVisitor<Object> { | 1014 class _InitializeParametersVisitor extends GeneralizingAstVisitor { |
| 977 final ExtractMethodRefactoringImpl ref; | 1015 final ExtractMethodRefactoringImpl ref; |
| 978 final List<VariableElement> assignedUsedVariables; | 1016 final List<VariableElement> assignedUsedVariables; |
| 979 | 1017 |
| 980 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); | 1018 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); |
| 981 | 1019 |
| 982 @override | 1020 @override |
| 983 Object visitSimpleIdentifier(SimpleIdentifier node) { | 1021 void visitSimpleIdentifier(SimpleIdentifier node) { |
| 984 SourceRange nodeRange = rangeNode(node); | 1022 SourceRange nodeRange = rangeNode(node); |
| 985 if (ref.selectionRange.covers(nodeRange)) { | 1023 if (!ref.selectionRange.covers(nodeRange)) { |
| 986 // analyze local variable | 1024 return; |
| 987 VariableElement variableElement = | 1025 } |
| 988 getLocalOrParameterVariableElement(node); | 1026 String name = node.name; |
| 989 if (variableElement != null) { | 1027 // analyze local variable |
| 990 // name of the named expression | 1028 VariableElement variableElement = getLocalOrParameterVariableElement(node); |
| 991 if (isNamedExpressionName(node)) { | 1029 if (variableElement != null) { |
| 992 return null; | 1030 // name of the named expression |
| 1031 if (isNamedExpressionName(node)) { | |
| 1032 return; | |
| 1033 } | |
| 1034 // if declared outside, add parameter | |
| 1035 if (!ref._isDeclaredInSelection(variableElement)) { | |
| 1036 // add parameter | |
| 1037 RefactoringMethodParameter parameter = ref._parametersMap[name]; | |
| 1038 if (parameter == null) { | |
| 1039 DartType parameterType = node.bestType; | |
| 1040 String parameterTypeCode = ref._getTypeCode(parameterType); | |
| 1041 parameter = new RefactoringMethodParameter( | |
| 1042 RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, name, | |
| 1043 id: name); | |
| 1044 ref._parameters.add(parameter); | |
| 1045 ref._parametersMap[name] = parameter; | |
| 993 } | 1046 } |
| 994 // if declared outside, add parameter | 1047 // add reference to parameter |
| 995 if (!ref._isDeclaredInSelection(variableElement)) { | 1048 ref._addParameterReference(name, nodeRange); |
| 996 String variableName = variableElement.displayName; | 1049 } |
| 997 // add parameter | 1050 // remember, if assigned and used after selection |
| 998 RefactoringMethodParameter parameter = | 1051 if (isLeftHandOfAssignment(node) && |
| 999 ref._parametersMap[variableName]; | 1052 ref._isUsedAfterSelection(variableElement)) { |
| 1000 if (parameter == null) { | 1053 if (!assignedUsedVariables.contains(variableElement)) { |
| 1001 DartType parameterType = node.bestType; | 1054 assignedUsedVariables.add(variableElement); |
| 1002 String parameterTypeCode = ref._getTypeCode(parameterType); | |
| 1003 parameter = new RefactoringMethodParameter( | |
| 1004 RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, | |
| 1005 variableName, id: variableName); | |
| 1006 ref._parameters.add(parameter); | |
| 1007 ref._parametersMap[variableName] = parameter; | |
| 1008 } | |
| 1009 // add reference to parameter | |
| 1010 ref._addParameterReference(variableName, nodeRange); | |
| 1011 } | |
| 1012 // remember, if assigned and used after selection | |
| 1013 if (isLeftHandOfAssignment(node) && | |
| 1014 ref._isUsedAfterSelection(variableElement)) { | |
| 1015 if (!assignedUsedVariables.contains(variableElement)) { | |
| 1016 assignedUsedVariables.add(variableElement); | |
| 1017 } | |
| 1018 } | 1055 } |
| 1019 } | 1056 } |
| 1020 // remember declaration names | 1057 } |
| 1058 // remember information for conflicts checking | |
| 1059 if (variableElement is LocalElement) { | |
| 1060 // declared local elements | |
| 1061 LocalElement localElement = variableElement as LocalElement; | |
| 1021 if (node.inDeclarationContext()) { | 1062 if (node.inDeclarationContext()) { |
| 1022 ref._usedNames.add(node.name); | 1063 ref._localNames.putIfAbsent(name, () => <SourceRange>[]); |
| 1064 ref._localNames[name].add(localElement.visibleRange); | |
| 1065 } | |
| 1066 } else { | |
| 1067 // unqualified non-local names | |
| 1068 if (!node.isQualified) { | |
| 1069 ref._unqualifiedNames.add(name); | |
| 1023 } | 1070 } |
| 1024 } | 1071 } |
| 1025 return null; | |
| 1026 } | 1072 } |
| 1027 } | 1073 } |
| 1028 | 1074 |
| 1029 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { | 1075 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { |
| 1030 final ExtractMethodRefactoringImpl ref; | 1076 final ExtractMethodRefactoringImpl ref; |
| 1031 final VariableElement element; | 1077 final VariableElement element; |
| 1032 bool result = false; | 1078 bool result = false; |
| 1033 | 1079 |
| 1034 _IsUsedAfterSelectionVisitor(this.ref, this.element); | 1080 _IsUsedAfterSelectionVisitor(this.ref, this.element); |
| 1035 | 1081 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1107 return false; | 1153 return false; |
| 1108 } | 1154 } |
| 1109 for (int i = 0; i < parameterTypes.length; i++) { | 1155 for (int i = 0; i < parameterTypes.length; i++) { |
| 1110 if (other.parameterTypes[i] != parameterTypes[i]) { | 1156 if (other.parameterTypes[i] != parameterTypes[i]) { |
| 1111 return false; | 1157 return false; |
| 1112 } | 1158 } |
| 1113 } | 1159 } |
| 1114 return true; | 1160 return true; |
| 1115 } | 1161 } |
| 1116 } | 1162 } |
| OLD | NEW |