diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml
index bd98166afb02..0f77daa4edaf 100644
--- a/python/src/META-INF/python-core-common.xml
+++ b/python/src/META-INF/python-core-common.xml
@@ -416,6 +416,7 @@
+
diff --git a/python/src/com/jetbrains/python/codeInsight/implement/PyImplementMethodsHandler.kt b/python/src/com/jetbrains/python/codeInsight/implement/PyImplementMethodsHandler.kt
new file mode 100644
index 000000000000..665e97fe15dc
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/implement/PyImplementMethodsHandler.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.jetbrains.python.codeInsight.implement
+
+import com.intellij.lang.LanguageCodeInsightActionHandler
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiFile
+import com.jetbrains.python.codeInsight.override.PyOverrideImplementUtil
+import com.jetbrains.python.psi.PyFile
+import com.jetbrains.python.psi.types.TypeEvalContext
+
+class PyImplementMethodsHandler : LanguageCodeInsightActionHandler {
+
+ override fun isValidFor(editor: Editor?, file: PsiFile?): Boolean {
+ return editor != null && file is PyFile && PyOverrideImplementUtil.getContextClass(editor, file) != null
+ }
+
+ override fun invoke(project: Project, editor: Editor, file: PsiFile) {
+ val cls = PyOverrideImplementUtil.getContextClass(editor, file)
+ if (cls != null) {
+ PyOverrideImplementUtil.chooseAndImplementMethods(project, editor, cls, TypeEvalContext.codeCompletion(project, file))
+ }
+ }
+
+ override fun startInWriteAction() = false
+}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
index 462133aa869a..15abbecdaf10 100644
--- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
@@ -35,6 +35,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.SpeedSearchComparator;
+import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyFunctionBuilder;
@@ -43,7 +44,10 @@ import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
/**
* @author Alexey.Ivanov
@@ -70,46 +74,54 @@ public class PyOverrideImplementUtil {
return pyClass;
}
- public static void chooseAndOverrideMethods(final Project project, @NotNull final Editor editor, @NotNull final PyClass pyClass) {
-
-
+ public static void chooseAndOverrideMethods(@NotNull Project project,
+ @NotNull Editor editor,
+ @NotNull PyClass cls,
+ @NotNull TypeEvalContext context) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT);
- chooseAndOverrideOrImplementMethods(project, editor, pyClass);
- }
-
- private static void chooseAndOverrideOrImplementMethods(final Project project,
- @NotNull final Editor editor,
- @NotNull final PyClass pyClass) {
- PyPsiUtils.assertValid(pyClass);
+ PyPsiUtils.assertValid(cls);
ApplicationManager.getApplication().assertReadAccessAllowed();
- final Set result = new HashSet<>();
- TypeEvalContext context = TypeEvalContext.codeCompletion(project, null);
- final Collection superFunctions = getAllSuperFunctions(pyClass, context);
-
-
- result.addAll(superFunctions);
- chooseAndOverrideOrImplementMethods(project, editor, pyClass, result, "Select Methods to Override", false);
+ chooseAndOverrideOrImplementMethods(project, editor, cls, getAllSuperMethods(cls, context), false);
}
- public static void chooseAndOverrideOrImplementMethods(@NotNull final Project project,
- @NotNull final Editor editor,
- @NotNull final PyClass pyClass,
- @NotNull final Collection superFunctions,
- @NotNull final String title, final boolean implement) {
- List elements = new ArrayList<>();
- for (PyFunction function : superFunctions) {
- final String name = function.getName();
+ public static void chooseAndImplementMethods(@NotNull Project project,
+ @NotNull Editor editor,
+ @NotNull PyClass cls,
+ @NotNull TypeEvalContext context) {
+ chooseAndImplementMethods(project, editor, cls, getAllSuperAbstractMethods(cls, context));
+ }
+
+ public static void chooseAndImplementMethods(@NotNull Project project,
+ @NotNull Editor editor,
+ @NotNull PyClass cls,
+ @NotNull Collection methods) {
+ FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT);
+
+ PyPsiUtils.assertValid(cls);
+ ApplicationManager.getApplication().assertReadAccessAllowed();
+
+ chooseAndOverrideOrImplementMethods(project, editor, cls, methods, true);
+ }
+
+ private static void chooseAndOverrideOrImplementMethods(@NotNull Project project,
+ @NotNull Editor editor,
+ @NotNull PyClass cls,
+ @NotNull Collection methods,
+ boolean implement) {
+ final List elements = new ArrayList<>();
+ for (PyFunction method : methods) {
+ final String name = method.getName();
if (name == null || PyUtil.isClassPrivateName(name)) {
continue;
}
- if (pyClass.findMethodByName(name, false, null) == null) {
- final PyMethodMember member = new PyMethodMember(function);
+ if (cls.findMethodByName(name, false, null) == null) {
+ final PyMethodMember member = new PyMethodMember(method);
elements.add(member);
}
}
- if (elements.size() == 0) {
+ if (elements.isEmpty()) {
return;
}
@@ -126,14 +138,13 @@ public class PyOverrideImplementUtil {
};
}
};
- chooser.setTitle(title);
+ chooser.setTitle(implement ? "Select Methods to Implement" : "Select Methods to Override");
chooser.setCopyJavadocVisible(false);
chooser.show();
if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
return;
}
- List membersToOverride = chooser.getSelectedElements();
- overrideMethods(editor, pyClass, membersToOverride, implement);
+ overrideMethods(editor, cls, chooser.getSelectedElements(), implement);
}
public static void overrideMethods(final Editor editor, final PyClass pyClass, final List membersToOverride,
@@ -326,11 +337,26 @@ public class PyOverrideImplementUtil {
return toClass.getName();
}
+ @NotNull
+ public static List getAllSuperAbstractMethods(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
+ return ContainerUtil.filter(getAllSuperMethods(cls, context), method -> isAbstractMethodForClass(method, cls, context));
+ }
+
+ private static boolean isAbstractMethodForClass(@NotNull PyFunction method, @NotNull PyClass cls, @NotNull TypeEvalContext context) {
+ final String methodName = method.getName();
+ if (methodName == null ||
+ cls.findMethodByName(methodName, false, context) != null ||
+ cls.findClassAttribute(methodName, false, context) != null) {
+ return false;
+ }
+ return PyUtil.isDecoratedAsAbstract(method) || raisesNotImplementedError(method);
+ }
+
/**
* Returns all super functions available through MRO.
*/
@NotNull
- public static List getAllSuperFunctions(@NotNull PyClass pyClass, @NotNull TypeEvalContext context) {
+ public static List getAllSuperMethods(@NotNull PyClass pyClass, @NotNull TypeEvalContext context) {
final Map functions = Maps.newLinkedHashMap();
for (final PyClassLikeType type : pyClass.getAncestorTypes(context)) {
if (type != null) {
diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideMethodsHandler.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideMethodsHandler.java
index c7e4d4195a6a..4e3ae62cd59b 100644
--- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideMethodsHandler.java
+++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideMethodsHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,23 +21,28 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NotNull;
/**
* @author Alexey.Ivanov
*/
public class PyOverrideMethodsHandler implements LanguageCodeInsightActionHandler {
+
+ @Override
public boolean isValidFor(Editor editor, PsiFile file) {
return (file instanceof PyFile) && (PyOverrideImplementUtil.getContextClass(editor, file) != null);
}
+ @Override
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
- PyClass aClass = PyOverrideImplementUtil.getContextClass(editor, file);
+ final PyClass aClass = PyOverrideImplementUtil.getContextClass(editor, file);
if (aClass != null) {
- PyOverrideImplementUtil.chooseAndOverrideMethods(project, editor, aClass);
+ PyOverrideImplementUtil.chooseAndOverrideMethods(project, editor, aClass, TypeEvalContext.userInitiated(project, file));
}
}
+ @Override
public boolean startInWriteAction() {
return false;
}
diff --git a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java
index a6bf2f1ea85e..a781634f9c22 100644
--- a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,6 @@ import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -62,18 +61,12 @@ public class PyAbstractClassInspection extends PyInspection {
if (isAbstract(pyClass)) {
return;
}
- final Set toBeImplemented = new HashSet<>();
- final Collection functions = PyOverrideImplementUtil.getAllSuperFunctions(pyClass, myTypeEvalContext);
- for (PyFunction method : functions) {
- if (isAbstractMethodForClass(method, pyClass)) {
- toBeImplemented.add(method);
- }
- }
+ final Set toImplement = new HashSet<>(PyOverrideImplementUtil.getAllSuperAbstractMethods(pyClass, myTypeEvalContext));
final ASTNode nameNode = pyClass.getNameNode();
- if (!toBeImplemented.isEmpty() && nameNode != null) {
+ if (!toImplement.isEmpty() && nameNode != null) {
registerProblem(nameNode.getPsi(),
PyBundle.message("INSP.NAME.abstract.class.$0.must.implement", pyClass.getName()),
- new PyImplementMethodsQuickFix(pyClass, toBeImplemented));
+ new PyImplementMethodsQuickFix(pyClass, toImplement));
}
}
@@ -95,15 +88,5 @@ public class PyAbstractClassInspection extends PyInspection {
}
return false;
}
-
- private static boolean isAbstractMethodForClass(@NotNull PyFunction method, @NotNull PyClass cls) {
- final String methodName = method.getName();
- if (methodName == null ||
- cls.findMethodByName(methodName, false, null) != null ||
- cls.findClassAttribute(methodName, false, null) != null) {
- return false;
- }
- return PyUtil.isDecoratedAsAbstract(method) || PyOverrideImplementUtil.raisesNotImplementedError(method);
- }
}
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyImplementMethodsQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyImplementMethodsQuickFix.java
index 2ad01a3fbf48..e0c8358ecb64 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/PyImplementMethodsQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/PyImplementMethodsQuickFix.java
@@ -21,6 +21,7 @@ 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.util.containers.ContainerUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.override.PyMethodMember;
import com.jetbrains.python.codeInsight.override.PyOverrideImplementUtil;
@@ -29,15 +30,15 @@ import com.jetbrains.python.psi.PyFunction;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
import java.util.Set;
public class PyImplementMethodsQuickFix extends LocalQuickFixOnPsiElement {
+ @NotNull
private final Set myToImplement;
- public PyImplementMethodsQuickFix(PyClass aClass, Set toImplement) {
- super(aClass);
+ public PyImplementMethodsQuickFix(@NotNull PyClass cls, @NotNull Set toImplement) {
+ super(cls);
myToImplement = toImplement;
}
@@ -47,6 +48,7 @@ public class PyImplementMethodsQuickFix extends LocalQuickFixOnPsiElement {
return PyBundle.message("QFIX.NAME.implement.methods");
}
+ @Override
@NonNls
@NotNull
public String getFamilyName() {
@@ -59,17 +61,10 @@ public class PyImplementMethodsQuickFix extends LocalQuickFixOnPsiElement {
if (editor != null && startElement instanceof PyClass) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
- ArrayList list = new ArrayList<>();
- for (PyFunction function: myToImplement) {
- list.add(new PyMethodMember(function));
- }
- PyOverrideImplementUtil.overrideMethods(editor, (PyClass)startElement, list, true);
+ PyOverrideImplementUtil.overrideMethods(editor, (PyClass)startElement, ContainerUtil.map(myToImplement, PyMethodMember::new), true);
}
else {
- PyOverrideImplementUtil
- .chooseAndOverrideOrImplementMethods(project, editor,
- (PyClass)startElement, myToImplement,
- "Select Methods to Implement", true);
+ PyOverrideImplementUtil.chooseAndImplementMethods(project, editor, (PyClass)startElement, myToImplement);
}
}
}