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

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

Issue 10384142: Initial support for 'Extract temp' - only when single expression selected (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Use ASTVisitor as type switch Created 8 years, 7 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/ExtractUtils.java
diff --git a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/ExtractUtils.java b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/ExtractUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e0a3ee935adc94e8fccd17945da217d92ba2ff5
--- /dev/null
+++ b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/code/ExtractUtils.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2012, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.dart.tools.internal.corext.refactoring.code;
+
+import com.google.dart.compiler.ast.ASTVisitor;
+import com.google.dart.compiler.ast.DartBinaryExpression;
+import com.google.dart.compiler.ast.DartExpression;
+import com.google.dart.compiler.ast.DartInvocation;
+import com.google.dart.compiler.ast.DartLiteral;
+import com.google.dart.compiler.ast.DartNode;
+import com.google.dart.compiler.ast.DartParenthesizedExpression;
+import com.google.dart.compiler.ast.DartTypedLiteral;
+import com.google.dart.compiler.ast.DartUnaryExpression;
+import com.google.dart.compiler.resolver.Element;
+import com.google.dart.compiler.resolver.MethodElement;
+import com.google.dart.compiler.type.Type;
+import com.google.dart.compiler.util.apache.StringUtils;
+import com.google.dart.tools.core.buffer.Buffer;
+import com.google.dart.tools.core.model.CompilationUnit;
+import com.google.dart.tools.core.model.DartModelException;
+import com.google.dart.tools.core.model.SourceRange;
+import com.google.dart.tools.internal.corext.SourceRangeFactory;
+import com.google.dart.tools.ui.internal.text.SelectionAnalyzer;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * Extract Local Variable (from selected expression inside method or initializer).
+ *
+ * @coverage dart.editor.ui.refactoring.core
+ */
+public class ExtractUtils {
+ /**
+ * The default end-of-line marker for the current platform. This value should (almost) never be
+ * used directly. The end-of-line marker should always be queried from {@link Buffer} because it
+ * can differ from the platform default in some situations. The only exception is if code is being
+ * constructed for a new file, in which case there is no {@link Buffer} to ask.
+ */
+ public static final String DEFAULT_END_OF_LINE = System.getProperty("line.separator", "\n");
+
+ public static boolean covers(SourceRange sourceRange, DartNode astNode) {
+ return covers(sourceRange, SourceRangeFactory.create(astNode));
+ }
+
+ public static boolean covers(SourceRange thisRange, SourceRange otherRange) {
+ return thisRange.getOffset() <= otherRange.getOffset()
+ && getEndInclusive(thisRange) >= getEndInclusive(otherRange);
+ }
+
+ public static int getEndExclusive(SourceRange sourceRange) {
+ return sourceRange.getOffset() + sourceRange.getLength();
+ }
+
+ public static int getEndInclusive(SourceRange sourceRange) {
+ return getEndExclusive(sourceRange) - 1;
+ }
+
+ /**
+ * @return the line prefix consisting of spaces and tabs on the left from the given
+ * {@link DartNode}.
+ */
+ public static String getNodePrefix(Buffer buffer, DartNode node) {
+ int endIndex = node.getSourceInfo().getOffset();
+ int startIndex = getNodePrefixStartIndex(buffer, node);
+ return buffer.getText(startIndex, endIndex - startIndex);
+ }
+
+ /**
+ * @return the index of the last space or tab on the left from the given {@link DartNode}.
+ */
+ public static int getNodePrefixStartIndex(Buffer buffer, DartNode node) {
+ int endIndex = node.getSourceInfo().getOffset();
+ int startIndex = endIndex;
+ while (true) {
+ char c = buffer.getChar(startIndex - 1);
+ if (c != ' ' && c != '\t') {
+ break;
+ }
+ startIndex--;
+ }
+ return startIndex;
+ }
+
+ /**
+ * @return the actual type source of the given {@link DartExpression}, may be <code>null</code> if
+ * can not be resolved, should be treated as <code>Dynamic</code>.
+ */
+ public static String getTypeSource(DartExpression expression) {
+ if (expression == null) {
+ return null;
+ }
+ return expression.accept(new ASTVisitor<String>() {
+ @Override
+ public String visitBinaryExpression(DartBinaryExpression node) {
+ DartExpression arg1 = node.getArg1();
+ DartExpression arg2 = node.getArg2();
+ String type1 = getTypeSource(arg1);
+ String type2 = getTypeSource(arg2);
+ if (type1 != null && type2 != null) {
+ switch (node.getOperator()) {
+ case NE:
+ case EQ:
+ case NE_STRICT:
+ case EQ_STRICT:
+ case LT:
+ case GT:
+ case LTE:
+ case GTE:
+ case AND:
+ case OR:
+ return "bool";
+ case ADD:
+ case SUB:
+ case MUL:
+ case DIV:
+ if (type1.equals("int") && type2.equals("int")) {
+ return type1;
+ }
+ if (type1.equals("double") && type2.equals("int")) {
+ return type1;
+ }
+ if (type1.equals("int") && type2.equals("double")) {
+ return type2;
+ }
+ if (type1.equals("double") && type2.equals("double")) {
+ return type1;
+ }
+ return null;
+ case BIT_AND:
+ case BIT_OR:
+ case BIT_XOR:
+ case SAR:
+ case SHL:
+ case MOD:
+ return "int";
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String visitExpression(DartExpression node) {
+ // TODO(scheglov) variables as DartIdentifier
+ return null;
+ }
+
+ @Override
+ public String visitInvocation(DartInvocation node) {
+ Element element = node.getElement();
+ if (element instanceof MethodElement) {
+ MethodElement methodElement = (MethodElement) element;
+ Type returnType = methodElement.getReturnType();
+ return getTypeSource(returnType);
+ }
+ return null;
+ }
+
+ @Override
+ public String visitLiteral(DartLiteral node) {
+ Type literalType = node.getType();
+ return getTypeSource(literalType);
+ }
+
+ @Override
+ public String visitParenthesizedExpression(DartParenthesizedExpression node) {
+ DartExpression expr = node.getExpression();
+ return getTypeSource(expr);
+ }
+
+ @Override
+ public String visitTypedLiteral(DartTypedLiteral node) {
+ Type literalType = node.getType();
+ return getTypeSource(literalType);
+ }
+
+ @Override
+ public String visitUnaryExpression(DartUnaryExpression node) {
+ DartExpression arg = node.getArg();
+ return getTypeSource(arg);
+ }
+ });
+ }
+
+ public static boolean isSingleNodeSelected(
+ SelectionAnalyzer sa,
+ SourceRange range,
+ CompilationUnit cu) throws DartModelException {
+ return sa.getSelectedNodes().length == 1
+ && !rangeIncludesNonWhitespaceOutsideNode(range, sa.getFirstSelectedNode(), cu);
+ }
+
+ static boolean rangeIncludesNonWhitespaceOutsideRange(
+ SourceRange selection,
+ SourceRange nodes,
+ Buffer buffer) {
+ if (!covers(selection, nodes)) {
+ return false;
+ }
+
+ //TODO: skip leading comments. Consider that leading line comment must be followed by newline!
+ if (!isJustWhitespace(selection.getOffset(), nodes.getOffset(), buffer)) {
+ return true;
+ }
+ if (!isJustWhitespaceOrComment(nodes.getOffset() + nodes.getLength(), selection.getOffset()
+ + selection.getLength(), buffer)) {
+ return true;
+ }
+ return false;
+ }
+
+ private static String getTypeSource(Type returnType) {
+ String typeSource = returnType.toString();
+ typeSource = StringUtils.replace(typeSource, "<dynamic>", "Dynamic");
+ typeSource = StringUtils.replace(typeSource, "<Dynamic>", "");
+ typeSource = StringUtils.replace(typeSource, "<Dynamic, Dynamic>", "");
+ return typeSource;
+ }
+
+ private static boolean isJustWhitespace(int start, int end, Buffer buffer) {
+ if (start == end) {
+ return true;
+ }
+ Assert.isTrue(start <= end);
+ return 0 == buffer.getText(start, end - start).trim().length();
+ }
+
+ private static boolean isJustWhitespaceOrComment(int start, int end, Buffer buffer) {
+ if (start == end) {
+ return true;
+ }
+ Assert.isTrue(start <= end);
+ String trimmedText = buffer.getText(start, end - start).trim();
+ if (0 == trimmedText.length()) {
+ return true;
+ } else {
+ // TODO(scheglov) support comment
+ return false;
+// IScanner scanner = ToolFactory.createScanner(false, false, false, null);
+// scanner.setSource(trimmedText.toCharArray());
+// try {
+// return scanner.getNextToken() == ITerminalSymbols.TokenNameEOF;
+// } catch (InvalidInputException e) {
+// return false;
+// }
+ }
+ }
+
+ private static boolean rangeIncludesNonWhitespaceOutsideNode(
+ SourceRange range,
+ DartNode node,
+ CompilationUnit cu) throws DartModelException {
+ return rangeIncludesNonWhitespaceOutsideRange(
+ range,
+ SourceRangeFactory.create(node),
+ cu.getBuffer());
+ }
+
+}

Powered by Google App Engine
This is Rietveld 408576698