| 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 if (_isParameterNameConflictWithBody(parameter)) { |
| 360 result.addError(format( | 369 result.addError(format( |
| 361 "'{0}' is already used as a name in the selected code", | 370 "'{0}' is already used as a name in the selected code", |
| 362 parameter.name)); | 371 parameter.name)); |
| 363 return result; | 372 return result; |
| 364 } | 373 } |
| 365 } | 374 } |
| 366 return result; | 375 return result; |
| 367 } | 376 } |
| 368 | 377 |
| 369 /** | 378 /** |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 | 630 |
| 622 /** | 631 /** |
| 623 * Checks if it is OK to extract the node with the given [SourceRange]. | 632 * Checks if it is OK to extract the node with the given [SourceRange]. |
| 624 */ | 633 */ |
| 625 bool _isExtractable(SourceRange range) { | 634 bool _isExtractable(SourceRange range) { |
| 626 _ExtractMethodAnalyzer analyzer = new _ExtractMethodAnalyzer(unit, range); | 635 _ExtractMethodAnalyzer analyzer = new _ExtractMethodAnalyzer(unit, range); |
| 627 utils.unit.accept(analyzer); | 636 utils.unit.accept(analyzer); |
| 628 return analyzer.status.isOK; | 637 return analyzer.status.isOK; |
| 629 } | 638 } |
| 630 | 639 |
| 640 bool _isParameterNameConflictWithBody(RefactoringMethodParameter parameter) { |
| 641 String id = parameter.id; |
| 642 String name = parameter.name; |
| 643 List<SourceRange> parameterRanges = _parameterReferencesMap[id]; |
| 644 List<SourceRange> otherRanges = _localNames[name]; |
| 645 for (SourceRange parameterRange in parameterRanges) { |
| 646 if (otherRanges != null) { |
| 647 for (SourceRange otherRange in otherRanges) { |
| 648 if (parameterRange.intersects(otherRange)) { |
| 649 return true; |
| 650 } |
| 651 } |
| 652 } |
| 653 } |
| 654 if (_unqualifiedNames.contains(name)) { |
| 655 return true; |
| 656 } |
| 657 return false; |
| 658 } |
| 659 |
| 631 /** | 660 /** |
| 632 * Checks if [element] is referenced after [selectionRange]. | 661 * Checks if [element] is referenced after [selectionRange]. |
| 633 */ | 662 */ |
| 634 bool _isUsedAfterSelection(VariableElement element) { | 663 bool _isUsedAfterSelection(VariableElement element) { |
| 635 var visitor = new _IsUsedAfterSelectionVisitor(this, element); | 664 var visitor = new _IsUsedAfterSelectionVisitor(this, element); |
| 636 _parentMember.accept(visitor); | 665 _parentMember.accept(visitor); |
| 637 return visitor.result; | 666 return visitor.result; |
| 638 } | 667 } |
| 639 | 668 |
| 640 /** | 669 /** |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 966 // next statement | 995 // next statement |
| 967 if (found) { | 996 if (found) { |
| 968 beginStatementIndex += selectionCount; | 997 beginStatementIndex += selectionCount; |
| 969 } else { | 998 } else { |
| 970 beginStatementIndex++; | 999 beginStatementIndex++; |
| 971 } | 1000 } |
| 972 } | 1001 } |
| 973 } | 1002 } |
| 974 } | 1003 } |
| 975 | 1004 |
| 976 class _InitializeParametersVisitor extends GeneralizingAstVisitor<Object> { | 1005 class _InitializeParametersVisitor extends GeneralizingAstVisitor { |
| 977 final ExtractMethodRefactoringImpl ref; | 1006 final ExtractMethodRefactoringImpl ref; |
| 978 final List<VariableElement> assignedUsedVariables; | 1007 final List<VariableElement> assignedUsedVariables; |
| 979 | 1008 |
| 980 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); | 1009 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); |
| 981 | 1010 |
| 982 @override | 1011 @override |
| 983 Object visitSimpleIdentifier(SimpleIdentifier node) { | 1012 void visitSimpleIdentifier(SimpleIdentifier node) { |
| 984 SourceRange nodeRange = rangeNode(node); | 1013 SourceRange nodeRange = rangeNode(node); |
| 985 if (ref.selectionRange.covers(nodeRange)) { | 1014 if (!ref.selectionRange.covers(nodeRange)) { |
| 986 // analyze local variable | 1015 return; |
| 987 VariableElement variableElement = | 1016 } |
| 988 getLocalOrParameterVariableElement(node); | 1017 String name = node.name; |
| 989 if (variableElement != null) { | 1018 // analyze local variable |
| 990 // name of the named expression | 1019 VariableElement variableElement = getLocalOrParameterVariableElement(node); |
| 991 if (isNamedExpressionName(node)) { | 1020 if (variableElement != null) { |
| 992 return null; | 1021 // name of the named expression |
| 1022 if (isNamedExpressionName(node)) { |
| 1023 return; |
| 1024 } |
| 1025 // if declared outside, add parameter |
| 1026 if (!ref._isDeclaredInSelection(variableElement)) { |
| 1027 // add parameter |
| 1028 RefactoringMethodParameter parameter = ref._parametersMap[name]; |
| 1029 if (parameter == null) { |
| 1030 DartType parameterType = node.bestType; |
| 1031 String parameterTypeCode = ref._getTypeCode(parameterType); |
| 1032 parameter = new RefactoringMethodParameter( |
| 1033 RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, name, |
| 1034 id: name); |
| 1035 ref._parameters.add(parameter); |
| 1036 ref._parametersMap[name] = parameter; |
| 993 } | 1037 } |
| 994 // if declared outside, add parameter | 1038 // add reference to parameter |
| 995 if (!ref._isDeclaredInSelection(variableElement)) { | 1039 ref._addParameterReference(name, nodeRange); |
| 996 String variableName = variableElement.displayName; | 1040 } |
| 997 // add parameter | 1041 // remember, if assigned and used after selection |
| 998 RefactoringMethodParameter parameter = | 1042 if (isLeftHandOfAssignment(node) && |
| 999 ref._parametersMap[variableName]; | 1043 ref._isUsedAfterSelection(variableElement)) { |
| 1000 if (parameter == null) { | 1044 if (!assignedUsedVariables.contains(variableElement)) { |
| 1001 DartType parameterType = node.bestType; | 1045 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 } | 1046 } |
| 1019 } | 1047 } |
| 1020 // remember declaration names | 1048 } |
| 1049 // remember information for conflicts checking |
| 1050 if (variableElement is LocalElement) { |
| 1051 // declared local elements |
| 1052 LocalElement localElement = variableElement as LocalElement; |
| 1021 if (node.inDeclarationContext()) { | 1053 if (node.inDeclarationContext()) { |
| 1022 ref._usedNames.add(node.name); | 1054 ref._localNames.putIfAbsent(name, () => <SourceRange>[]); |
| 1055 ref._localNames[name].add(localElement.visibleRange); |
| 1056 } |
| 1057 } else { |
| 1058 // unqualified non-local names |
| 1059 if (!node.isQualified) { |
| 1060 ref._unqualifiedNames.add(name); |
| 1023 } | 1061 } |
| 1024 } | 1062 } |
| 1025 return null; | |
| 1026 } | 1063 } |
| 1027 } | 1064 } |
| 1028 | 1065 |
| 1029 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { | 1066 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { |
| 1030 final ExtractMethodRefactoringImpl ref; | 1067 final ExtractMethodRefactoringImpl ref; |
| 1031 final VariableElement element; | 1068 final VariableElement element; |
| 1032 bool result = false; | 1069 bool result = false; |
| 1033 | 1070 |
| 1034 _IsUsedAfterSelectionVisitor(this.ref, this.element); | 1071 _IsUsedAfterSelectionVisitor(this.ref, this.element); |
| 1035 | 1072 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1107 return false; | 1144 return false; |
| 1108 } | 1145 } |
| 1109 for (int i = 0; i < parameterTypes.length; i++) { | 1146 for (int i = 0; i < parameterTypes.length; i++) { |
| 1110 if (other.parameterTypes[i] != parameterTypes[i]) { | 1147 if (other.parameterTypes[i] != parameterTypes[i]) { |
| 1111 return false; | 1148 return false; |
| 1112 } | 1149 } |
| 1113 } | 1150 } |
| 1114 return true; | 1151 return true; |
| 1115 } | 1152 } |
| 1116 } | 1153 } |
| OLD | NEW |