PY-16581 Quickfix "Implement abstract methods" implements abstract properties as properties. Fix possible memory leak caused by holding PsiElement

This commit is contained in:
Valentina Kiryushkina
2015-12-23 13:28:07 +03:00
parent 50486973ca
commit ef4d61c25b
7 changed files with 101 additions and 15 deletions
@@ -191,8 +191,11 @@ public class PyOverrideImplementUtil {
}
}
private static PyFunctionBuilder buildOverriddenFunction(PyClass pyClass, PyFunction baseFunction, boolean implement) {
private static PyFunctionBuilder buildOverriddenFunction(PyClass pyClass,
PyFunction baseFunction,
boolean implement) {
final boolean overridingNew = PyNames.NEW.equals(baseFunction.getName());
assert baseFunction.getName() != null;
PyFunctionBuilder pyFunctionBuilder = new PyFunctionBuilder(baseFunction.getName(), baseFunction);
final PyDecoratorList decorators = baseFunction.getDecoratorList();
boolean baseMethodIsStatic = false;
@@ -204,6 +207,10 @@ public class PyOverrideImplementUtil {
baseMethodIsStatic = true;
pyFunctionBuilder.decorate(PyNames.STATICMETHOD);
}
else if (decorators.findDecorator(PyNames.PROPERTY) != null ||
decorators.findDecorator(PyNames.ABSTRACTPROPERTY) != null) {
pyFunctionBuilder.decorate(PyNames.PROPERTY);
}
}
PyAnnotation anno = baseFunction.getAnnotation();
if (anno != null) {
@@ -15,15 +15,17 @@
*/
package com.jetbrains.python.inspections.quickfix;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.override.PyMethodMember;
import com.jetbrains.python.codeInsight.override.PyOverrideImplementUtil;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFunction;
@@ -31,23 +33,24 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Set;
/**
* User: ktisha
*/
public class PyImplementMethodsQuickFix implements LocalQuickFix {
public class PyImplementMethodsQuickFix extends LocalQuickFixOnPsiElement {
private final PyClass myClass;
private final Set<PyFunction> myToImplement;
public PyImplementMethodsQuickFix(PyClass aClass, Set<PyFunction> toBeImplemented) {
myClass = aClass;
myToImplement = toBeImplemented;
public PyImplementMethodsQuickFix(PyClass aClass, Set<PyFunction> toImplement) {
super(aClass);
myToImplement = toImplement;
}
@NotNull
public String getName() {
@Override
public String getText() {
return PyBundle.message("QFIX.NAME.implement.methods");
}
@@ -57,10 +60,26 @@ public class PyImplementMethodsQuickFix implements LocalQuickFix {
return getName();
}
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
final Editor editor = getEditor(project, descriptor.getPsiElement().getContainingFile());
if (editor != null)
PyOverrideImplementUtil.chooseAndOverrideOrImplementMethods(project, editor, myClass, myToImplement, "Select Methods to Implement", true);
@Override
public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
final Editor editor = getEditor(project, file);
if (editor != null && startElement instanceof PyClass) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
ArrayList<PyMethodMember> list = new ArrayList<PyMethodMember>();
for (PyFunction function: myToImplement) {
list.add(new PyMethodMember(function));
}
PyOverrideImplementUtil.overrideMethods(editor, (PyClass)startElement, list, true);
}
else {
PyOverrideImplementUtil
.chooseAndOverrideOrImplementMethods(project, editor,
(PyClass)startElement, myToImplement,
"Select Methods to Implement", true);
}
}
}
@Nullable
@@ -76,5 +95,4 @@ public class PyImplementMethodsQuickFix implements LocalQuickFix {
}
return null;
}
}
@@ -0,0 +1,11 @@
from abc import ABC, abstractproperty
class Base(ABC):
@abstractproperty
def some_method(self):
pass
class <weak_warning descr="Class Sub must implement all abstract methods">S<caret>ub</weak_warning>(Base):
pass
@@ -0,0 +1,12 @@
from abc import ABC, abstractproperty
class Base(ABC):
@abstract
@property
def some_method(self):
pass
class <weak_warning descr="Class Sub must implement all abstract methods">S<caret>ub</weak_warning>(Base):
pass
@@ -0,0 +1,14 @@
from abc import ABC, abstractproperty
class Base(ABC):
@abstractproperty
def some_method(self):
pass
class Sub(Base):
@property
def some_method(self):
pass
@@ -0,0 +1,14 @@
from abc import ABC, abstractproperty
class Base(ABC):
@abstractproperty
def some_method(self):
pass
class Sub(Base):
@property
def some_method(self):
pass
@@ -619,6 +619,16 @@ public class PyQuickFixTest extends PyTestCase {
myFixture.checkHighlighting(true, false, true);
}
public void testImplementAbstractProperty() {
doInspectionTest("ImplementAbstractProperty.py", PyAbstractClassInspection.class, PyBundle.message("QFIX.NAME.implement.methods"),
true, true);
}
public void testImplementAbstractProperty1() {
doInspectionTest("ImplementAbstractProperty.py", PyAbstractClassInspection.class, PyBundle.message("QFIX.NAME.implement.methods"),
true, true);
}
@Override
@NonNls
protected String getTestDataPath() {
@@ -669,7 +679,7 @@ public class PyQuickFixTest extends PyTestCase {
}
if (applyFix) {
myFixture.launchAction(intentionActions.get(0));
myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after"));
myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after"), true);
}
}
else {