diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 45be9da4c5ec..1a4e4a37a36f 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -179,6 +179,7 @@ + @@ -318,13 +319,6 @@ - - - - - - + + + + + + + + + + + + + + - + diff --git a/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java b/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java index d03ccf784b27..573c3004a577 100644 --- a/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java +++ b/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java @@ -5,15 +5,14 @@ import com.intellij.codeInsight.template.TemplateBuilder; import com.intellij.codeInsight.template.TemplateBuilderFactory; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.lang.Language; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.psi.PsiElement; import com.intellij.util.Function; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; -import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -89,30 +88,27 @@ public class AddFieldQuickFix implements LocalQuickFix { public static PsiElement addFieldToInit(Project project, PyClass cls, String item_name, Function callback) { if (cls != null && item_name != null) { PyFunction init = cls.findMethodByName(PyNames.INIT, false); - Language language = cls.getLanguage(); - if (language instanceof PythonLanguage) { - if (init != null) { - return appendToInit(init, callback); + if (init != null) { + return appendToInit(init, callback); + } + else { // no init! boldly copy ancestor's. + for (PyClass ancestor : cls.iterateAncestors()) { + init = ancestor.findMethodByName(PyNames.INIT, false); + if (init != null) break; } - else { // no init! boldly copy ancestor's. - for (PyClass ancestor : cls.iterateAncestors()) { - init = ancestor.findMethodByName(PyNames.INIT, false); - if (init != null) break; - } - PyFunction new_init = createInitMethod(project, cls, init); + PyFunction new_init = createInitMethod(project, cls, init); - appendToInit(new_init, callback); + appendToInit(new_init, callback); - PsiElement add_anchor = null; - PyFunction[] meths = cls.getMethods(); - if (meths.length > 0) add_anchor = meths[0].getPrevSibling(); - PyStatementList cls_content = cls.getStatementList(); - new_init = (PyFunction) cls_content.addAfter(new_init, add_anchor); + PsiElement add_anchor = null; + PyFunction[] meths = cls.getMethods(); + if (meths.length > 0) add_anchor = meths[0].getPrevSibling(); + PyStatementList cls_content = cls.getStatementList(); + new_init = (PyFunction) cls_content.addAfter(new_init, add_anchor); - PyUtil.showBalloon(project, PyBundle.message("QFIX.added.constructor.$0.for.field.$1", cls.getName(), item_name), MessageType.INFO); - return new_init.getStatementList().getStatements()[0]; - //else // well, that can't be - } + PyUtil.showBalloon(project, PyBundle.message("QFIX.added.constructor.$0.for.field.$1", cls.getName(), item_name), MessageType.INFO); + return new_init.getStatementList().getStatements()[0]; + //else // well, that can't be } } return null; @@ -124,7 +120,8 @@ public class AddFieldQuickFix implements LocalQuickFix { String paramList = ancestorInit != null ? ancestorInit.getParameterList().getText() : "(self)"; String functionText = "def " + PyNames.INIT + paramList + ":\n"; - if (cls.isNewStyleClass() && ancestorInit != null) { + if (cls.isNewStyleClass() && ancestorInit != null && + ancestorInit.getContainingClass() != PyBuiltinCache.getInstance(ancestorInit).getClass("object")) { // form the super() call StringBuffer sb = new StringBuffer("super("); sb.append(cls.getName()); diff --git a/python/src/com/jetbrains/python/codeInsight/PyClassInsertHandler.java b/python/src/com/jetbrains/python/codeInsight/PyClassInsertHandler.java index 8a6fa8fd4dd2..c679f7f0428a 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyClassInsertHandler.java +++ b/python/src/com/jetbrains/python/codeInsight/PyClassInsertHandler.java @@ -1,8 +1,10 @@ package com.jetbrains.python.codeInsight; import com.intellij.codeInsight.AutoPopupController; +import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -36,5 +38,8 @@ public class PyClassInsertHandler implements InsertHandler { editor.getCaretModel().moveToOffset(offset+2); } } + else if (context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { + TailType.SMART_COMPLETION.processTail(editor, context.getTailOffset()); + } } } diff --git a/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java index 8a6f6a387c8b..6f2849b5ef8c 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java @@ -12,6 +12,7 @@ import com.intellij.util.Processor; import com.intellij.util.Query; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; +import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; @@ -136,6 +137,9 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator @Nullable private static LineMarkerInfo getMethodMarker(final PsiElement element, final PyFunction function) { + if (PyNames.INIT.equals(function.getName())) { + return null; + } final PsiElement superMethod = PySuperMethodsSearch.search(function).findFirst(); if (superMethod != null) { PyClass superClass = null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java index 07ae89a8e1db..e4c48842e628 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java @@ -100,7 +100,7 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl { PyExpression qualifier = myElement.getQualifier(); assert qualifier != null; - PyType qualifierType = qualifier.getType(TypeEvalContext.fast()); + PyType qualifierType = qualifier.getType(TypeEvalContext.slow()); ProcessingContext ctx = new ProcessingContext(); final Set names_already = new HashSet(); ctx.put(PyType.CTX_NAMES, names_already); diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java index 7f2108804c43..0a573d939b92 100644 --- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java +++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java @@ -10,13 +10,16 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.IntroduceTargetChooser; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.*; @@ -28,6 +31,7 @@ import com.jetbrains.python.refactoring.PyRefactoringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -106,6 +110,11 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { element1 = file.findElementAt(document.getLineStartOffset(lineNumber)); element2 = file.findElementAt(document.getLineEndOffset(lineNumber) - 1); } + if (element1 == null || element2 == null || PyRefactoringUtil.getSelectedExpression(project, file, element1, element2) == null) { + if (smartIntroduce(file, editor, name, replaceAll, hasConstructor)) { + return; + } + } } if (element1 == null || element2 == null) { CommonRefactoringUtil.showErrorHint(project, editor, PyBundle.message("refactoring.introduce.selection.error"), myDialogTitle, @@ -120,11 +129,53 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { return; } - if (!checkEnabled(project, editor, element1, myDialogTitle)) { + performActionOnElement(editor, element1, name, replaceAll, hasConstructor); + } + + private boolean smartIntroduce(final PsiFile file, final Editor editor, final String name, final boolean replaceAll, final boolean hasConstructor) { + int offset = editor.getCaretModel().getOffset(); + PsiElement elementAtCaret = file.findElementAt(offset); + final List expressions = new ArrayList(); + while (elementAtCaret != null) { + if (elementAtCaret instanceof PyStatement) { + break; + } + if (elementAtCaret instanceof PyExpression) { + expressions.add((PyExpression)elementAtCaret); + } + elementAtCaret = elementAtCaret.getParent(); + } + if (expressions.size() == 1) { + performActionOnElement(editor, expressions.get(0), name, replaceAll, hasConstructor); + return true; + } + else if (expressions.size() > 1) { + IntroduceTargetChooser.showChooser(editor, expressions, new Pass() { + @Override + public void pass(PyExpression pyExpression) { + performActionOnElement(editor, pyExpression, name, replaceAll, hasConstructor); + } + }, new Function() { + public String fun(PyExpression pyExpression) { + return pyExpression.getText(); + } + }); + return true; + } + return false; + } + + private void performActionOnElement(Editor editor, + PsiElement element, + String name, + boolean replaceAll, + boolean hasConstructor) { + final Project project = element.getProject(); + if (!checkEnabled(project, editor, element, myDialogTitle)) { return; } - final PyExpression expression = (PyExpression)element1; + final PyExpression expression = (PyExpression)element; final List occurrences; if (expression.getUserData(PyPsiUtils.SELECTION_BREAKS_AST_NODE) == null && !(expression instanceof PyCallExpression)) { diff --git a/python/testData/optimizeImports/importStarOneOfMultiple.after.py b/python/testData/optimizeImports/importStarOneOfMultiple.after.py index 1e6589a19e4c..d98696221063 100644 --- a/python/testData/optimizeImports/importStarOneOfMultiple.after.py +++ b/python/testData/optimizeImports/importStarOneOfMultiple.after.py @@ -1,2 +1,3 @@ from re import compile + compile \ No newline at end of file diff --git a/python/testData/optimizeImports/oneOfMultiple.after.py b/python/testData/optimizeImports/oneOfMultiple.after.py index 24d13554fc54..db49e72a894d 100644 --- a/python/testData/optimizeImports/oneOfMultiple.after.py +++ b/python/testData/optimizeImports/oneOfMultiple.after.py @@ -1,2 +1,3 @@ import sys + print sys.argv