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

Unified Diff: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/correction/QuickFixProcessor.java

Issue 10834222: Initial implementation of 'Create Method' quick fix (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Use resolveUnit() in ASTProvider 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/ui/internal/text/correction/QuickFixProcessor.java
diff --git a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/correction/QuickFixProcessor.java b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/correction/QuickFixProcessor.java
index eb491d13b39ca3ed066e7fbb2aee949e41f628ac..d153b01b47c5b79e5c8558459042a9fe855b78ee 100644
--- a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/correction/QuickFixProcessor.java
+++ b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/correction/QuickFixProcessor.java
@@ -13,23 +13,38 @@
*/
package com.google.dart.tools.ui.internal.text.correction;
+import static com.google.dart.tools.core.dom.PropertyDescriptorHelper.DART_VARIABLE_VALUE;
+import static com.google.dart.tools.core.dom.PropertyDescriptorHelper.getLocationInParent;
+
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import com.google.dart.compiler.ErrorCode;
import com.google.dart.compiler.ast.DartDirective;
+import com.google.dart.compiler.ast.DartExpression;
import com.google.dart.compiler.ast.DartIdentifier;
import com.google.dart.compiler.ast.DartImportDirective;
+import com.google.dart.compiler.ast.DartInvocation;
import com.google.dart.compiler.ast.DartLibraryDirective;
+import com.google.dart.compiler.ast.DartMethodDefinition;
import com.google.dart.compiler.ast.DartMethodInvocation;
import com.google.dart.compiler.ast.DartNode;
import com.google.dart.compiler.ast.DartTypeNode;
import com.google.dart.compiler.ast.DartUnit;
+import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
+import com.google.dart.compiler.ast.DartVariable;
import com.google.dart.compiler.resolver.ClassElement;
import com.google.dart.compiler.resolver.Element;
import com.google.dart.compiler.resolver.MethodElement;
+import com.google.dart.compiler.resolver.ResolverErrorCode;
import com.google.dart.compiler.resolver.TypeErrorCode;
+import com.google.dart.compiler.type.Type;
+import com.google.dart.compiler.type.TypeKind;
import com.google.dart.compiler.util.apache.StringUtils;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.dom.PropertyDescriptorHelper;
+import com.google.dart.tools.core.dom.StructuralPropertyDescriptor;
+import com.google.dart.tools.core.dom.rewrite.TrackedNodePosition;
import com.google.dart.tools.core.internal.model.EditorLibraryManager;
import com.google.dart.tools.core.internal.model.SystemLibraryManagerProvider;
import com.google.dart.tools.core.model.CompilationUnit;
@@ -41,12 +56,17 @@ import com.google.dart.tools.core.model.SourceRange;
import com.google.dart.tools.core.refactoring.CompilationUnitChange;
import com.google.dart.tools.core.utilities.compiler.DartCompilerUtilities;
import com.google.dart.tools.internal.corext.SourceRangeFactory;
+import com.google.dart.tools.internal.corext.codemanipulation.StubUtility;
+import com.google.dart.tools.internal.corext.dom.ASTNodes;
import com.google.dart.tools.internal.corext.refactoring.code.ExtractUtils;
import com.google.dart.tools.internal.corext.refactoring.util.ExecutionUtils;
import com.google.dart.tools.internal.corext.refactoring.util.Messages;
import com.google.dart.tools.internal.corext.refactoring.util.RunnableEx;
import com.google.dart.tools.ui.DartPluginImages;
import com.google.dart.tools.ui.internal.text.correction.proposals.CUCorrectionProposal;
+import com.google.dart.tools.ui.internal.text.correction.proposals.LinkedCorrectionProposal;
+import com.google.dart.tools.ui.internal.text.correction.proposals.SourceBuilder;
+import com.google.dart.tools.ui.internal.text.correction.proposals.TrackedPositions;
import com.google.dart.tools.ui.text.dart.IDartCompletionProposal;
import com.google.dart.tools.ui.text.dart.IInvocationContext;
import com.google.dart.tools.ui.text.dart.IProblemLocation;
@@ -62,6 +82,9 @@ import org.eclipse.text.edits.TextEdit;
import java.net.URI;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
/**
* Standard {@link IQuickFixProcessor} for Dart.
@@ -71,18 +94,40 @@ import java.util.List;
public class QuickFixProcessor implements IQuickFixProcessor {
private static final int DEFAULT_RELEVANCE = 50;
+// private static ReplaceEdit createInsertEdit(int offset, String text) {
+// return new ReplaceEdit(offset, 0, text);
+// }
+//
+// private static ReplaceEdit createRemoveEdit(SourceRange range) {
+// return createReplaceEdit(range, "");
+// }
+
private static ReplaceEdit createReplaceEdit(SourceRange range, String text) {
return new ReplaceEdit(range.getOffset(), range.getLength(), text);
}
+ /**
+ * @return the suggestions for given {@link Type} and {@link DartExpression}, not empty.
+ */
+ private static String[] getArgumentNameSuggestions(Set<String> excluded, Type type,
+ DartExpression expression, int index) {
+ String[] suggestions = StubUtility.getVariableNameSuggestions(type, expression, excluded);
+ if (suggestions.length != 0) {
+ return suggestions;
+ }
+ return new String[] {"arg" + index};
+ }
+
private CompilationUnit unit;
private ExtractUtils utils;
private DartNode node;
private final List<ICommandAccess> proposals = Lists.newArrayList();
-
- private final List<TextEdit> textEdits = Lists.newArrayList();
private int proposalRelevance = DEFAULT_RELEVANCE;
+ private final List<TextEdit> textEdits = Lists.newArrayList();
+ private final Map<String, List<TrackedNodePosition>> linkedPositions = Maps.newHashMap();
+
+ private LinkedCorrectionProposal proposal;
@Override
public IDartCompletionProposal[] getCorrections(IInvocationContext context,
@@ -98,6 +143,9 @@ public class QuickFixProcessor implements IQuickFixProcessor {
@Override
public void run() throws Exception {
ErrorCode errorCode = location.getProblemId();
+ if (errorCode == ResolverErrorCode.CANNOT_RESOLVE_METHOD) {
+ addFix_createUnresolvedMethod(location);
+ }
if (errorCode == TypeErrorCode.IS_STATIC_METHOD_IN) {
addFix_useStaticAccess_method(location);
}
@@ -105,6 +153,7 @@ public class QuickFixProcessor implements IQuickFixProcessor {
addFix_importLibrary_withType(location);
}
}
+
});
}
}
@@ -113,10 +162,106 @@ public class QuickFixProcessor implements IQuickFixProcessor {
@Override
public boolean hasCorrections(CompilationUnit unit, ErrorCode errorCode) {
- return errorCode == TypeErrorCode.IS_STATIC_METHOD_IN
+ return errorCode == ResolverErrorCode.CANNOT_RESOLVE_METHOD
+ || errorCode == TypeErrorCode.IS_STATIC_METHOD_IN
|| errorCode == TypeErrorCode.NO_SUCH_TYPE;
}
+ private void addFix_createUnresolvedMethod(IProblemLocation location) {
+ if (node instanceof DartIdentifier && node.getParent() instanceof DartUnqualifiedInvocation) {
+ String name = ((DartIdentifier) node).getName();
+ DartUnqualifiedInvocation invocation = (DartUnqualifiedInvocation) node.getParent();
+ DartMethodDefinition enclosingMethod = ASTNodes.getAncestor(node, DartMethodDefinition.class);
+ // prepare environment
+ String eol = utils.getEndOfLine();
+ String prefix = utils.getNodePrefix(enclosingMethod);
+ //
+ SourceRange range = SourceRangeFactory.forEndLength(enclosingMethod, 0);
+ SourceBuilder sb = new SourceBuilder(range);
+ {
+ sb.append(eol + eol + prefix);
+ // may be return type
+ {
+ Type type = addFix_createUnresolvedMethod_getReturnType(invocation);
+ if (type != null) {
+ sb.startPosition("RETURN_TYPE");
+ sb.append(ExtractUtils.getTypeSource(type));
+ sb.endPosition();
+ sb.append(" ");
+ }
+ }
+ // append name
+ {
+ sb.startPosition("NAME");
+ sb.append(name);
+ sb.endPosition();
+ }
+ // append parameters
+ sb.append("(");
+ Set<String> excluded = Sets.newHashSet();
+ List<DartExpression> arguments = invocation.getArguments();
+ for (int i = 0; i < arguments.size(); i++) {
+ DartExpression argument = arguments.get(i);
+ // append separator
+ if (i != 0) {
+ sb.append(", ");
+ }
+ // append type name
+ Type type = argument.getType();
+ if (type != null) {
+ String typeSource = ExtractUtils.getTypeSource(type);
+ {
+ sb.startPosition("TYPE" + i);
+ sb.append(typeSource);
+ sb.endPosition();
+ }
+ sb.append(" ");
+ }
+ // append parameter name
+ {
+ sb.startPosition("ARG" + i);
+ String[] suggestions = getArgumentNameSuggestions(excluded, type, argument, i);
+ sb.append(suggestions[0]);
+ sb.endPosition();
+ }
+ }
+ sb.append(") {" + eol + prefix + "}");
+ }
+ // insert source
+ addReplaceEdit(range, sb.toString());
+ addLinkedPosition("NAME", TrackedPositions.forNode(node));
+ addLinkedPositions(sb);
+ // add proposal
+ addUnitCorrectionProposal(
+ unit,
+ TextFileChange.FORCE_SAVE,
+ Messages.format(CorrectionMessages.QuickFixProcessor_addMethod_topLevel, name),
+ DartPluginImages.get(DartPluginImages.IMG_CORRECTION_CHANGE));
+ }
+ // TODO
+// foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28);
+// foo(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8);
+// foo("0", "1");
+// foo(true, false);
+ }
+
+ /**
+ * @return the possible return {@link Type}, may be <code>null</code> if can not be identified.
+ * {@link TypeKind#DYNAMIC} also returned as <code>null</code>.
+ */
+ private Type addFix_createUnresolvedMethod_getReturnType(DartInvocation invocation) {
+ Type type = null;
+ StructuralPropertyDescriptor invocationLocation = getLocationInParent(invocation);
+ if (invocationLocation == DART_VARIABLE_VALUE) {
+ DartVariable variable = (DartVariable) invocation.getParent();
+ type = variable.getElement().getType();
+ }
+ if (TypeKind.of(type) == TypeKind.DYNAMIC) {
+ type = null;
+ }
+ return type;
+ }
+
private void addFix_importLibrary_withType(IProblemLocation location) throws Exception {
if (node instanceof DartIdentifier && node.getParent() instanceof DartTypeNode) {
String typeName = ((DartIdentifier) node).getName();
@@ -136,7 +281,7 @@ public class QuickFixProcessor implements IQuickFixProcessor {
String prefix = imp.getPrefix();
if (!StringUtils.isEmpty(prefix) && imp.getLibrary().findType(typeName) != null) {
SourceRange range = SourceRangeFactory.forStartLength(node, 0);
- textEdits.add(createReplaceEdit(range, prefix + "."));
+ addReplaceEdit(range, prefix + ".");
// add proposal
proposalRelevance++;
addUnitCorrectionProposal(
@@ -204,7 +349,7 @@ public class QuickFixProcessor implements IQuickFixProcessor {
}
// insert new #import
String importSource = prefix + "#import('" + importPath + "');" + suffix;
- textEdits.add(createReplaceEdit(range, importSource));
+ addReplaceEdit(range, importSource);
// add proposal
addUnitCorrectionProposal(
libraryUnit,
@@ -241,13 +386,59 @@ public class QuickFixProcessor implements IQuickFixProcessor {
String className) {
// replace "target" with class name
SourceRange range = SourceRangeFactory.create(invocation.getTarget());
- textEdits.add(createReplaceEdit(range, className));
+ addReplaceEdit(range, className);
// add proposal
addUnitCorrectionProposal(
Messages.format(CorrectionMessages.QuickFixProcessor_useStaticAccess_method, className),
DartPluginImages.get(DartPluginImages.IMG_CORRECTION_CHANGE));
}
+// private void addInsertEdit(int offset, String text) {
+// textEdits.add(createInsertEdit(offset, text));
+// }
+
+ private void addLinkedPosition(String group, TrackedNodePosition position) {
+ List<TrackedNodePosition> positions = linkedPositions.get(group);
+ if (positions == null) {
+ positions = Lists.newArrayList();
+ linkedPositions.put(group, positions);
+ }
+ positions.add(position);
+ }
+
+ /**
+ * Adds positions from the given {@link SourceBuilder} to the {@link #linkedPositions}.
+ */
+ private void addLinkedPositions(SourceBuilder builder) {
+ Map<String, List<TrackedNodePosition>> builderPositions = builder.getTrackedPositions();
+ for (Entry<String, List<TrackedNodePosition>> entry : builderPositions.entrySet()) {
+ String groupId = entry.getKey();
+ for (TrackedNodePosition position : entry.getValue()) {
+ addLinkedPosition(groupId, position);
+ }
+ }
+ }
+
+ /**
+ * Adds {@link #linkedPositions} to the current {@link #proposal}.
+ */
+ private void addLinkedPositionsToProposal() {
+ for (Entry<String, List<TrackedNodePosition>> entry : linkedPositions.entrySet()) {
+ String groupId = entry.getKey();
+ for (TrackedNodePosition position : entry.getValue()) {
+ proposal.addLinkedPosition(position, false, groupId);
+ }
+ }
+ }
+
+// private void addRemoveEdit(SourceRange range) {
+// textEdits.add(createRemoveEdit(range));
+// }
+
+ private void addReplaceEdit(SourceRange range, String text) {
+ textEdits.add(createReplaceEdit(range, text));
+ }
+
/**
* Adds new {@link CUCorrectionProposal} using given "unit" and {@link #textEdits}.
*/
@@ -263,7 +454,9 @@ public class QuickFixProcessor implements IQuickFixProcessor {
}
// add proposal
if (!textEdits.isEmpty()) {
- proposals.add(new CUCorrectionProposal(label, unit, change, proposalRelevance, image));
+ proposal = new LinkedCorrectionProposal(label, unit, change, proposalRelevance, image);
+ addLinkedPositionsToProposal();
+ proposals.add(proposal);
}
// done
resetProposalElements();
@@ -296,6 +489,7 @@ public class QuickFixProcessor implements IQuickFixProcessor {
*/
private void resetProposalElements() {
textEdits.clear();
+ linkedPositions.clear();
proposalRelevance = DEFAULT_RELEVANCE;
}
}

Powered by Google App Engine
This is Rietveld 408576698