mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
Quick fix to set abc.ABCMeta as metaclass (PY-30789)
This commit is contained in:
@@ -211,6 +211,7 @@ public class PyNames {
|
||||
public static final String ABSTRACTPROPERTY = "abstractproperty";
|
||||
public static final String ABC_META_CLASS = "ABCMeta";
|
||||
public static final String ABC = "abc.ABC";
|
||||
public static final String ABC_META = "abc.ABCMeta";
|
||||
|
||||
public static final String TUPLE = "tuple";
|
||||
public static final String SET = "set";
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.jetbrains.python.codeInsight.typing.PyProtocolsKt;
|
||||
import com.jetbrains.python.inspections.quickfix.PyImplementMethodsQuickFix;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.types.PyClassLikeType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -52,7 +53,11 @@ public class PyAbstractClassInspection extends PyInspection {
|
||||
final List<PyFunction> toImplement = PyOverrideImplementUtil.getAllSuperAbstractMethods(pyClass, myTypeEvalContext);
|
||||
final ASTNode nameNode = pyClass.getNameNode();
|
||||
if (!toImplement.isEmpty() && nameNode != null) {
|
||||
final SmartList<LocalQuickFix> quickFixes = new SmartList<>(new PyImplementMethodsQuickFix(pyClass, toImplement));
|
||||
final SmartList<LocalQuickFix> quickFixes = new SmartList<>(
|
||||
new PyImplementMethodsQuickFix(pyClass, toImplement),
|
||||
new SetABCMetaAsMetaclassQuickFix()
|
||||
);
|
||||
|
||||
if (LanguageLevel.forElement(pyClass).isPy3K()) {
|
||||
quickFixes.add(new AddABCToSuperclassesQuickFix());
|
||||
}
|
||||
@@ -101,5 +106,27 @@ public class PyAbstractClassInspection extends PyInspection {
|
||||
PyClassRefactoringUtil.addSuperclasses(project, cls, abcClass);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SetABCMetaAsMetaclassQuickFix implements LocalQuickFix {
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Set '" + PyNames.ABC_META + "' as metaclass";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PyClass cls = PyUtil.as(descriptor.getPsiElement().getParent(), PyClass.class);
|
||||
if (cls == null) return;
|
||||
|
||||
final PyClass abcMetaClass = PyPsiFacade.getInstance(project).createClassByQName(PyNames.ABC_META, cls);
|
||||
if (abcMetaClass == null) return;
|
||||
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated(cls.getProject(), cls.getContainingFile());
|
||||
PyClassRefactoringUtil.addMetaClassIfNotExist(cls, abcMetaClass, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1509,11 +1509,9 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final String abcMeta = "abc." + PyNames.ABC_META_CLASS;
|
||||
|
||||
return classTypes
|
||||
.stream()
|
||||
.filter(t -> !abcMeta.equals(t.getClassQName()))
|
||||
.filter(t -> !PyNames.ABC_META.equals(t.getClassQName()))
|
||||
.max(
|
||||
(t1, t2) -> {
|
||||
if (Objects.equals(t1, t2)) {
|
||||
|
||||
@@ -116,7 +116,7 @@ class MethodsManager extends MembersManager<PyFunction> {
|
||||
final Project project = aClass.getProject();
|
||||
final PsiFile file = aClass.getContainingFile();
|
||||
|
||||
final PyClass abcMetaClass = PyPsiFacade.getInstance(project).createClassByQName("abc." + PyNames.ABC_META_CLASS, aClass);
|
||||
final PyClass abcMetaClass = PyPsiFacade.getInstance(project).createClassByQName(PyNames.ABC_META, aClass);
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated(project, file);
|
||||
|
||||
if (abcMetaClass != null && PyClassRefactoringUtil.addMetaClassIfNotExist(aClass, abcMetaClass, context)) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from PyAbstractClassInspection.quickFix.SetABCMetaAsMetaclassPy3.main_import import A1
|
||||
|
||||
class A<caret>2(A1):
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
from abc import ABCMeta
|
||||
|
||||
from PyAbstractClassInspection.quickFix.SetABCMetaAsMetaclassPy3.main_import import A1
|
||||
|
||||
class A2(A1, metaclass=ABCMeta):
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
import abc
|
||||
|
||||
class A1(metaclass=abc.ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def m1(self):
|
||||
pass
|
||||
@@ -0,0 +1,12 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
class A1:
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def m1(self):
|
||||
pass
|
||||
|
||||
class A<caret>2(A1):
|
||||
pass
|
||||
@@ -0,0 +1,12 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
class A1:
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def m1(self):
|
||||
pass
|
||||
|
||||
class A2(A1):
|
||||
__metaclass__ = ABCMeta
|
||||
@@ -0,0 +1,9 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
class A1(metaclass=ABCMeta):
|
||||
@abstractmethod
|
||||
def m1(self):
|
||||
pass
|
||||
|
||||
class A<caret>2(A1):
|
||||
pass
|
||||
@@ -0,0 +1,9 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
class A1(metaclass=ABCMeta):
|
||||
@abstractmethod
|
||||
def m1(self):
|
||||
pass
|
||||
|
||||
class A2(A1, metaclass=ABCMeta):
|
||||
pass
|
||||
@@ -161,6 +161,29 @@ public class Py3QuickFixTest extends PyTestCase {
|
||||
true);
|
||||
}
|
||||
|
||||
// PY-30789
|
||||
public void testSetABCMetaAsMetaclassPy3() {
|
||||
final String[] testFiles = {
|
||||
"PyAbstractClassInspection/quickFix/SetABCMetaAsMetaclassPy3/main.py",
|
||||
"PyAbstractClassInspection/quickFix/SetABCMetaAsMetaclassPy3/main_import.py"
|
||||
};
|
||||
|
||||
doInspectionTest(testFiles,
|
||||
PyAbstractClassInspection.class,
|
||||
"Set '" + PyNames.ABC_META + "' as metaclass",
|
||||
true,
|
||||
true);
|
||||
}
|
||||
|
||||
// PY-30789
|
||||
public void testSetImportedABCMetaAsMetaclassPy3() {
|
||||
doInspectionTest("PyAbstractClassInspection/quickFix/SetImportedABCMetaAsMetaclassPy3/main.py",
|
||||
PyAbstractClassInspection.class,
|
||||
"Set '" + PyNames.ABC_META + "' as metaclass",
|
||||
true,
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNls
|
||||
protected String getTestDataPath() {
|
||||
|
||||
@@ -4,7 +4,6 @@ package com.jetbrains.python;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.TestDataFile;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -685,6 +684,15 @@ public class PyQuickFixTest extends PyTestCase {
|
||||
doInspectionTest(PyMethodOverridingInspection.class, "<html>Change signature of m(self, <b>**kwargs</b>)</html>", true, true);
|
||||
}
|
||||
|
||||
// PY-30789
|
||||
public void testSetImportedABCMetaAsMetaclassPy2() {
|
||||
doInspectionTest("PyAbstractClassInspection/quickFix/SetImportedABCMetaAsMetaclassPy2/main.py",
|
||||
PyAbstractClassInspection.class,
|
||||
"Set '" + PyNames.ABC_META + "' as metaclass",
|
||||
true,
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNls
|
||||
protected String getTestDataPath() {
|
||||
|
||||
Reference in New Issue
Block a user