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

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

Issue 506753002: Parameters and validation for the 'Extract Method' refactoring. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 00990465393a8b3fda749c3810c0ba860b16c35c..4418916d38b6fa796b737a903b58ccd489419fd5 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -15,6 +15,8 @@ import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
+import 'package:analysis_server/src/services/refactoring/rename_class_member.dart';
+import 'package:analysis_server/src/services/refactoring/rename_unit_member.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
@@ -23,7 +25,7 @@ import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
-const String _TOKEN_SEPARATOR = "\uFFFF";
+const String _TOKEN_SEPARATOR = '\uFFFF';
/**
@@ -106,50 +108,12 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
return true;
}
- /**
- * @return the selected [DartExpression] source, with applying new parameter names.
- */
- String get methodBodySource {
- String source = utils.getRangeText(selectionRange);
- // prepare ReplaceEdit operations to replace variables with parameters
- // TODO: implement parameters
- List<SourceEdit> replaceEdits = [];
-// for (Parameter parameter in _parametersMap.values) {
-// List<SourceRange> ranges = _parameterReferencesMap[parameter.oldName];
-// if (ranges != null) {
-// for (SourceRange range in ranges) {
-// replaceEdits.add(new SourceEdit(range.offset - selectionRange.offset, range.length, parameter.newName));
-// }
-// }
-// }
- // apply replacements
- source = SourceEdit.applySequence(source, replaceEdits);
- // change indentation
- if (_selectionFunctionExpression != null) {
- AstNode baseNode =
- _selectionFunctionExpression.getAncestor((node) => node is Statement);
- if (baseNode != null) {
- String baseIndent = utils.getNodePrefix(baseNode);
- String targetIndent = utils.getNodePrefix(_parentMember);
- source = utils.replaceSourceIndent(source, baseIndent, targetIndent);
- source = source.trim();
- }
- }
- if (_selectionStatements != null) {
- String selectionIndent = utils.getNodePrefix(_selectionStatements[0]);
- String targetIndent = utils.getNodePrefix(_parentMember) + ' ';
- source = utils.replaceSourceIndent(source, selectionIndent, targetIndent);
- }
- // done
- return source;
- }
-
@override
List<RefactoringMethodParameter> get parameters => _parameters;
@override
void set parameters(List<RefactoringMethodParameter> parameters) {
- // TODO: implement parameters
+ _parameters = parameters.toList();
}
@override
@@ -165,11 +129,11 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
String get signature {
StringBuffer sb = new StringBuffer();
if (createGetter) {
- sb.write("get ");
+ sb.write('get ');
sb.write(name);
} else {
sb.write(name);
- sb.write("(");
+ sb.write('(');
// add all parameters
bool firstParameter = true;
for (RefactoringMethodParameter parameter in _parameters) {
@@ -184,13 +148,13 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
String typeSource = parameter.type;
if ('dynamic' != typeSource && '' != typeSource) {
sb.write(typeSource);
- sb.write(" ");
+ sb.write(' ');
}
}
// name
sb.write(parameter.name);
}
- sb.write(")");
+ sb.write(')');
}
// done
return sb.toString();
@@ -199,10 +163,17 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
@override
Future<RefactoringStatus> checkFinalConditions() {
RefactoringStatus result = new RefactoringStatus();
- return new Future.value(result);
+ result.addStatus(validateMethodName(name));
+ result.addStatus(_checkParameterNames());
// TODO: implement checkFinalConditions
+ return _checkPossibleConflicts().then((status) {
+ result.addStatus(status);
+ return result;
+ });
+ return new Future.value(result);
}
+
@override
Future<RefactoringStatus> checkInitialConditions() {
RefactoringStatus result = new RefactoringStatus();
@@ -273,7 +244,7 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
// invocation itself
sb.write(name);
if (!createGetter) {
- sb.write("(");
+ sb.write('(');
bool firstParameter = true;
for (RefactoringMethodParameter parameter in _parameters) {
// may be comma
@@ -307,7 +278,7 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
String prefix = utils.getNodePrefix(_parentMember);
String eol = utils.endOfLine;
// prepare annotations
- String annotations = "";
+ String annotations = '';
{
// may be "static"
if (_staticContext) {
@@ -317,10 +288,10 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
// prepare declaration source
String declarationSource = null;
{
- String returnExpressionSource = methodBodySource;
+ String returnExpressionSource = _getMethodBodySource();
// closure
if (_selectionFunctionExpression != null) {
- declarationSource = "${name}${returnExpressionSource}";
+ declarationSource = '${name}${returnExpressionSource}';
if (_selectionFunctionExpression.body is ExpressionFunctionBody) {
declarationSource += ';';
}
@@ -330,12 +301,12 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
// add return type
String returnTypeName =
utils.getExpressionTypeSource(_selectionExpression);
- if (returnTypeName != null && returnTypeName != "dynamic") {
- annotations += "${returnTypeName} ";
+ if (returnTypeName != null && returnTypeName != 'dynamic') {
+ annotations += '${returnTypeName} ';
}
// just return expression
declarationSource =
- "${annotations}${signature} => ${returnExpressionSource};";
+ '${annotations}${signature} => ${returnExpressionSource};';
}
// statements
if (_selectionStatements != null) {
@@ -346,7 +317,7 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
} else {
annotations += 'void ';
}
- declarationSource = "${annotations}${signature} {${eol}";
+ declarationSource = '${annotations}${signature} {${eol}';
declarationSource += returnExpressionSource;
if (_returnVariableName != null) {
declarationSource +=
@@ -382,6 +353,46 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
references.add(range);
}
+ RefactoringStatus _checkParameterNames() {
+ RefactoringStatus result = new RefactoringStatus();
+ for (RefactoringMethodParameter parameter in _parameters) {
+ result.addStatus(validateParameterName(parameter.name));
+ for (RefactoringMethodParameter other in _parameters) {
+ if (!identical(parameter, other) && other.name == parameter.name) {
+ result.addError(
+ format("Parameter '{0}' already exists", parameter.name));
+ return result;
+ }
+ }
+ if (_usedNames.contains(parameter.name)) {
+ result.addError(
+ format("'{0}' is already used as a name in the selected code", parameter.name));
+ return result;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if created method will shadow or will be shadowed by other elements.
+ */
+ Future<RefactoringStatus> _checkPossibleConflicts() {
+ RefactoringStatus result = new RefactoringStatus();
+ AstNode parent = _parentMember.parent;
+ // top-level function
+ if (parent is CompilationUnit) {
+ LibraryElement libraryElement = parent.element.library;
+ return validateCreateFunction(searchEngine, libraryElement, name);
+ }
+ // method of class
+ if (parent is ClassDeclaration) {
+ ClassElement classElement = parent.element;
+ return validateCreateMethod(searchEngine, classElement, name);
+ }
+ // OK
+ return new Future.value(result);
+ }
+
/**
* Checks if [selectionRange] selects [Expression] which can be extracted, and
* location of this [DartExpression] in AST allows extracting.
@@ -439,6 +450,48 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
'Can only extract a single expression or a set of statements.');
}
+ /**
+ * @return the selected [DartExpression] source, with applying new parameter names.
+ */
+ String _getMethodBodySource() {
+ String source = utils.getRangeText(selectionRange);
+ // prepare operations to replace variables with parameters
+ List<SourceEdit> replaceEdits = [];
+ for (RefactoringMethodParameter parameter in _parametersMap.values) {
+ List<SourceRange> ranges = _parameterReferencesMap[parameter.id];
+ if (ranges != null) {
+ for (SourceRange range in ranges) {
+ replaceEdits.add(
+ new SourceEdit(
+ range.offset - selectionRange.offset,
+ range.length,
+ parameter.name));
+ }
+ }
+ }
+ replaceEdits.sort((a, b) => b.offset - a.offset);
+ // apply replacements
+ source = SourceEdit.applySequence(source, replaceEdits);
+ // change indentation
+ if (_selectionFunctionExpression != null) {
+ AstNode baseNode =
+ _selectionFunctionExpression.getAncestor((node) => node is Statement);
+ if (baseNode != null) {
+ String baseIndent = utils.getNodePrefix(baseNode);
+ String targetIndent = utils.getNodePrefix(_parentMember);
+ source = utils.replaceSourceIndent(source, baseIndent, targetIndent);
+ source = source.trim();
+ }
+ }
+ if (_selectionStatements != null) {
+ String selectionIndent = utils.getNodePrefix(_selectionStatements[0]);
+ String targetIndent = utils.getNodePrefix(_parentMember) + ' ';
+ source = utils.replaceSourceIndent(source, selectionIndent, targetIndent);
+ }
+ // done
+ return source;
+ }
+
_SourcePattern _getSourcePattern(SourceRange range) {
String originalSource = utils.getText(range.offset, range.length);
_SourcePattern pattern = new _SourcePattern();
@@ -484,6 +537,7 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
* Fills [_occurrences] field.
*/
void _initializeOccurrences() {
+ _occurrences.clear();
// prepare selection
_SourcePattern selectionPattern = _getSourcePattern(selectionRange);
String selectionSource =
@@ -527,8 +581,8 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
// we cannot both return variable and have explicit return statement
if (_returnType != null) {
result.addFatalError(
- "Ambiguous return value: Selected block contains assignment(s) to "
- "local variables and return statement.");
+ 'Ambiguous return value: Selected block contains assignment(s) to '
+ 'local variables and return statement.');
return result;
}
// prepare to return an assigned variable
@@ -541,12 +595,12 @@ class ExtractMethodRefactoringImpl extends RefactoringImpl implements
StringBuffer sb = new StringBuffer();
for (VariableElement variable in assignedUsedVariables) {
sb.write(variable.displayName);
- sb.write("\n");
+ sb.write('\n');
}
result.addFatalError(
format(
- "Ambiguous return value: Selected block contains more than one "
- "assignment to local variables. Affected variables are:\n\n{0}",
+ 'Ambiguous return value: Selected block contains more than one '
+ 'assignment to local variables. Affected variables are:\n\n{0}',
sb.toString().trim()));
}
// done
@@ -617,8 +671,8 @@ class _ExtractMethodAnalyzer extends StatementAnalyzer {
void handleSelectionEndsIn(AstNode node) {
super.handleSelectionEndsIn(node);
invalidSelection(
- "The selection does not cover a set of statements or an expression. "
- "Extend selection to a valid range.");
+ 'The selection does not cover a set of statements or an expression. '
+ 'Extend selection to a valid range.');
}
@override
@@ -663,17 +717,17 @@ class _ExtractMethodAnalyzer extends StatementAnalyzer {
if (_isFirstSelectedNode(node)) {
// name of declaration
if (node.inDeclarationContext()) {
- invalidSelection("Cannot extract the name part of a declaration.");
+ invalidSelection('Cannot extract the name part of a declaration.');
}
// method name
Element element = node.bestElement;
if (element is FunctionElement || element is MethodElement) {
- invalidSelection("Cannot extract a single method name.");
+ invalidSelection('Cannot extract a single method name.');
}
// name in property access
if (node.parent is PrefixedIdentifier &&
(node.parent as PrefixedIdentifier).identifier == node) {
- invalidSelection("Can not extract name part of a property access.");
+ invalidSelection('Can not extract name part of a property access.');
}
}
return null;
@@ -683,7 +737,7 @@ class _ExtractMethodAnalyzer extends StatementAnalyzer {
Object visitTypeName(TypeName node) {
super.visitTypeName(node);
if (_isFirstSelectedNode(node)) {
- invalidSelection("Cannot extract a single type reference.");
+ invalidSelection('Cannot extract a single type reference.');
}
return null;
}
@@ -693,8 +747,8 @@ class _ExtractMethodAnalyzer extends StatementAnalyzer {
super.visitVariableDeclaration(node);
if (_isFirstSelectedNode(node)) {
invalidSelection(
- "Cannot extract a variable declaration fragment. "
- "Select whole declaration statement.",
+ 'Cannot extract a variable declaration fragment. '
+ 'Select whole declaration statement.',
new Location.fromNode(node));
}
return null;
@@ -709,7 +763,7 @@ class _ExtractMethodAnalyzer extends StatementAnalyzer {
}
} while (node != null);
invalidSelection(
- "Not all selected statements are enclosed by the same parent statement.");
+ 'Not all selected statements are enclosed by the same parent statement.');
}
bool _isFirstSelectedNode(AstNode node) => identical(firstSelectedNode, node);
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698