added create property quick fix

This commit is contained in:
Ekaterina Tuzova
2014-03-07 16:14:24 +04:00
parent eab361118e
commit 155f99a1a3
10 changed files with 230 additions and 15 deletions

View File

@@ -19,6 +19,9 @@ ACT.from.some.module.import=Import from ...
QFIX.add.parameter.self=Add parameter ''{0}''
QFIX.add.super=Add super class call
QFIX.add.property=Add property for the field
QFIX.use.property=Use property for the field
QFIX.add.encoding=Add encoding declaration
QFIX.NAME.parameters=Parameters of functions and methods

View File

@@ -77,8 +77,6 @@ public class PyMethodMayBeStaticInspection extends PyInspection {
if (property != null) return;
final PyStatementList statementList = node.getStatementList();
if (statementList == null) return;
final PyStatement[] statements = statementList.getStatements();
if (statements.length == 1 && statements[0] instanceof PyPassStatement) return;

View File

@@ -16,8 +16,11 @@
package com.jetbrains.python.inspections;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiReference;
@@ -26,9 +29,11 @@ import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
import com.jetbrains.python.inspections.quickfix.PyAddPropertyForFieldQuickFix;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyReferenceExpression;
import com.jetbrains.python.psi.PyTargetExpression;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.testing.pytest.PyTestUtil;
@@ -37,6 +42,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
/**
* User: ktisha
@@ -75,29 +82,40 @@ public class PyProtectedMemberInspection extends PyInspection {
if (qualifier == null || PyNames.CANONICAL_SELF.equals(qualifier.getText())) return;
if (myTypeEvalContext.getType(qualifier) instanceof PyNamedTupleType) return;
final String name = node.getName();
final List<LocalQuickFix> quickFixes = new ArrayList<LocalQuickFix>();
quickFixes.add(new PyRenameElementQuickFix());
if (name != null && name.startsWith("_") && !name.startsWith("__") && !name.endsWith("__")) {
final PsiReference reference = node.getReference(getResolveContext());
if (reference == null) return;
final PsiElement resolvedExpression = reference.resolve();
if (resolvedExpression instanceof PyTargetExpression) {
final PyClass containingClass = ((PyTargetExpression)resolvedExpression).getContainingClass();
if (containingClass != null) {
final String qFixName = containingClass.getProperties().containsKey(StringUtil.trimLeading(name, '_')) ?
PyBundle.message("QFIX.use.property") : PyBundle.message("QFIX.add.property");
quickFixes.add(new PyAddPropertyForFieldQuickFix(qFixName));
}
}
final PyClass parentClass = getClassOwner(node);
if (parentClass != null) {
if (PyTestUtil.isPyTestClass(parentClass) && ignoreTestFunctions) return;
final PsiReference reference = node.getReference(getResolveContext());
if (reference != null) {
final PsiElement resolvedExpression = reference.resolve();
final PyClass resolvedClass = getClassOwner(resolvedExpression);
if (parentClass.isSubclass(resolvedClass))
final PyClass resolvedClass = getClassOwner(resolvedExpression);
if (parentClass.isSubclass(resolvedClass))
return;
PyClass outerClass = getClassOwner(parentClass);
while (outerClass != null) {
if (outerClass.isSubclass(resolvedClass))
return;
PyClass outerClass = getClassOwner(parentClass);
while (outerClass != null) {
if (outerClass.isSubclass(resolvedClass))
return;
outerClass = getClassOwner(outerClass);
}
outerClass = getClassOwner(outerClass);
}
}
final PyType type = myTypeEvalContext.getType(qualifier);
final String bundleKey = type instanceof PyModuleType ? "INSP.protected.member.$0.access.module" : "INSP.protected.member.$0.access";
registerProblem(node, PyBundle.message(bundleKey, name), new PyRenameElementQuickFix());
registerProblem(node, PyBundle.message(bundleKey, name), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null, quickFixes.toArray(new LocalQuickFix[quickFixes.size()-1]));
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class PyAddPropertyForFieldQuickFix implements LocalQuickFix {
private String myName = PyBundle.message("QFIX.add.property");
public PyAddPropertyForFieldQuickFix(String name) {
myName = name;
}
@NotNull
public String getName() {
return myName;
}
@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 PyReferenceExpression) {
final PsiReference reference = element.getReference();
if (reference == null) return;
final PsiElement resolved = reference.resolve();
if (resolved instanceof PyTargetExpression) {
PyTargetExpression target = (PyTargetExpression)resolved;
final PyClass containingClass = target.getContainingClass();
if (containingClass != null) {
final String name = target.getName();
if (name == null) return;
String propertyName = StringUtil.trimStart(name, "_");
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 PyExpression qualifier = ((PyReferenceExpression)element).getQualifier();
if (qualifier != null) {
String newElementText = qualifier.getText() + "." + propertyName;
final PyExpression newElement = generator.createExpressionFromText(LanguageLevel.forElement(containingClass), newElementText);
element.replace(newElement);
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
class A:
def __init__(self):
self._x = 1
def _foo(self):
print(self._x)
a = A()
a._f<caret>oo()
print(a._x)

View File

@@ -0,0 +1,12 @@
class A:
def __init__(self):
self._x = 1
def _foo(self):
print(self._x)
a = A()
a._foo()
print(a._<caret>x)

View File

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

View File

@@ -0,0 +1,16 @@
class A:
@property
def x(self):
return self._x
def __init__(self):
self._x = 1
def _foo(self):
print(self._x)
a = A()
a._foo()
print(a.x)
print(a._<caret>x)

View File

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

View File

@@ -0,0 +1,45 @@
/*
* 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.codeInsight.intention.IntentionAction;
import com.intellij.testFramework.TestDataPath;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyQuickFixTestCase;
import com.jetbrains.python.inspections.PyProtectedMemberInspection;
/**
* User: ktisha
*/
@TestDataPath("$CONTENT_ROOT/../testData/quickFixes/PyAddPropertyForFieldQuickFixTest")
public class PyAddPropertyForFieldQuickFixTest extends PyQuickFixTestCase {
public void testProtectedMember() {
doQuickFixTest(PyProtectedMemberInspection.class, PyBundle.message("QFIX.add.property"));
}
public void testUseProperty() {
doQuickFixTest(PyProtectedMemberInspection.class, PyBundle.message("QFIX.use.property"));
}
public void testProtectedFunction() {
final String testFileName = getTestName(true);
myFixture.enableInspections(PyProtectedMemberInspection.class);
myFixture.configureByFile(testFileName + ".py");
myFixture.checkHighlighting(true, false, false);
final IntentionAction intentionAction = myFixture.getAvailableIntention(PyBundle.message("QFIX.add.property"));
assertNull(intentionAction);
}
}