diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java
index c7c898e1180..823e6394eff 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java
@@ -25,8 +25,10 @@ import org.jetbrains.jet.lexer.JetTokens;
public class JetParserDefinition implements ParserDefinition {
public JetParserDefinition() {
- if (!ApplicationManager.getApplication().isCommandLine()) {
- }
+ //todo: ApplicationManager.getApplication() is null during JetParsingTest setting up
+
+ /*if (!ApplicationManager.getApplication().isCommandLine()) {
+ }*/
}
@NotNull
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java
index cf8074088aa..c59d75bb54e 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java
@@ -9,7 +9,7 @@ import java.util.List;
/**
* @author max
*/
-public class JetBlockExpression extends JetExpression {
+public class JetBlockExpression extends JetExpression implements JetStatementExpression {
public JetBlockExpression(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBreakExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBreakExpression.java
index cd2037985fb..8d05f373d85 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBreakExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBreakExpression.java
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author max
*/
-public class JetBreakExpression extends JetLabelQualifiedExpression {
+public class JetBreakExpression extends JetLabelQualifiedExpression implements JetStatementExpression {
public JetBreakExpression(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassInitializer.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassInitializer.java
index a2a93ee1f48..d2c97e6270c 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassInitializer.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassInitializer.java
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author max
*/
-public class JetClassInitializer extends JetDeclaration {
+public class JetClassInitializer extends JetDeclaration implements JetStatementExpression {
public JetClassInitializer(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassObject.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassObject.java
index 4147cc3dd20..7b7b6717c5b 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassObject.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassObject.java
@@ -8,7 +8,7 @@ import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
*/
-public class JetClassObject extends JetDeclaration {
+public class JetClassObject extends JetDeclaration implements JetStatementExpression {
public JetClassObject(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java
index 7dec7aedd95..f6c124ba380 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author max
*/
-public class JetContinueExpression extends JetLabelQualifiedExpression {
+public class JetContinueExpression extends JetLabelQualifiedExpression implements JetStatementExpression {
public JetContinueExpression(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java
index 67b0b7c6b85..063085d7d8e 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java
@@ -81,4 +81,9 @@ abstract public class JetFunction extends JetTypeParameterListOwner
public JetElement asElement() {
return this;
}
+
+ public boolean isLocal() {
+ PsiElement parent = getParent();
+ return !(parent instanceof JetFile || parent instanceof JetClassBody || parent instanceof JetNamespaceBody);
+ }
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedInstanceExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedInstanceExpression.java
index 297830432d7..6832da45771 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedInstanceExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedInstanceExpression.java
@@ -7,7 +7,8 @@ import org.jetbrains.jet.JetNodeTypes;
/**
* @author abreslav
*/
-public abstract class JetLabelQualifiedInstanceExpression extends JetLabelQualifiedExpression {
+public abstract class JetLabelQualifiedInstanceExpression extends JetLabelQualifiedExpression
+ implements JetStatementExpression {
public JetLabelQualifiedInstanceExpression(@NotNull ASTNode node) {
super(node);
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLoopExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLoopExpression.java
index 1bf26d49171..9322326bd30 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLoopExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetLoopExpression.java
@@ -8,7 +8,7 @@ import org.jetbrains.jet.JetNodeTypes;
/**
* @author abreslav
*/
-public abstract class JetLoopExpression extends JetExpression {
+public abstract class JetLoopExpression extends JetExpression implements JetStatementExpression {
public JetLoopExpression(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java
index dc37a770c64..0179fab1e42 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedDeclaration.java
@@ -11,7 +11,7 @@ import org.jetbrains.jet.lexer.JetTokens;
/**
* @author max
*/
-public abstract class JetNamedDeclaration extends JetDeclaration implements PsiNameIdentifierOwner {
+public abstract class JetNamedDeclaration extends JetDeclaration implements PsiNameIdentifierOwner, JetStatementExpression {
public JetNamedDeclaration(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java
index ccacaa8a4d4..012492e54c9 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java
@@ -2,6 +2,8 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.SearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
@@ -39,6 +41,21 @@ public class JetProperty extends JetTypeParameterListOwner implements JetModifie
return getNode().findChildByType(JetTokens.VAR_KEYWORD) != null;
}
+ public boolean isLocal() {
+ PsiElement parent = getParent();
+ return !(parent instanceof JetFile || parent instanceof JetClassBody || parent instanceof JetNamespaceBody);
+ }
+
+ @NotNull
+ @Override
+ public SearchScope getUseScope() {
+ if (isLocal()) {
+ PsiElement block = PsiTreeUtil.getParentOfType(this, JetBlockExpression.class, JetClassInitializer.class);
+ if (block == null) return super.getUseScope();
+ else return new LocalSearchScope(block);
+ } else return super.getUseScope();
+ }
+
@Nullable
public JetTypeReference getReceiverTypeRef() {
ASTNode node = getNode().getFirstChildNode();
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetReturnExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetReturnExpression.java
index 396a0f22515..94177a29ea7 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetReturnExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetReturnExpression.java
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable;
/**
* @author max
*/
-public class JetReturnExpression extends JetLabelQualifiedExpression {
+public class JetReturnExpression extends JetLabelQualifiedExpression implements JetStatementExpression {
public JetReturnExpression(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSecondaryConstructor.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSecondaryConstructor.java
index 6d20610771c..accea61b0a2 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSecondaryConstructor.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSecondaryConstructor.java
@@ -12,7 +12,7 @@ import java.util.List;
/**
* @author max
*/
-public class JetSecondaryConstructor extends JetDeclaration implements JetDeclarationWithBody {
+public class JetSecondaryConstructor extends JetDeclaration implements JetDeclarationWithBody, JetStatementExpression {
public JetSecondaryConstructor(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java
index fc2d71a0772..133e8581b4c 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java
@@ -83,6 +83,14 @@ public class JetSimpleNameExpression extends JetReferenceExpression {
return ReferenceProvidersRegistry.getReferencesFromProviders(this, PsiReferenceService.Hints.NO_HINTS);
}
+ @Nullable
+ @Override
+ public PsiReference getReference() {
+ PsiReference[] references = getReferences();
+ if (references.length == 1) return references[0];
+ else return null;
+ }
+
@Override
public void accept(@NotNull JetVisitorVoid visitor) {
visitor.visitSimpleNameExpression(this);
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetStatementExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetStatementExpression.java
new file mode 100644
index 00000000000..aaa44a9ebb0
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetStatementExpression.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jet.lang.psi;
+
+/**
+ * User: Alefas
+ * Date: 31.01.12
+ */
+
+/**
+ * This is an interface to show that {@link JetExpression} is not
+ * actually an expression (in meaning that this expression can be placed after "val x = ").
+ * This is possibly redundant interface, all inheritors of this interface should be refactored that they are not
+ * {@link JetExpression}, after such refactoring, this interface can be removed.
+ */
+public interface JetStatementExpression {
+}
diff --git a/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java b/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java
index 48433f12b24..85446a53257 100644
--- a/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java
+++ b/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java
@@ -70,7 +70,8 @@ public class JetParsingTest extends ParsingTestCase {
Method[] methods = elem.getClass().getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
- if (!methodName.startsWith("get") && !methodName.startsWith("find") || methodName.equals("getReference") || methodName.equals("getReferences")) continue;
+ if (!methodName.startsWith("get") && !methodName.startsWith("find") || methodName.equals("getReference") ||
+ methodName.equals("getReferences") || methodName.equals("getUseScope")) continue;
if (method.getParameterTypes().length > 0) continue;
Class> declaringClass = method.getDeclaringClass();
if (!declaringClass.getName().startsWith("org.jetbrains.jet")) continue;
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 476da74b585..e21de172e4b 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -57,6 +57,7 @@
+
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetIntroduceHandlerBase.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetIntroduceHandlerBase.java
new file mode 100644
index 00000000000..ca3ffb8071b
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetIntroduceHandlerBase.java
@@ -0,0 +1,10 @@
+package org.jetbrains.jet.plugin.refactoring;
+
+import com.intellij.refactoring.RefactoringActionHandler;
+
+/**
+ * User: Alefas
+ * Date: 25.01.12
+ */
+public abstract class JetIntroduceHandlerBase implements RefactoringActionHandler {
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java
new file mode 100644
index 00000000000..4b676dd0a49
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java
@@ -0,0 +1,29 @@
+package org.jetbrains.jet.plugin.refactoring;
+
+import org.jetbrains.jet.lang.psi.JetExpression;
+import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.jet.lang.resolve.BindingContext;
+import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
+import org.jetbrains.jet.lang.types.JetStandardLibrary;
+import org.jetbrains.jet.lang.types.JetType;
+import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
+
+/**
+ * User: Alefas
+ * Date: 31.01.12
+ */
+public class JetNameSuggester {
+ public static String[] suggestNames(JetExpression expression) {
+ String[] def = {"i"};
+ BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) expression.getContainingFile(),
+ AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
+ JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
+ if (jetType == null) return def;
+
+ JetType booleanType = JetStandardLibrary.getJetStandardLibrary(expression.getProject()).getBooleanType();
+ if (JetTypeChecker.INSTANCE.equalTypes(jetType, booleanType)) {
+ return new String[] {"b"};
+ }
+ return new String[] {"i"}; //todo:
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.java
new file mode 100644
index 00000000000..d004617799d
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.java
@@ -0,0 +1,37 @@
+package org.jetbrains.jet.plugin.refactoring;
+
+import com.intellij.CommonBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.ResourceBundle;
+
+/**
+ * User: Alefas
+ * Date: 25.01.12
+ */
+public class JetRefactoringBundle {
+ private static Reference ourBundle;
+
+ @NonNls
+ private static final String BUNDLE = "org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle";
+
+ private JetRefactoringBundle() {
+ }
+
+ public static String message(@NonNls @PropertyKey(resourceBundle = BUNDLE)String key, Object... params) {
+ return CommonBundle.message(getBundle(), key, params);
+ }
+
+ private static ResourceBundle getBundle() {
+ ResourceBundle bundle = null;
+ if (ourBundle != null) bundle = ourBundle.get();
+ if (bundle == null) {
+ bundle = ResourceBundle.getBundle(BUNDLE);
+ ourBundle = new SoftReference(bundle);
+ }
+ return bundle;
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties
new file mode 100644
index 00000000000..3f07febfbee
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringBundle.properties
@@ -0,0 +1,5 @@
+cannot.refactor.not.expression=Cannot refactor not expression.
+expressions.title=Expressions
+introduce.variable=Introduce Variable
+cannot.refactor.no.container=Cannot refactor without refactoring container.
+cannot.refactor.no.expression=Cannot perform refactoring without an expression
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java
new file mode 100644
index 00000000000..e1165b4c97b
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.plugin.refactoring;
+
+import com.intellij.lang.refactoring.RefactoringSupportProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.refactoring.RefactoringActionHandler;
+import org.jetbrains.jet.lang.psi.JetFunction;
+import org.jetbrains.jet.lang.psi.JetProperty;
+import org.jetbrains.jet.plugin.refactoring.introduceVariable.JetIntroduceVariableHandler;
+
+/**
+ * User: Alefas
+ * Date: 25.01.12
+ */
+public class JetRefactoringSupportProvider extends RefactoringSupportProvider {
+ @Override
+ public RefactoringActionHandler getIntroduceVariableHandler() {
+ return new JetIntroduceVariableHandler();
+ }
+
+ @Override
+ public boolean isInplaceRenameAvailable(PsiElement element, PsiElement context) {
+ if (element instanceof JetProperty) {
+ JetProperty property = (JetProperty) element;
+ if (property.isLocal()) return true;
+ } else if (element instanceof JetFunction) {
+ JetFunction function = (JetFunction) element;
+ if (function.isLocal()) return true;
+ }
+ return false;
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java
new file mode 100644
index 00000000000..a6fdc87cd69
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java
@@ -0,0 +1,157 @@
+package org.jetbrains.jet.plugin.refactoring;
+
+import com.intellij.codeInsight.unwrap.ScopeHighlighter;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.ui.popup.JBPopupAdapter;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.LightweightWindowEvent;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.ui.components.JBList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.psi.*;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.*;
+import java.util.ArrayList;
+
+/**
+ * User: Alefas
+ * Date: 25.01.12
+ */
+public class JetRefactoringUtil {
+
+ private JetRefactoringUtil() {
+ }
+
+ public interface SelectExpressionCallback {
+ void run(@Nullable JetExpression expression);
+ }
+
+ public static void selectExpression(@NotNull Editor editor,
+ @NotNull PsiFile file,
+ @NotNull SelectExpressionCallback callback) throws IntroduceRefactoringException {
+ if (editor.getSelectionModel().hasSelection()) {
+ int selectionStart = editor.getSelectionModel().getSelectionStart();
+ int selectionEnd = editor.getSelectionModel().getSelectionEnd();
+ String text = file.getText();
+ while (selectionStart < selectionEnd && Character.isSpaceChar(text.charAt(selectionStart))) ++selectionStart;
+ while (selectionStart < selectionEnd && Character.isSpaceChar(text.charAt(selectionEnd - 1))) --selectionEnd;
+ callback.run(findExpression(editor, file, selectionStart, selectionEnd));
+ } else {
+ int offset = editor.getCaretModel().getOffset();
+ smartSelectExpression(editor, file, offset, callback);
+ }
+ }
+
+ private static void smartSelectExpression(@NotNull Editor editor, @NotNull PsiFile file, int offset,
+ @NotNull final SelectExpressionCallback callback)
+ throws IntroduceRefactoringException {
+ if (offset < 0) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
+ PsiElement element = file.findElementAt(offset);
+ if (element == null) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
+ if (element instanceof PsiWhiteSpace) {
+ smartSelectExpression(editor, file, offset - 1, callback);
+ return;
+ }
+ ArrayList expressions = new ArrayList();
+ while (element != null && !(element instanceof JetBlockExpression) && !(element instanceof JetNamedFunction)
+ && !(element instanceof JetClassBody) && !(element instanceof JetSecondaryConstructor)) {
+ if (element instanceof JetExpression && !(element instanceof JetStatementExpression)) {
+ expressions.add((JetExpression) element);
+ }
+ element = element.getParent();
+ }
+ if (expressions.size() == 0) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
+
+ final DefaultListModel model = new DefaultListModel();
+ for (JetExpression expression : expressions) {
+ model.addElement(expression);
+ }
+
+ final ScopeHighlighter highlighter = new ScopeHighlighter(editor);
+
+ final JList list = new JBList(model);
+
+ list.setCellRenderer(new DefaultListCellRenderer() {
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ StringBuilder buffer = new StringBuilder();
+ JetExpression element = (JetExpression) value;
+ if (element.isValid()) {
+ setText(getExpressionShortText(element));
+ }
+ return rendererComponent;
+ }
+ });
+
+ list.addListSelectionListener(new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ highlighter.dropHighlight();
+ int selectedIndex = list.getSelectedIndex();
+ if (selectedIndex < 0) return;
+ JetExpression expression = (JetExpression) model.get(selectedIndex);
+ ArrayList toExtract = new ArrayList();
+ toExtract.add(expression);
+ highlighter.highlight(expression, toExtract);
+ }
+ });
+
+ JBPopupFactory.getInstance().createListPopupBuilder(list).
+ setTitle(JetRefactoringBundle.message("expressions.title")).setMovable(false).setResizable(false).
+ setRequestFocus(true).setItemChoosenCallback(new Runnable() {
+ @Override
+ public void run() {
+ callback.run((JetExpression) list.getSelectedValue());
+ }
+ }).addListener(new JBPopupAdapter() {
+ @Override
+ public void onClosed(LightweightWindowEvent event) {
+ highlighter.dropHighlight();
+ }
+ }).createPopup().showInBestPositionFor(editor);
+
+ }
+
+ public static String getExpressionShortText(@NotNull JetExpression expression) { //todo: write appropriate implementation
+ String expressionText = expression.getText();
+ if (expressionText.length() > 20) {
+ expressionText = expressionText.substring(0, 17) + "...";
+ }
+ return expressionText;
+ }
+
+ @Nullable
+ private static JetExpression findExpression(@NotNull Editor editor, @NotNull PsiFile file,
+ int startOffset, int endOffset) throws IntroduceRefactoringException{
+ PsiElement element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JetExpression.class);
+ if (element == null || element.getTextRange().getStartOffset() != startOffset ||
+ element.getTextRange().getEndOffset() != endOffset) {
+ //todo: if it's infix expression => add (), then commit document then return new created expression
+ throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
+ } else if (!(element instanceof JetExpression)) {
+ throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
+ }
+ return (JetExpression) element;
+ }
+
+ public static class IntroduceRefactoringException extends Exception {
+ private String myMessage;
+
+ public IntroduceRefactoringException(String message) {
+ myMessage = message;
+ }
+
+ public String getMessage() {
+ return myMessage;
+ }
+ }
+
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetInplaceVariableIntroducer.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetInplaceVariableIntroducer.java
new file mode 100644
index 00000000000..c85824bf43f
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetInplaceVariableIntroducer.java
@@ -0,0 +1,46 @@
+package org.jetbrains.jet.plugin.refactoring.introduceVariable;
+
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.refactoring.introduce.inplace.InplaceVariableIntroducer;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.psi.JetExpression;
+import org.jetbrains.jet.lang.psi.JetProperty;
+
+/**
+ * User: Alefas
+ * Date: 01.02.12
+ */
+public class JetInplaceVariableIntroducer extends InplaceVariableIntroducer {
+
+ private boolean myReplaceOccurrence;
+ private JetProperty myProperty;
+
+ public JetInplaceVariableIntroducer(PsiNamedElement elementToRename, Editor editor, Project project,
+ String title, JetExpression[] occurrences,
+ @Nullable JetExpression expr, boolean replaceOccurrence,
+ JetProperty property) {
+ super(elementToRename, editor, project, title, occurrences, expr);
+ this.myReplaceOccurrence = replaceOccurrence;
+ myProperty = property;
+ }
+
+ @Override
+ protected void moveOffsetAfter(boolean success) {
+ if (!myReplaceOccurrence || myExprMarker == null) {
+ myEditor.getCaretModel().moveToOffset(myProperty.getTextRange().getEndOffset());
+ } else {
+ int startOffset = myExprMarker.getStartOffset();
+ PsiFile file = myProperty.getContainingFile();
+ PsiElement elementAt = file.findElementAt(startOffset);
+ if (elementAt != null) {
+ myEditor.getCaretModel().moveToOffset(elementAt.getTextRange().getEndOffset());
+ } else {
+ myEditor.getCaretModel().moveToOffset(myExprMarker.getEndOffset());
+ }
+ }
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java
new file mode 100644
index 00000000000..48f6d22fe02
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java
@@ -0,0 +1,313 @@
+package org.jetbrains.jet.plugin.refactoring.introduceVariable;
+
+import com.intellij.codeInsight.PsiEquivalenceUtil;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pass;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.refactoring.HelpID;
+import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
+import com.intellij.refactoring.util.CommonRefactoringUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.psi.*;
+import org.jetbrains.jet.plugin.refactoring.JetIntroduceHandlerBase;
+import org.jetbrains.jet.plugin.refactoring.JetNameSuggester;
+import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
+import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+/**
+ * User: Alefas
+ * Date: 25.01.12
+ */
+public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
+
+ private static final String INTRODUCE_VARIABLE = JetRefactoringBundle.message("introduce.variable");
+
+ @Override
+ public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, DataContext dataContext) {
+ JetRefactoringUtil.SelectExpressionCallback callback = new JetRefactoringUtil.SelectExpressionCallback() {
+ @Override
+ public void run(@Nullable JetExpression expression) {
+ doRefactoring(project, editor, expression);
+ }
+ };
+ try {
+ JetRefactoringUtil.selectExpression(editor, file, callback);
+ } catch (JetRefactoringUtil.IntroduceRefactoringException e) {
+ showErrorHint(project, editor, e.getMessage());
+ }
+ }
+
+ private static void doRefactoring(@NotNull final Project project, final Editor editor, @Nullable JetExpression _expression) {
+ if (_expression == null) {
+ showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
+ return;
+ }
+ if (_expression.getParent() instanceof JetParenthesizedExpression) {
+ _expression = (JetExpression) _expression.getParent();
+ }
+ final JetExpression expression = _expression;
+ final PsiElement container = getContainer(expression);
+ final PsiElement occurrenceContainer = getOccurrenceContainer(expression);
+ if (container == null) {
+ showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.container"));
+ return;
+ }
+ final boolean isInplaceAvailableOnDataContext =
+ editor.getSettings().isVariableInplaceRenameEnabled() &&
+ !ApplicationManager.getApplication().isUnitTestMode();
+ final ArrayList allOccurrences = findOccurrences(occurrenceContainer, expression);
+ Pass callback = new Pass() {
+ @Override
+ public void pass(OccurrencesChooser.ReplaceChoice replaceChoice) {
+ boolean replaceOccurrence = container != expression.getParent();
+ final List allReplaces;
+ if (OccurrencesChooser.ReplaceChoice.ALL == replaceChoice) {
+ if (allOccurrences.size() > 1) replaceOccurrence = true;
+ allReplaces = allOccurrences;
+ } else {
+ allReplaces = Collections.singletonList(expression);
+ }
+
+ String[] suggestedNames = JetNameSuggester.suggestNames(expression); //todo: add name validator
+ final LinkedHashSet suggestedNamesSet = new LinkedHashSet();
+ Collections.addAll(suggestedNamesSet, suggestedNames);
+ PsiElement commonParent = PsiTreeUtil.findCommonParent(allReplaces);
+ PsiElement commonContainer = getContainer(commonParent);
+ final Ref propertyRef = new Ref();
+ final ArrayList references = new ArrayList();
+ final Ref reference = new Ref();
+ final Runnable introduceRunnable = introduceVariable(project, expression, suggestedNames, allReplaces, commonContainer,
+ commonParent, replaceOccurrence, propertyRef, references,
+ reference);
+ final boolean finalReplaceOccurrence = replaceOccurrence;
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(introduceRunnable);
+ JetProperty property = propertyRef.get();
+ if (property != null) {
+ editor.getCaretModel().moveToOffset(property.getTextOffset());
+ editor.getSelectionModel().removeSelection();
+ if (isInplaceAvailableOnDataContext) {
+ JetInplaceVariableIntroducer variableIntroducer =
+ new JetInplaceVariableIntroducer(property, editor, project, INTRODUCE_VARIABLE,
+ references.toArray(new JetExpression[references.size()]),
+ reference.get(), finalReplaceOccurrence,
+ property);
+ PsiDocumentManager.getInstance(project).
+ doPostponedOperationsAndUnblockDocument(editor.getDocument());
+ variableIntroducer.performInplaceRefactoring(suggestedNamesSet);
+ }
+ }
+ }
+ }, INTRODUCE_VARIABLE, null);
+ }
+ };
+ if (isInplaceAvailableOnDataContext) {
+ OccurrencesChooser.simpleChooser(editor).
+ showChooser(expression, allOccurrences, callback);
+ } else {
+ callback.pass(OccurrencesChooser.ReplaceChoice.ALL);
+ }
+ }
+
+ private static Runnable introduceVariable(final @NotNull Project project, final JetExpression expression,
+ final String[] suggestedNames,
+ final List allReplaces, final PsiElement commonContainer,
+ final PsiElement commonParent, final boolean replaceOccurrence,
+ final Ref propertyRef,
+ final ArrayList references,
+ final Ref reference) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ String variableText = "val " + suggestedNames[0] + " = ";
+ if (expression instanceof JetParenthesizedExpression) {
+ JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression;
+ JetExpression innerExpression = parenthesizedExpression.getExpression();
+ if (innerExpression != null) variableText += innerExpression.getText();
+ else variableText += expression.getText();
+ } else variableText += expression.getText();
+ JetProperty property = JetPsiFactory.createProperty(project, variableText);
+ if (property == null) return;
+ PsiElement anchor = commonParent;
+ if (anchor != commonContainer) {
+ while (anchor.getParent() != commonContainer) {
+ anchor = anchor.getParent();
+ }
+ } else {
+ anchor = commonContainer.getFirstChild();
+ int startOffset = commonContainer.getTextRange().getEndOffset();
+ for (JetExpression expr : allReplaces) {
+ int offset = expr.getTextRange().getStartOffset();
+ if (offset < startOffset) startOffset = offset;
+ }
+ while (anchor != null && !anchor.getTextRange().contains(startOffset)) {
+ anchor = anchor.getNextSibling();
+ }
+ if (anchor == null) return;
+ }
+ boolean needBraces = !(commonContainer instanceof JetBlockExpression ||
+ commonContainer instanceof JetClassBody ||
+ commonContainer instanceof JetFile ||
+ commonContainer instanceof JetClassInitializer);
+ if (!needBraces) {
+ property = (JetProperty) commonContainer.addBefore(property, anchor);
+ commonContainer.addBefore(JetPsiFactory.createWhiteSpace(project, "\n"), anchor);
+ } else {
+ JetExpression emptyBody = JetPsiFactory.createEmptyBody(project);
+ PsiElement firstChild = emptyBody.getFirstChild();
+ emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild);
+ property = (JetProperty) emptyBody.addAfter(property, firstChild);
+ emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild);
+ anchor.replace(emptyBody);
+ }
+ for (JetExpression replace : allReplaces) {
+ if (replaceOccurrence) {
+ boolean isActualExpression = expression == replace;
+ JetExpression element = (JetExpression) replace.replace(JetPsiFactory.createExpression(project, suggestedNames[0]));
+ references.add(element);
+ if (isActualExpression) reference.set(element);
+ } else if (!needBraces) {
+ replace.delete();
+ }
+ }
+ propertyRef.set(property);
+ }
+ };
+ }
+
+ private static ArrayList findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) {
+ if (expression instanceof JetParenthesizedExpression) {
+ JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression;
+ JetExpression innerExpression = parenthesizedExpression.getExpression();
+ if (innerExpression != null) {
+ expression = innerExpression;
+ }
+ }
+ final JetExpression actualExpression = expression;
+
+ final ArrayList result = new ArrayList();
+
+ JetVisitorVoid visitor = new JetVisitorVoid() {
+ @Override
+ public void visitJetElement(JetElement element) {
+ element.acceptChildren(this);
+ super.visitJetElement(element);
+ }
+
+ @Override
+ public void visitExpression(JetExpression expression) {
+ if (PsiEquivalenceUtil.areElementsEquivalent(expression, actualExpression)) {
+ PsiElement parent = expression.getParent();
+ if (parent instanceof JetParenthesizedExpression) {
+ result.add((JetParenthesizedExpression) parent);
+ } else {
+ result.add(expression);
+ }
+ } else {
+ super.visitExpression(expression);
+ }
+ }
+ };
+ occurrenceContainer.accept(visitor);
+ return result;
+ }
+
+ @Nullable
+ private static PsiElement getContainer(PsiElement place) {
+ if (place instanceof JetBlockExpression || place instanceof JetClassBody || place instanceof JetFile ||
+ place instanceof JetClassInitializer) {
+ return place;
+ }
+ while (place != null) {
+ PsiElement parent = place.getParent();
+ if (parent instanceof JetContainerNode) {
+ if (!(parent.getParent() instanceof JetIfExpression &&
+ ((JetIfExpression) parent.getParent()).getCondition() == place)) {
+ return parent;
+ }
+ } if (parent instanceof JetBlockExpression || parent instanceof JetWhenEntry ||
+ parent instanceof JetClassBody || parent instanceof JetFile || parent instanceof JetClassInitializer) {
+ return parent;
+ } else if (parent instanceof JetNamedFunction) {
+ JetNamedFunction function = (JetNamedFunction) parent;
+ if (function.getBodyExpression() == place) {
+ return parent;
+ }
+ } else if (parent instanceof JetSecondaryConstructor) {
+ JetSecondaryConstructor secondaryConstructor = (JetSecondaryConstructor) parent;
+ if (secondaryConstructor.getBodyExpression() == place) {
+ return parent;
+ }
+ }
+ place = parent;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PsiElement getOccurrenceContainer(PsiElement place) {
+ PsiElement result = null;
+ while (place != null) {
+ PsiElement parent = place.getParent();
+ if (parent instanceof JetContainerNode) {
+ if (!(place instanceof JetBlockExpression) && !(parent.getParent() instanceof JetIfExpression &&
+ ((JetIfExpression) parent.getParent()).getCondition() == place)) {
+ result = parent;
+ }
+ } else if (parent instanceof JetClassBody || parent instanceof JetFile || parent instanceof JetClassInitializer) {
+ if (result == null) return parent;
+ else return result;
+ } else if (parent instanceof JetBlockExpression) {
+ result = parent;
+ } else if (parent instanceof JetWhenEntry ) {
+ if (!(place instanceof JetBlockExpression)) {
+ result = parent;
+ }
+ } else if (parent instanceof JetNamedFunction) {
+ JetNamedFunction function = (JetNamedFunction) parent;
+ if (function.getBodyExpression() == place) {
+ if (!(place instanceof JetBlockExpression)) {
+ result = parent;
+ }
+ }
+ } else if (parent instanceof JetSecondaryConstructor) {
+ JetSecondaryConstructor secondaryConstructor = (JetSecondaryConstructor) parent;
+ if (secondaryConstructor.getBodyExpression() == place) {
+ if (!(place instanceof JetBlockExpression)) {
+ result = parent;
+ }
+ }
+ }
+ place = parent;
+ }
+ return null;
+ }
+
+ private static void showErrorHint(Project project, Editor editor, String message) {
+ if (ApplicationManager.getApplication().isUnitTestMode()) throw new RuntimeException(message);
+ CommonRefactoringUtil.showErrorHint(project, editor, message,
+ INTRODUCE_VARIABLE,
+ HelpID.INTRODUCE_VARIABLE);
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
+ //do nothing
+ }
+}
diff --git a/idea/testData/refactoring/introduceVariable/ClassBody.kt b/idea/testData/refactoring/introduceVariable/ClassBody.kt
new file mode 100644
index 00000000000..a5bd81ba677
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/ClassBody.kt
@@ -0,0 +1,9 @@
+open class A {
+ val x = 1
+}
+/*
+open class A {
+ val i = 1
+ val x = i
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/DoWhileAddBlock.kt b/idea/testData/refactoring/introduceVariable/DoWhileAddBlock.kt
new file mode 100644
index 00000000000..6a84f39c52a
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/DoWhileAddBlock.kt
@@ -0,0 +1,14 @@
+open class A {
+ {
+ do 1 while (true)
+ }
+}
+/*
+open class A {
+ {
+ do {
+ val i = 1
+ } while (true)
+ }
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/FileLevel.kt b/idea/testData/refactoring/introduceVariable/FileLevel.kt
new file mode 100644
index 00000000000..9663d7878ad
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/FileLevel.kt
@@ -0,0 +1,5 @@
+fun x(x: Int = 1) {}
+/*
+val i = 1
+fun x(x: Int = i) {}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/FunctionAddBlock.kt b/idea/testData/refactoring/introduceVariable/FunctionAddBlock.kt
new file mode 100644
index 00000000000..8403106987d
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/FunctionAddBlock.kt
@@ -0,0 +1,6 @@
+fun x(): Int = 1
+/*
+fun x(): Int {
+ val i = 1
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/IfCondition.kt b/idea/testData/refactoring/introduceVariable/IfCondition.kt
new file mode 100644
index 00000000000..f9eeed5f999
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/IfCondition.kt
@@ -0,0 +1,11 @@
+fun a() {
+ if (true) 2
+ else 1
+}
+/*
+fun a() {
+ val b = true
+ if (b) 2
+ else 1
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/IfElseAddBlock.kt b/idea/testData/refactoring/introduceVariable/IfElseAddBlock.kt
new file mode 100644
index 00000000000..1c390070055
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/IfElseAddBlock.kt
@@ -0,0 +1,12 @@
+fun a() {
+ if (true) 2
+ else 1
+}
+/*
+fun a() {
+ if (true) 2
+ else {
+ val i = 1
+ }
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/IfThenAddBlock.kt b/idea/testData/refactoring/introduceVariable/IfThenAddBlock.kt
new file mode 100644
index 00000000000..61e5cece18f
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/IfThenAddBlock.kt
@@ -0,0 +1,11 @@
+fun a() {
+ if (true) 1
+ else 2
+}
+/*
+fun a() {
+ if (true) {
+ val i = 1
+ } else 2
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/Simple.kt b/idea/testData/refactoring/introduceVariable/Simple.kt
new file mode 100644
index 00000000000..23c4d75fe91
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/Simple.kt
@@ -0,0 +1,8 @@
+fun a() {
+ 1
+}
+/*
+fun a() {
+ val i = 1
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/WhenAddBlock.kt b/idea/testData/refactoring/introduceVariable/WhenAddBlock.kt
new file mode 100644
index 00000000000..a79b019167c
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/WhenAddBlock.kt
@@ -0,0 +1,14 @@
+fun a() {
+ when (1) {
+ is 1 -> 1
+ }
+}
+/*
+fun a() {
+ when (1) {
+ is 1 -> {
+ val i = 1
+ }
+ }
+}
+*/
\ No newline at end of file
diff --git a/idea/testData/refactoring/introduceVariable/WhileAddBlock.kt b/idea/testData/refactoring/introduceVariable/WhileAddBlock.kt
new file mode 100644
index 00000000000..49b99c3bfd1
--- /dev/null
+++ b/idea/testData/refactoring/introduceVariable/WhileAddBlock.kt
@@ -0,0 +1,14 @@
+open class A {
+ {
+ while (true) 1
+ }
+}
+/*
+open class A {
+ {
+ while (true) {
+ val i = 1
+ }
+ }
+}
+*/
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableTest.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableTest.java
new file mode 100644
index 00000000000..168e4b221a7
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableTest.java
@@ -0,0 +1,86 @@
+package org.jetbrains.jet.plugin.refactoring.introduceVariable;
+
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.jet.lexer.JetTokens;
+import org.jetbrains.jet.plugin.PluginTestCaseBase;
+
+/**
+ * User: Alefas
+ * Date: 31.01.12
+ */
+public class JetIntroduceVariableTest extends LightCodeInsightFixtureTestCase {
+ public void testClassBody() {
+ doTest();
+ }
+
+ public void testDoWhileAddBlock() {
+ doTest();
+ }
+
+ /*public void testFileLevel() {
+ doTest();
+ }
+
+ public void testFunctionAddBlock() {
+ doTest();
+ }*/
+
+ public void testIfCondition() {
+ doTest();
+ }
+
+ public void testIfElseAddBlock() {
+ doTest();
+ }
+
+ /*public void testIfThenAddBlock() {
+ doTest();
+ }*/
+
+ public void testSimple() {
+ doTest();
+ }
+
+ /*public void testWhenAddBlock() {
+ doTest();
+ }*/
+
+ public void testWhileAddBlock() {
+ doTest();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/refactoring/introduceVariable");
+ }
+
+ private void doTest() {
+ myFixture.configureByFile(getTestName(false) + ".kt");
+ final JetFile file = (JetFile) myFixture.getFile();
+ PsiElement lastChild = file.getLastChild();
+ assert lastChild != null;
+ String expectedResultText = null;
+ if (lastChild.getNode().getElementType().equals(JetTokens.BLOCK_COMMENT)) {
+ String lastChildText = lastChild.getText();
+ expectedResultText = lastChildText.substring(2, lastChildText.length() - 2).trim();
+ } else if (lastChild.getNode().getElementType().equals(JetTokens.EOL_COMMENT)) {
+ expectedResultText = lastChild.getText().substring(2).trim();
+ }
+ assert expectedResultText != null;
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ new JetIntroduceVariableHandler().invoke(getProject(), myFixture.getEditor(), file,
+ DataManager.getInstance().getDataContext(myFixture.getEditor().
+ getComponent()));
+ }
+ });
+ int endOffset = file.getLastChild().getTextRange().getStartOffset();
+ assertEquals(expectedResultText, file.getText().substring(0, endOffset).trim());
+ }
+}