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

Unified Diff: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/InlineMethodRefactoring.java

Issue 10823372: 'Inline Method' refactoring (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 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
Index: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/InlineMethodRefactoring.java
diff --git a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/InlineMethodRefactoring.java b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/InlineMethodRefactoring.java
index 10d14d9279cdceb1fa8518e6c75dc6fc7b6bf023..27348406ea99bfb0fe64b425e16ad189e2dcae1a 100644
--- a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/InlineMethodRefactoring.java
+++ b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/InlineMethodRefactoring.java
@@ -16,8 +16,10 @@ package com.google.dart.tools.internal.corext.refactoring.code;
import static com.google.dart.tools.core.dom.PropertyDescriptorHelper.DART_CLASS_MEMBER_NAME;
import static com.google.dart.tools.core.dom.PropertyDescriptorHelper.getLocationInParent;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import com.google.dart.compiler.ast.ASTVisitor;
import com.google.dart.compiler.ast.DartBinaryExpression;
import com.google.dart.compiler.ast.DartBlock;
@@ -28,23 +30,33 @@ import com.google.dart.compiler.ast.DartMethodDefinition;
import com.google.dart.compiler.ast.DartNode;
import com.google.dart.compiler.ast.DartReturnStatement;
import com.google.dart.compiler.ast.DartStatement;
+import com.google.dart.compiler.ast.DartThisExpression;
import com.google.dart.compiler.ast.DartUnit;
import com.google.dart.compiler.common.SourceInfo;
+import com.google.dart.compiler.resolver.ClassElement;
+import com.google.dart.compiler.resolver.Elements;
+import com.google.dart.compiler.resolver.FieldElement;
import com.google.dart.compiler.resolver.VariableElement;
+import com.google.dart.compiler.util.apache.StringUtils;
import com.google.dart.tools.core.dom.NodeFinder;
import com.google.dart.tools.core.internal.util.SourceRangeUtils;
import com.google.dart.tools.core.model.CompilationUnit;
+import com.google.dart.tools.core.model.DartElement;
import com.google.dart.tools.core.model.DartFunction;
import com.google.dart.tools.core.model.DartModelException;
import com.google.dart.tools.core.model.SourceRange;
+import com.google.dart.tools.core.model.Type;
import com.google.dart.tools.core.search.SearchMatch;
import com.google.dart.tools.core.utilities.compiler.DartCompilerUtilities;
import com.google.dart.tools.internal.corext.SourceRangeFactory;
import com.google.dart.tools.internal.corext.dom.ASTNodes;
import com.google.dart.tools.internal.corext.refactoring.RefactoringCoreMessages;
+import com.google.dart.tools.internal.corext.refactoring.base.DartStatusContext;
import com.google.dart.tools.internal.corext.refactoring.changes.TextChangeCompatibility;
+import com.google.dart.tools.internal.corext.refactoring.rename.FunctionLocalElement;
import com.google.dart.tools.internal.corext.refactoring.rename.RenameAnalyzeUtil;
import com.google.dart.tools.internal.corext.refactoring.util.TextChangeManager;
+import com.google.dart.tools.ui.internal.util.DartModelUtil;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -59,6 +71,7 @@ import org.eclipse.text.edits.ReplaceEdit;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
/**
* Inlines a method in a compilation unit based on a text selection range.
@@ -71,30 +84,75 @@ public class InlineMethodRefactoring extends Refactoring {
INLINE_SINGLE;
}
-// private static class AAA {
-// int zzz = 5;
-//
-// void bar() {
-// AAA aaa = new AAA();
-// int c = foo(1, 2);
-// }
-//
-// int foo(int a, int b) {
-// return zzz + a + b;
-// }
-// }
-
private static class ParameterOccurrence {
- final int parentOperatorPrecedence;
+ final int parentPrecedence;
final SourceRange range;
- public ParameterOccurrence(int parentOperatorPrecedence, SourceRange range) {
- this.parentOperatorPrecedence = parentOperatorPrecedence;
+ public ParameterOccurrence(int parentPrecedence, SourceRange range) {
+ this.parentPrecedence = parentPrecedence;
this.range = range;
}
}
- private static final String EMPTY = ""; //$NON-NLS-1$
+ /**
+ * Information about part of the source in {@link #methodUnit}.
+ */
+ private static class SourcePart {
+ private final SourceRange baseRange;
+ final String source;
+ final String prefix;
+ final Map<Integer, List<ParameterOccurrence>> parameters = Maps.newHashMap();
+ final Map<VariableElement, List<SourceRange>> variables = Maps.newHashMap();
+ final List<SourceRange> instanceFieldQualifiers = Lists.newArrayList();
+ final Map<String, List<SourceRange>> staticFieldQualifiers = Maps.newHashMap();
+
+ public SourcePart(SourceRange baseRange, String source, String prefix) {
+ this.baseRange = baseRange;
+ this.source = source;
+ this.prefix = prefix;
+ }
+
+ public void addInstanceFieldQualifier(SourceRange range) {
+ range = SourceRangeFactory.fromBase(range, baseRange);
+ instanceFieldQualifiers.add(range);
+ }
+
+ public void addParameterOccurrence(int index, SourceRange range, int precedence) {
+ if (index != -1) {
+ List<ParameterOccurrence> occurrences = parameters.get(index);
+ if (occurrences == null) {
+ occurrences = Lists.newArrayList();
+ parameters.put(index, occurrences);
+ }
+ range = SourceRangeFactory.fromBase(range, baseRange);
+ occurrences.add(new ParameterOccurrence(precedence, range));
+ }
+ }
+
+ public void addStaticFieldQualifier(String className, SourceRange range) {
+ List<SourceRange> ranges = staticFieldQualifiers.get(className);
+ if (ranges == null) {
+ ranges = Lists.newArrayList();
+ staticFieldQualifiers.put(className, ranges);
+ }
+ range = SourceRangeFactory.fromBase(range, baseRange);
+ ranges.add(range);
+ }
+
+ public void addVariable(VariableElement element, SourceRange range) {
+ List<SourceRange> ranges = variables.get(element);
+ if (ranges == null) {
+ ranges = Lists.newArrayList();
+ variables.put(element, ranges);
+ }
+ range = SourceRangeFactory.fromBase(range, baseRange);
+ ranges.add(range);
+ }
+ }
+
+ private static ReplaceEdit createReplaceEdit(SourceRange range, String text) {
+ return new ReplaceEdit(range.getOffset(), range.getLength(), text);
+ }
/**
* @return {@link #getExpressionPrecedence(DartNode)} for parent node.
@@ -122,14 +180,13 @@ public class InlineMethodRefactoring extends Refactoring {
private final TextChangeManager changeManager = new TextChangeManager(true);
private boolean deleteSource;
- private Mode fInitialMode;
- private Mode fCurrentMode;
+ private Mode initialMode;
+ private Mode currentMode;
private ExtractUtils methodUtils;
private DartMethodDefinition methodNode;
- private Map<Integer, List<ParameterOccurrence>> methodParameterRanges = Maps.newHashMap();
- private DartExpression methodExpression;
-
- private String methodExpressionSource;
+ private ClassElement methodClassElement;
+ private SourcePart methodExpressionPart;
+ private SourcePart methodStatementsPart;
public InlineMethodRefactoring(DartFunction method, CompilationUnit selectionUnit,
int selectionOffset) {
@@ -145,73 +202,71 @@ public class InlineMethodRefactoring extends Refactoring {
@Override
public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
- pm.beginTask(RefactoringCoreMessages.InlineMethodRefactoring_processing, 3);
- pm.subTask(EMPTY);
-
RefactoringStatus result = new RefactoringStatus();
-
+ // begin task
+ pm.beginTask(RefactoringCoreMessages.InlineMethodRefactoring_processing, 3);
+ pm.subTask(StringUtils.EMPTY);
+ // find references
+ List<SearchMatch> references;
+ {
+ SubProgressMonitor pm2 = new SubProgressMonitor(pm, 1);
+ references = RenameAnalyzeUtil.getReferences(method, pm2);
+ }
// replace all references
- List<SearchMatch> references = RenameAnalyzeUtil.getReferences(method, new SubProgressMonitor(
- pm,
- 1));
for (SearchMatch reference : references) {
CompilationUnit refUnit = reference.getElement().getAncestor(CompilationUnit.class);
+ TextChange refChange = changeManager.get(refUnit);
ExtractUtils utils = new ExtractUtils(refUnit);
// prepare invocation
DartNode coveringNode = NodeFinder.find(
utils.getUnitNode(),
reference.getSourceRange().getOffset(),
0).getCoveringNode();
- DartInvocation invocationNode = ASTNodes.getAncestor(coveringNode, DartInvocation.class);
+ DartInvocation invocation = ASTNodes.getAncestor(coveringNode, DartInvocation.class);
// we need invocation
- if (invocationNode != null) {
+ if (invocation != null) {
+ DartStatement invocationStatement = ASTNodes.getAncestor(invocation, DartStatement.class);
+ SourceRange invocationLineRange = utils.getLinesRange(ImmutableList.of(invocationStatement));
+ String refPrefix = utils.getNodePrefix(invocationStatement);
// may be only single place should be inlined
- SourceRange invocationRange = SourceRangeFactory.create(invocationNode);
- if (fCurrentMode == Mode.INLINE_SINGLE) {
+ SourceRange invocationRange = SourceRangeFactory.create(invocation);
+ if (currentMode == Mode.INLINE_SINGLE) {
if (!SourceRangeUtils.contains(invocationRange, selectionOffset)) {
continue;
}
}
- // prepare arguments
- List<DartExpression> arguments = invocationNode.getArguments();
- // replace invocation with inlined expression XXX
- List<ReplaceEdit> edits = Lists.newArrayList();
- for (Entry<Integer, List<ParameterOccurrence>> entry : methodParameterRanges.entrySet()) {
- int parameterIndex = entry.getKey();
- // prepare argument
- DartExpression argument = arguments.get(parameterIndex);
- int argumentPrecedence = getExpressionPrecedence(argument);
- String argumentSource = utils.getText(argument);
- // replace all occurrences of this argument
- for (ParameterOccurrence occurrence : entry.getValue()) {
- SourceRange range = occurrence.range;
- // prepare argument source to apply at this occurrence
- String occurrenceArgumentSource;
- if (argumentPrecedence > occurrence.parentOperatorPrecedence) {
- occurrenceArgumentSource = argumentSource;
- } else {
- occurrenceArgumentSource = "(" + argumentSource + ")";
- }
- // do replace
- edits.add(new ReplaceEdit(
- range.getOffset(),
- range.getLength(),
- occurrenceArgumentSource));
- }
+ // insert non-return statements
+ if (methodStatementsPart != null) {
+ // prepare statements source for invocation
+ String source = getMethodSourceForInvocation(methodStatementsPart, utils, invocation);
+ source = utils.getIndentSource(source, methodStatementsPart.prefix, refPrefix);
+ // do insert
+ SourceRange range = SourceRangeFactory.forStartLength(invocationLineRange, 0);
+ TextChangeCompatibility.addTextEdit(
+ refChange,
+ RefactoringCoreMessages.InlineMethodRefactoring_replace_references,
+ new ReplaceEdit(range.getOffset(), range.getLength(), source));
+ }
+ // replace invocation with return expression
+ if (methodExpressionPart != null) {
+ // prepare expression source for invocation
+ String source = getMethodSourceForInvocation(methodExpressionPart, utils, invocation);
+ // do replace
+ SourceRange sourceRange = invocationRange;
+ TextChangeCompatibility.addTextEdit(
+ refChange,
+ RefactoringCoreMessages.InlineMethodRefactoring_replace_references,
+ new ReplaceEdit(sourceRange.getOffset(), sourceRange.getLength(), source));
+ } else {
+ TextChangeCompatibility.addTextEdit(
+ refChange,
+ RefactoringCoreMessages.InlineMethodRefactoring_replace_references,
+ new ReplaceEdit(invocationLineRange.getOffset(), invocationLineRange.getLength(), ""));
}
- // prepare source with applied arguments
- String source = ExtractUtils.applyReplaceEdits(methodExpressionSource, edits);
- // replace this reference
- TextChange change = changeManager.get(refUnit);
- SourceRange sourceRange = invocationRange;
- TextChangeCompatibility.addTextEdit(
- change,
- RefactoringCoreMessages.InlineMethodRefactoring_replace_references,
- new ReplaceEdit(sourceRange.getOffset(), sourceRange.getLength(), source));
}
}
- // delete source
- if (deleteSource) {
+ // delete method
+ if (deleteSource && currentMode == Mode.INLINE_ALL) {
SourceInfo methodSI = methodNode.getSourceInfo();
int lineThisIndex = methodUtils.getLineThisIndex(methodSI.getOffset());
int lineNextIndex = methodUtils.getLineNextIndex(methodSI.getEnd());
@@ -222,15 +277,6 @@ public class InlineMethodRefactoring extends Refactoring {
new ReplaceEdit(lineThisIndex, lineNextIndex - lineThisIndex, ""));
}
- // XXX
-// RefactoringStatus result = checkMethodName();
-// pm.worked(1);
-//
-// result.merge(checkParameterNames());
-// pm.worked(1);
-//
-// result.merge(checkPossibleConflicts(new SubProgressMonitor(pm, 1)));
-
pm.done();
return result;
}
@@ -239,15 +285,15 @@ public class InlineMethodRefactoring extends Refactoring {
public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
try {
pm.beginTask("", 4); //$NON-NLS-1$
- RefactoringStatus result = new RefactoringStatus();
+ final RefactoringStatus result = new RefactoringStatus();
// prepare mode
{
DartUnit selectionUnitNode = DartCompilerUtilities.resolveUnit(selectionUnit);
DartNode node = NodeFinder.perform(selectionUnitNode, selectionOffset, 0);
boolean methodNameSelected = getLocationInParent(node) == DART_CLASS_MEMBER_NAME;
- fInitialMode = fCurrentMode = methodNameSelected ? Mode.INLINE_ALL : Mode.INLINE_SINGLE;
+ initialMode = currentMode = methodNameSelected ? Mode.INLINE_ALL : Mode.INLINE_SINGLE;
}
- // XXX
+ // prepare "methodX" information
{
methodUtils = new ExtractUtils(methodUnit);
DartNode methodNameNode = NodeFinder.find(
@@ -255,43 +301,43 @@ public class InlineMethodRefactoring extends Refactoring {
method.getNameRange().getOffset(),
0).getCoveringNode();
methodNode = ASTNodes.getAncestor(methodNameNode, DartMethodDefinition.class);
- if (methodNode == null) {
- return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineMethodRefactoring_cannotFindMethodDeclaration);
+ if (methodNode.getElement().getEnclosingElement() instanceof ClassElement) {
+ methodClassElement = (ClassElement) methodNode.getElement().getEnclosingElement();
}
- // TODO(scheglov) only "return expression;" support right now
- {
- DartBlock body = methodNode.getFunction().getBody();
- List<DartStatement> statements = body.getStatements();
- if (statements.size() != 1 || !(statements.get(0) instanceof DartReturnStatement)) {
- return RefactoringStatus.createFatalErrorStatus("Only methods with single 'return' are supported right now.");
+ // analyze method body
+ DartBlock body = methodNode.getFunction().getBody();
+ List<DartStatement> statements = body.getStatements();
+ if (statements.size() >= 1) {
+ DartStatement lastStatement = statements.get(statements.size() - 1);
+ // "return" statement requires special handling
+ if (lastStatement instanceof DartReturnStatement) {
+ DartExpression methodExpression = ((DartReturnStatement) lastStatement).getValue();
+ SourceRange methodExpressionRange = SourceRangeFactory.create(methodExpression);
+ methodExpressionPart = createSourcePart(methodExpressionRange);
+ // exclude "return" statement from statements
+ statements = ImmutableList.copyOf(statements).subList(0, statements.size() - 1);
+ }
+ // if there are statements, process them
+ if (statements.size() > 1) {
+ SourceRange statementsRange = methodUtils.getLinesRange(statements);
+ methodStatementsPart = createSourcePart(statementsRange);
}
- methodExpression = ((DartReturnStatement) statements.get(0)).getValue();
- methodExpressionSource = methodUnit.getSource().substring(
- methodExpression.getSourceInfo().getOffset(),
- methodExpression.getSourceInfo().getEnd());
- methodExpression.accept(new ASTVisitor<Void>() {
- @Override
- public Void visitIdentifier(DartIdentifier node) {
- VariableElement parameterElement = ASTNodes.getParameterElement(node);
- if (parameterElement != null) {
- int parameterIndex = ASTNodes.getParameterIndex(parameterElement);
- if (parameterIndex != -1) {
- List<ParameterOccurrence> occurrences = methodParameterRanges.get(parameterIndex);
- if (occurrences == null) {
- occurrences = Lists.newArrayList();
- methodParameterRanges.put(parameterIndex, occurrences);
- }
- int methodExpressionOffset = methodExpression.getSourceInfo().getOffset();
- SourceRange nodeRange = SourceRangeFactory.fromBase(node, methodExpressionOffset);
- occurrences.add(new ParameterOccurrence(
- getExpressionParentPrecedence(node),
- nodeRange));
- }
- }
- return null;
- }
- });
}
+ // check if we support such body
+ body.accept(new ASTVisitor<Void>() {
+ private int numReturns = 0;
+
+ @Override
+ public Void visitReturnStatement(DartReturnStatement node) {
+ numReturns++;
+ if (numReturns == 2) {
+ result.addError(
+ RefactoringCoreMessages.InlineMethodRefactoring_multipleReturns,
+ DartStatusContext.create(methodUnit, node));
+ }
+ return super.visitReturnStatement(node);
+ }
+ });
}
// done
return result;
@@ -311,7 +357,7 @@ public class InlineMethodRefactoring extends Refactoring {
}
public Mode getInitialMode() {
- return fInitialMode;
+ return initialMode;
}
public DartFunction getMethod() {
@@ -324,25 +370,7 @@ public class InlineMethodRefactoring extends Refactoring {
}
public RefactoringStatus setCurrentMode(Mode mode) throws DartModelException {
- if (fCurrentMode == mode) {
- return new RefactoringStatus();
- }
- // TODO(scheglov)
-// Assert.isTrue(getInitialMode() == Mode.INLINE_SINGLE);
- fCurrentMode = mode;
-// if (mode == Mode.INLINE_SINGLE) {
-// if (fInitialNode instanceof MethodInvocation)
-// fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (MethodInvocation)fInitialNode);
-// else if (fInitialNode instanceof SuperMethodInvocation)
-// fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (SuperMethodInvocation)fInitialNode);
-// else if (fInitialNode instanceof ConstructorInvocation)
-// fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (ConstructorInvocation)fInitialNode);
-// else
-// throw new IllegalStateException(String.valueOf(fInitialNode));
-// } else {
-// fTargetProvider= TargetProvider.create(fSourceProvider.getDeclaration());
-// }
-// return fTargetProvider.checkActivation();
+ currentMode = mode;
return new RefactoringStatus();
}
@@ -350,4 +378,206 @@ public class InlineMethodRefactoring extends Refactoring {
this.deleteSource = delete;
}
+ private SourcePart createSourcePart(final SourceRange sourceRange) throws DartModelException {
+ final SourcePart result;
+ {
+ String source = getMethodUnitSource(sourceRange);
+ String prefix = ExtractUtils.getLinesPrefix(source);
+ result = new SourcePart(sourceRange, source, prefix);
+ }
+ // remember parameters and variables occurrences
+ methodUtils.getUnitNode().accept(new ASTVisitor<Void>() {
+ @Override
+ public Void visitIdentifier(DartIdentifier node) {
+ addInstanceFieldQualifier(node);
+ addParameter(node);
+ addVariable(node);
+ return null;
+ }
+
+ @Override
+ public Void visitNode(DartNode node) {
+ SourceRange nodeRange = SourceRangeFactory.create(node);
+ if (!SourceRangeUtils.intersects(sourceRange, nodeRange)) {
+ return null;
+ }
+ return super.visitNode(node);
+ }
+
+ private void addInstanceFieldQualifier(DartIdentifier node) {
+ FieldElement fieldElement = ASTNodes.getFieldElement(node);
+ if (isMethodClassField(fieldElement)) {
+ if (Elements.isStaticField(fieldElement)) {
+ String className = fieldElement.getEnclosingElement().getName();
+ if (ASTNodes.getNodeQualifier(node) == null) {
+ SourceRange qualifierRange = SourceRangeFactory.forStartLength(node, 0);
+ result.addStaticFieldQualifier(className, qualifierRange);
+ }
+ } else {
+ SourceRange qualifierRange;
+ DartThisExpression qualifier = ASTNodes.getThisQualifier(node);
+ if (qualifier != null) {
+ qualifierRange = SourceRangeFactory.forStartStart(qualifier, node);
+ } else {
+ qualifierRange = SourceRangeFactory.forStartLength(node, 0);
+ }
+ result.addInstanceFieldQualifier(qualifierRange);
+ }
+ }
+ }
+
+ private void addParameter(DartIdentifier node) {
+ VariableElement parameterElement = ASTNodes.getParameterElement(node);
+ if (parameterElement != null) {
+ int parameterIndex = ASTNodes.getParameterIndex(parameterElement);
+ if (parameterIndex != -1) {
+ SourceRange nodeRange = SourceRangeFactory.create(node);
+ int parentPrecedence = getExpressionParentPrecedence(node);
+ result.addParameterOccurrence(parameterIndex, nodeRange, parentPrecedence);
+ }
+ }
+ }
+
+ private void addVariable(DartIdentifier node) {
+ VariableElement variableElement = ASTNodes.getVariableElement(node);
+ if (variableElement != null) {
+ SourceRange nodeRange = SourceRangeFactory.create(node);
+ result.addVariable(variableElement, nodeRange);
+ }
+ }
+ });
+ // done
+ return result;
+ }
+
+ /**
+ * @return the source which should replace given {@link DartInvocation}.
+ */
+ private String getMethodSourceForInvocation(SourcePart part, ExtractUtils utils,
+ DartInvocation invocation) throws DartModelException {
+ // prepare arguments
+ List<DartExpression> arguments = invocation.getArguments();
+ // prepare edits to replace parameters with arguments
+ List<ReplaceEdit> edits = Lists.newArrayList();
+ for (Entry<Integer, List<ParameterOccurrence>> entry : part.parameters.entrySet()) {
+ int parameterIndex = entry.getKey();
+ // prepare argument
+ DartExpression argument = arguments.get(parameterIndex);
+ int argumentPrecedence = getExpressionPrecedence(argument);
+ String argumentSource = utils.getText(argument);
+ // replace all occurrences of this parameter
+ for (ParameterOccurrence occurrence : entry.getValue()) {
+ SourceRange range = occurrence.range;
+ // prepare argument source to apply at this occurrence
+ String occurrenceArgumentSource;
+ if (argumentPrecedence < occurrence.parentPrecedence) {
+ occurrenceArgumentSource = "(" + argumentSource + ")";
+ } else {
+ occurrenceArgumentSource = argumentSource;
+ }
+ // do replace
+ edits.add(createReplaceEdit(range, occurrenceArgumentSource));
+ }
+ }
+ // replace static field "qualifier" with invocation target
+ for (Entry<String, List<SourceRange>> entry : part.staticFieldQualifiers.entrySet()) {
+ String className = entry.getKey();
+ for (SourceRange range : entry.getValue()) {
+ edits.add(createReplaceEdit(range, className + "."));
+ }
+ }
+ // replace instance field "qualifier" with invocation target
+ {
+ DartExpression targetExpression = invocation.getTarget();
+ String targetSource = utils.getText(targetExpression) + ".";
+ for (SourceRange qualifierRange : part.instanceFieldQualifiers) {
+ edits.add(createReplaceEdit(qualifierRange, targetSource));
+ }
+ }
+ // prepare edits to replace conflicting variables
+ Set<String> conflictingNames = getNamesConflictingWithLocal(utils.getUnit(), invocation);
+ for (Entry<VariableElement, List<SourceRange>> entry : part.variables.entrySet()) {
+ String originalName = entry.getKey().getName();
+ // prepare unique name
+ String uniqueName;
+ {
+ uniqueName = originalName;
+ int uniqueIndex = 2;
+ while (conflictingNames.contains(uniqueName)) {
+ uniqueName = originalName + uniqueIndex;
+ uniqueIndex++;
+ }
+ }
+ // update references, if name was change
+ if (!StringUtils.equals(uniqueName, originalName)) {
+ for (SourceRange range : entry.getValue()) {
+ edits.add(createReplaceEdit(range, uniqueName));
+ }
+ }
+ }
+ // prepare source with applied arguments
+ return ExtractUtils.applyReplaceEdits(part.source, edits);
+ }
+
+ /**
+ * @return the part of source from {@link #methodUnit}.
+ */
+ private String getMethodUnitSource(SourceRange range) throws DartModelException {
+ int start = range.getOffset();
+ int end = start + range.getLength();
+ return methodUnit.getSource().substring(start, end);
+ }
+
+ /**
+ * @return the names which will shadow or will be shadowed by any declaration at "node".
+ */
+ private Set<String> getNamesConflictingWithLocal(CompilationUnit unit, DartNode node)
+ throws DartModelException {
+ Set<String> result = Sets.newHashSet();
+ // prepare offsets
+ int offset = node.getSourceInfo().getOffset();
+ SourceRange offsetRange;
+ {
+ DartBlock block = ASTNodes.getAncestor(node, DartBlock.class);
+ int endOffset = block.getSourceInfo().getEnd();
+ offsetRange = SourceRangeFactory.forStartEnd(offset, endOffset);
+ }
+ // local variables and functions
+ {
+ DartFunction function = DartModelUtil.getElementContaining(unit, DartFunction.class, offset);
+ if (function != null) {
+ for (FunctionLocalElement element : RenameAnalyzeUtil.getFunctionLocalElements(function)) {
+ SourceRange variableRange = element.getVisibleRange();
+ if (SourceRangeUtils.intersects(variableRange, offsetRange)) {
+ result.add(element.getElementName());
+ }
+ }
+ }
+ }
+ // fields
+ {
+ Type enclosingType = DartModelUtil.getElementContaining(unit, Type.class, offset);
+ if (enclosingType != null) {
+ Set<Type> superTypes = RenameAnalyzeUtil.getSuperTypes(enclosingType);
+ Set<Type> types = Sets.newHashSet(superTypes);
+ types.add(enclosingType);
+ for (Type type : types) {
+ for (DartElement typeChild : type.getChildren()) {
+ result.add(typeChild.getElementName());
+ }
+ }
+ }
+ }
+ // done
+ return result;
+ }
+
+ /**
+ * @return <code>true</code> if given {@link FieldElement} is a field of
+ * {@link #methodClassElement} or one of its super-classes.
+ */
+ private boolean isMethodClassField(FieldElement field) {
+ return field != null && Elements.hasClassMember(methodClassElement, field.getName());
+ }
+
}

Powered by Google App Engine
This is Rietveld 408576698