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 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 565 _parameters.clear(); | 565 _parameters.clear(); |
| 566 _parametersMap.clear(); | 566 _parametersMap.clear(); |
| 567 _parameterReferencesMap.clear(); | 567 _parameterReferencesMap.clear(); |
| 568 RefactoringStatus result = new RefactoringStatus(); | 568 RefactoringStatus result = new RefactoringStatus(); |
| 569 List<VariableElement> assignedUsedVariables = []; | 569 List<VariableElement> assignedUsedVariables = []; |
| 570 unit.accept(new _InitializeParametersVisitor(this, assignedUsedVariables)); | 570 unit.accept(new _InitializeParametersVisitor(this, assignedUsedVariables)); |
| 571 // single expression | 571 // single expression |
| 572 if (_selectionExpression != null) { | 572 if (_selectionExpression != null) { |
| 573 _returnType = _selectionExpression.bestType; | 573 _returnType = _selectionExpression.bestType; |
| 574 } | 574 } |
| 575 // may be ends with "return" statement | 575 // verify that none or all execution flows end with a "return" |
| 576 if (_selectionStatements != null) { | |
| 577 bool hasReturn = _selectionStatements.any(_mayEndWithReturnStatement); | |
| 578 bool endsReturn = _endsWithReturnStatement(_selectionStatements.last); | |
| 579 if (hasReturn && !endsReturn) { | |
| 580 result.addError( | |
| 581 "Selected statements contain a return statement, but " | |
| 582 "not all possible execuion flows end in a return. " | |
| 583 "Semantics may not be preserved."); | |
| 584 } | |
| 585 } | |
| 586 // maybe ends with "return" statement | |
| 576 if (_selectionStatements != null) { | 587 if (_selectionStatements != null) { |
| 577 _ReturnTypeComputer returnTypeComputer = new _ReturnTypeComputer(); | 588 _ReturnTypeComputer returnTypeComputer = new _ReturnTypeComputer(); |
| 578 _selectionStatements.forEach((statement) { | 589 _selectionStatements.forEach((statement) { |
| 579 statement.accept(returnTypeComputer); | 590 statement.accept(returnTypeComputer); |
| 580 }); | 591 }); |
| 581 _returnType = returnTypeComputer.returnType; | 592 _returnType = returnTypeComputer.returnType; |
| 582 } | 593 } |
| 583 // may be single variable to return | 594 // maybe single variable to return |
| 584 if (assignedUsedVariables.length == 1) { | 595 if (assignedUsedVariables.length == 1) { |
| 585 // we cannot both return variable and have explicit return statement | 596 // we cannot both return variable and have explicit return statement |
| 586 if (_returnType != null) { | 597 if (_returnType != null) { |
| 587 result.addFatalError( | 598 result.addFatalError( |
| 588 'Ambiguous return value: Selected block contains assignment(s) to ' | 599 'Ambiguous return value: Selected block contains assignment(s) to ' |
| 589 'local variables and return statement.'); | 600 'local variables and return statement.'); |
| 590 return result; | 601 return result; |
| 591 } | 602 } |
| 592 // prepare to return an assigned variable | 603 // prepare to return an assigned variable |
| 593 VariableElement returnVariable = assignedUsedVariables[0]; | 604 VariableElement returnVariable = assignedUsedVariables[0]; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 684 void _prepareOffsetsLengths() { | 695 void _prepareOffsetsLengths() { |
| 685 offsets.clear(); | 696 offsets.clear(); |
| 686 lengths.clear(); | 697 lengths.clear(); |
| 687 for (_Occurrence occurrence in _occurrences) { | 698 for (_Occurrence occurrence in _occurrences) { |
| 688 offsets.add(occurrence.range.offset); | 699 offsets.add(occurrence.range.offset); |
| 689 lengths.add(occurrence.range.length); | 700 lengths.add(occurrence.range.length); |
| 690 } | 701 } |
| 691 } | 702 } |
| 692 | 703 |
| 693 /** | 704 /** |
| 705 * Returns `true` if the given [statement] is a [ReturnStatement] or | |
| 706 * unconditionally ends with one. | |
| 707 */ | |
| 708 static bool _endsWithReturnStatement(Statement statement) { | |
|
Brian Wilkerson
2015/02/10 18:29:03
Should this be using ExitDetector?
scheglov
2015/02/10 19:13:42
Great idea.
Thank you!
| |
| 709 if (statement is ReturnStatement) { | |
| 710 return true; | |
| 711 } | |
| 712 if (statement is Block) { | |
| 713 List<Statement> statements = statement.statements; | |
| 714 return statements.isNotEmpty && _endsWithReturnStatement(statements[0]); | |
|
Brian Wilkerson
2015/02/10 18:29:03
Shouldn't this be "statements.last"?
scheglov
2015/02/10 19:13:42
Acknowledged.
| |
| 715 } | |
| 716 if (statement is IfStatement) { | |
| 717 Statement thenStatement = statement.thenStatement; | |
| 718 Statement elseStatement = statement.elseStatement; | |
| 719 return thenStatement != null && | |
| 720 elseStatement != null && | |
| 721 _endsWithReturnStatement(thenStatement) && | |
| 722 _endsWithReturnStatement(elseStatement); | |
| 723 } | |
| 724 return false; | |
| 725 } | |
| 726 | |
| 727 /** | |
| 694 * Checks if [node] has a [MethodInvocation]. | 728 * Checks if [node] has a [MethodInvocation]. |
| 695 */ | 729 */ |
| 696 static bool _hasMethodInvocation(AstNode node) { | 730 static bool _hasMethodInvocation(AstNode node) { |
| 697 var visitor = new _HasMethodInvocationVisitor(); | 731 var visitor = new _HasMethodInvocationVisitor(); |
| 698 node.accept(visitor); | 732 node.accept(visitor); |
| 699 return visitor.result; | 733 return visitor.result; |
| 700 } | 734 } |
| 735 | |
| 736 /** | |
| 737 * Returns `true` if the given [statement] may end with a [ReturnStatement]. | |
| 738 */ | |
| 739 static bool _mayEndWithReturnStatement(Statement statement) { | |
| 740 _HasReturnStatementVisitor visitor = new _HasReturnStatementVisitor(); | |
| 741 statement.accept(visitor); | |
| 742 return visitor.hasReturn; | |
| 743 } | |
| 701 } | 744 } |
| 702 | 745 |
| 703 | 746 |
| 704 /** | 747 /** |
| 705 * [SelectionAnalyzer] for [ExtractMethodRefactoringImpl]. | 748 * [SelectionAnalyzer] for [ExtractMethodRefactoringImpl]. |
| 706 */ | 749 */ |
| 707 class _ExtractMethodAnalyzer extends StatementAnalyzer { | 750 class _ExtractMethodAnalyzer extends StatementAnalyzer { |
| 708 _ExtractMethodAnalyzer(CompilationUnit unit, SourceRange selection) | 751 _ExtractMethodAnalyzer(CompilationUnit unit, SourceRange selection) |
| 709 : super(unit, selection); | 752 : super(unit, selection); |
| 710 | 753 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 858 class _HasMethodInvocationVisitor extends RecursiveAstVisitor { | 901 class _HasMethodInvocationVisitor extends RecursiveAstVisitor { |
| 859 bool result = false; | 902 bool result = false; |
| 860 | 903 |
| 861 @override | 904 @override |
| 862 visitMethodInvocation(MethodInvocation node) { | 905 visitMethodInvocation(MethodInvocation node) { |
| 863 result = true; | 906 result = true; |
| 864 } | 907 } |
| 865 } | 908 } |
| 866 | 909 |
| 867 | 910 |
| 911 class _HasReturnStatementVisitor extends RecursiveAstVisitor { | |
| 912 bool hasReturn = false; | |
| 913 | |
| 914 @override | |
| 915 visitBlockFunctionBody(BlockFunctionBody node) { | |
| 916 } | |
| 917 | |
| 918 @override | |
| 919 visitReturnStatement(ReturnStatement node) { | |
| 920 hasReturn = true; | |
| 921 } | |
| 922 } | |
| 923 | |
| 924 | |
| 868 class _InitializeOccurrencesVisitor extends GeneralizingAstVisitor<Object> { | 925 class _InitializeOccurrencesVisitor extends GeneralizingAstVisitor<Object> { |
| 869 final ExtractMethodRefactoringImpl ref; | 926 final ExtractMethodRefactoringImpl ref; |
| 870 final _SourcePattern selectionPattern; | 927 final _SourcePattern selectionPattern; |
| 871 final Map<String, String> patternToSelectionName; | 928 final Map<String, String> patternToSelectionName; |
| 872 | 929 |
| 873 bool forceStatic = false; | 930 bool forceStatic = false; |
| 874 | 931 |
| 875 _InitializeOccurrencesVisitor(this.ref, this.selectionPattern, | 932 _InitializeOccurrencesVisitor(this.ref, this.selectionPattern, |
| 876 this.patternToSelectionName); | 933 this.patternToSelectionName); |
| 877 | 934 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 965 // next statement | 1022 // next statement |
| 966 if (found) { | 1023 if (found) { |
| 967 beginStatementIndex += selectionCount; | 1024 beginStatementIndex += selectionCount; |
| 968 } else { | 1025 } else { |
| 969 beginStatementIndex++; | 1026 beginStatementIndex++; |
| 970 } | 1027 } |
| 971 } | 1028 } |
| 972 } | 1029 } |
| 973 } | 1030 } |
| 974 | 1031 |
| 975 | |
| 976 class _InitializeParametersVisitor extends GeneralizingAstVisitor<Object> { | 1032 class _InitializeParametersVisitor extends GeneralizingAstVisitor<Object> { |
| 977 final ExtractMethodRefactoringImpl ref; | 1033 final ExtractMethodRefactoringImpl ref; |
| 978 final List<VariableElement> assignedUsedVariables; | 1034 final List<VariableElement> assignedUsedVariables; |
| 979 | 1035 |
| 980 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); | 1036 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); |
| 981 | 1037 |
| 982 @override | 1038 @override |
| 983 Object visitSimpleIdentifier(SimpleIdentifier node) { | 1039 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 984 SourceRange nodeRange = rangeNode(node); | 1040 SourceRange nodeRange = rangeNode(node); |
| 985 if (ref.selectionRange.covers(nodeRange)) { | 1041 if (ref.selectionRange.covers(nodeRange)) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1024 } | 1080 } |
| 1025 // remember declaration names | 1081 // remember declaration names |
| 1026 if (node.inDeclarationContext()) { | 1082 if (node.inDeclarationContext()) { |
| 1027 ref._usedNames.add(node.name); | 1083 ref._usedNames.add(node.name); |
| 1028 } | 1084 } |
| 1029 } | 1085 } |
| 1030 return null; | 1086 return null; |
| 1031 } | 1087 } |
| 1032 } | 1088 } |
| 1033 | 1089 |
| 1090 | |
| 1034 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { | 1091 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { |
| 1035 final ExtractMethodRefactoringImpl ref; | 1092 final ExtractMethodRefactoringImpl ref; |
| 1036 final VariableElement element; | 1093 final VariableElement element; |
| 1037 bool result = false; | 1094 bool result = false; |
| 1038 | 1095 |
| 1039 _IsUsedAfterSelectionVisitor(this.ref, this.element); | 1096 _IsUsedAfterSelectionVisitor(this.ref, this.element); |
| 1040 | 1097 |
| 1041 @override | 1098 @override |
| 1042 visitSimpleIdentifier(SimpleIdentifier node) { | 1099 visitSimpleIdentifier(SimpleIdentifier node) { |
| 1043 VariableElement nodeElement = getLocalVariableElement(node); | 1100 VariableElement nodeElement = getLocalVariableElement(node); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1147 return false; | 1204 return false; |
| 1148 } | 1205 } |
| 1149 for (int i = 0; i < parameterTypes.length; i++) { | 1206 for (int i = 0; i < parameterTypes.length; i++) { |
| 1150 if (other.parameterTypes[i] != parameterTypes[i]) { | 1207 if (other.parameterTypes[i] != parameterTypes[i]) { |
| 1151 return false; | 1208 return false; |
| 1152 } | 1209 } |
| 1153 } | 1210 } |
| 1154 return true; | 1211 return true; |
| 1155 } | 1212 } |
| 1156 } | 1213 } |
| OLD | NEW |