added create property quick fix for the property access inspection

This commit is contained in:
Ekaterina Tuzova
2014-03-07 18:31:00 +04:00
parent 823897267c
commit 7438ce848b
14 changed files with 237 additions and 9 deletions

View File

@@ -92,6 +92,8 @@ public abstract class PyElementGenerator {
public abstract PyImportElement createImportElement(final LanguageLevel languageLevel, String name);
public abstract PyFunction createProperty(final LanguageLevel languageLevel, String propertyName, String fieldName, AccessDirection accessDirection);
@NotNull
public abstract <T> T createFromText(LanguageLevel langLevel, Class<T> aClass, final String text);

View File

@@ -24,6 +24,8 @@ QFIX.use.property=Use property for the field
QFIX.make.public=Make public
QFIX.create.property=Create property
QFIX.add.encoding=Add encoding declaration
QFIX.NAME.parameters=Parameters of functions and methods

View File

@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.util.containers.HashMap;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.inspections.quickfix.PyCreatePropertyQuickFix;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
@@ -117,7 +118,7 @@ public class PyPropertyAccessInspection extends PyInspection {
else {
message = PyBundle.message("INSP.property.$0.cant.be.read", name);
}
registerProblem(node, message);
registerProblem(node, message, new PyCreatePropertyQuickFix(dir));
}
}

View File

@@ -62,9 +62,8 @@ public class PyAddPropertyForFieldQuickFix implements LocalQuickFix {
final Map<String,Property> properties = containingClass.getProperties();
final PyElementGenerator generator = PyElementGenerator.getInstance(project);
if (!properties.containsKey(propertyName)) {
String propertyText = "@property\ndef " + propertyName + "(self):\n\t return self." + name;
final PyFunction property = generator.createFromText(LanguageLevel.forElement(containingClass), PyFunction.class, propertyText);
PyUtil.addElementToStatementList(property, containingClass.getStatementList());
final PyFunction property = generator.createProperty(LanguageLevel.forElement(containingClass), propertyName, name, AccessDirection.READ);
PyUtil.addElementToStatementList(property, containingClass.getStatementList(), false);
}
final PyExpression qualifier = ((PyReferenceExpression)element).getQualifier();
if (qualifier != null) {

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2000-2013 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.inspections.quickfix;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class PyCreatePropertyQuickFix implements LocalQuickFix {
private final AccessDirection myAccessDirection;
public PyCreatePropertyQuickFix(AccessDirection dir) {
myAccessDirection = dir;
}
@NotNull
public String getName() {
return PyBundle.message("QFIX.create.property");
}
@NonNls
@NotNull
public String getFamilyName() {
return getName();
}
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (element instanceof PyQualifiedExpression) {
final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier();
if (qualifier != null) {
final PyType type = TypeEvalContext.codeAnalysis(element.getContainingFile()).getType(qualifier);
if (type instanceof PyClassType) {
final PyClass cls = ((PyClassType)type).getPyClass();
final String propertyName = ((PyQualifiedExpression)element).getName();
if (propertyName == null) return;
final String fieldName = "_" + propertyName;
final PyElementGenerator generator = PyElementGenerator.getInstance(project);
final PyFunction property = generator.createProperty(LanguageLevel.forElement(cls), propertyName, fieldName, myAccessDirection);
PyUtil.addElementToStatementList(property, cls.getStatementList(), myAccessDirection == AccessDirection.READ);
}
}
}
}
}

View File

@@ -42,7 +42,6 @@ import org.jetbrains.annotations.Nullable;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.Formatter;
@@ -291,6 +290,24 @@ public class PyElementGeneratorImpl extends PyElementGenerator {
return createFromText(languageLevel, PyImportElement.class, "from foo import " + name, new int[]{0, 6});
}
@Override
public PyFunction createProperty(LanguageLevel languageLevel,
String propertyName,
String fieldName,
AccessDirection accessDirection) {
String propertyText;
if (accessDirection == AccessDirection.DELETE) {
propertyText = "@" + propertyName +".deleter\ndef " + propertyName + "(self):\n del self." + fieldName;
}
else if (accessDirection == AccessDirection.WRITE) {
propertyText = "@" + propertyName + ".setter\ndef " + propertyName + "(self, value):\n self." + fieldName + " = value";
}
else {
propertyText = "@property\ndef " + propertyName + "(self):\n return self." + fieldName;
}
return createFromText(languageLevel, PyFunction.class, propertyText);
}
static final int[] FROM_ROOT = new int[]{0};
@NotNull

View File

@@ -1,15 +1,16 @@
class A:
@property
def x(self):
return self._x
def __init__(self):
self._x = 1
def _foo(self):
print(self._x)
@property
def x(self):
return self._x
a = A()
a._foo()

View File

@@ -0,0 +1,16 @@
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
c = C()
print(c.x)
del <warning descr="Property 'x' cannot be deleted">c.<caret>x</warning>
<warning descr="Property 'x' cannot be set">c.x</warning> = 1

View File

@@ -0,0 +1,20 @@
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.deleter
def x(self):
del self._x
c = C()
print(c.x)
del c.x
c.x = 1

View File

@@ -0,0 +1,14 @@
class C(object):
def __init__(self):
self._x = None
@x.setter
def x(self, value):
self._x = value
c = C()
print(<warning descr="Property 'x' cannot be read">c.<caret>x</warning>)
del <warning descr="Property 'x' cannot be deleted">c.x</warning>
c.x = 1

View File

@@ -0,0 +1,18 @@
class C(object):
@property
def x(self):
return self._x
def __init__(self):
self._x = None
@x.setter
def x(self, value):
self._x = value
c = C()
print(c.x)
del c.x
c.x = 1

View File

@@ -0,0 +1,15 @@
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
c = C()
print(c.x)
del <warning descr="Property 'x' cannot be deleted">c.x</warning>
<warning descr="Property 'x' cannot be set">c.<caret>x</warning> = 1

View File

@@ -0,0 +1,20 @@
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
c = C()
print(c.x)
del c.x
c.x = 1

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2000-2013 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.quickFixes;
import com.intellij.testFramework.TestDataPath;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyQuickFixTestCase;
import com.jetbrains.python.inspections.PyPropertyAccessInspection;
@TestDataPath("$CONTENT_ROOT/../testData/quickFixes/PyCreatePropertyQuickFixTest")
public class PyCreatePropertyQuickFixTest extends PyQuickFixTestCase {
public void testSetter() {
doQuickFixTest(PyPropertyAccessInspection.class, PyBundle.message("QFIX.create.property"));
}
public void testDeleter() {
doQuickFixTest(PyPropertyAccessInspection.class, PyBundle.message("QFIX.create.property"));
}
public void testGetter() {
doQuickFixTest(PyPropertyAccessInspection.class, PyBundle.message("QFIX.create.property"));
}
}