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

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

Issue 871013012: Issue 22188. Verify that none or all execution flows return. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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
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';
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698