unused constructor parameters have quickfix to initialize field (PY-1398)

This commit is contained in:
Dmitry Jemerov
2010-08-17 21:35:49 +04:00
parent 23788a4a64
commit d320cedecd
6 changed files with 37 additions and 12 deletions
@@ -25,11 +25,13 @@ import org.jetbrains.annotations.Nullable;
public class AddFieldQuickFix implements LocalQuickFix {
private PyClass myQualifierClass;
private final String myInitializer;
private String myIdentifier;
public AddFieldQuickFix(String identifier, PyClass qualifierClass) {
public AddFieldQuickFix(String identifier, PyClass qualifierClass, String initializer) {
myIdentifier = identifier;
myQualifierClass = qualifierClass;
myInitializer = initializer;
}
@NotNull
@@ -67,7 +69,7 @@ public class AddFieldQuickFix implements LocalQuickFix {
PyClass cls = myQualifierClass;
String item_name = myIdentifier;
if (cls != null) {
PsiElement initStatement = addFieldToInit(project, cls, item_name, new CreateFieldCallback(project, item_name));
PsiElement initStatement = addFieldToInit(project, cls, item_name, new CreateFieldCallback(project, item_name, myInitializer));
if (initStatement != null) {
showTemplateBuilder(initStatement);
return;
@@ -77,11 +79,11 @@ public class AddFieldQuickFix implements LocalQuickFix {
PyUtil.showBalloon(project, PyBundle.message("QFIX.failed.to.add.field"), MessageType.ERROR);
}
private static void showTemplateBuilder(PsiElement initStatement) {
private void showTemplateBuilder(PsiElement initStatement) {
initStatement = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(initStatement);
if (initStatement instanceof PyAssignmentStatement) {
final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(initStatement);
builder.replaceElement(((PyAssignmentStatement) initStatement).getAssignedValue(), "None");
builder.replaceElement(((PyAssignmentStatement) initStatement).getAssignedValue(), myInitializer);
builder.run();
}
}
@@ -159,14 +161,16 @@ public class AddFieldQuickFix implements LocalQuickFix {
private static class CreateFieldCallback implements Function<String, PyStatement> {
private Project myProject;
private String myItemName;
private String myInitializer;
private CreateFieldCallback(Project project, String itemName) {
private CreateFieldCallback(Project project, String itemName, String initializer) {
myProject = project;
myItemName = itemName;
myInitializer = initializer;
}
public PyStatement fun(String self_name) {
return PyElementGenerator.getInstance(myProject).createFromText(PyStatement.class, self_name + "." + myItemName + " = None");
return PyElementGenerator.getInstance(myProject).createFromText(PyStatement.class, self_name + "." + myItemName + " = " + myInitializer);
}
}
}
@@ -210,7 +210,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
if (reference.getElement().getParent() instanceof PyCallExpression) {
actions.add(new AddMethodQuickFix(ref_text, (PyClassType)qtype));
}
else actions.add(new AddFieldQuickFix(ref_text, cls));
else actions.add(new AddFieldQuickFix(ref_text, cls, "None"));
}
}
description_buf.append(PyBundle.message("INSP.unresolved.ref.$0.for.class.$1", ref_text, qtype.getName()));
@@ -17,6 +17,8 @@ import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Function;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.actions.AddFieldQuickFix;
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
@@ -244,14 +246,23 @@ class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
continue;
}
}
boolean isInitMethod = false;
PyClass containingClass = null;
PyParameterList paramList = PsiTreeUtil.getParentOfType(element, PyParameterList.class);
if (paramList != null && paramList.getParent() instanceof PyFunction) {
PyFunction func = (PyFunction) paramList.getParent();
if (canHaveUnusedParameters(func, functionsWithInheritors)) {
containingClass = func.getContainingClass();
if (PyNames.INIT.equals(func.getName()) && containingClass != null) {
isInitMethod = true;
}
else if (ignoreUnusedParameters(func, functionsWithInheritors)) {
continue;
}
}
registerWarning(element, PyBundle.message("INSP.unused.locals.parameter.isnot.used", name));
LocalQuickFix[] fixes = isInitMethod
? new LocalQuickFix[] { new AddFieldQuickFix(name, containingClass, name) }
: LocalQuickFix.EMPTY_ARRAY;
registerWarning(element, PyBundle.message("INSP.unused.locals.parameter.isnot.used", name), fixes);
}
else {
if (myIgnoreTupleUnpacking && isTupleUnpacking(element)) {
@@ -269,7 +280,7 @@ class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
}
}
private static boolean canHaveUnusedParameters(PyFunction func, Set<PyFunction> functionsWithInheritors) {
private static boolean ignoreUnusedParameters(PyFunction func, Set<PyFunction> functionsWithInheritors) {
if (functionsWithInheritors.contains(func)) {
return true;
}
@@ -297,8 +308,8 @@ class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
return false;
}
private void registerWarning(final PsiElement element, final String msg) {
registerProblem(element, msg, ProblemHighlightType.LIKE_UNUSED_SYMBOL, null);
private void registerWarning(final PsiElement element, final String msg, LocalQuickFix... quickfixes) {
registerProblem(element, msg, ProblemHighlightType.LIKE_UNUSED_SYMBOL, null, quickfixes);
}
private static class ReplaceWithWildCard implements LocalQuickFix {
@@ -0,0 +1,3 @@
class A:
def __init__(self, <warning descr="Parameter 'foo' value is not used">f<caret>oo</warning>):
pass
@@ -0,0 +1,3 @@
class A:
def __init__(self, foo):
self.foo = foo
@@ -144,6 +144,10 @@ public class PyQuickFixTest extends PyLightFixtureTestCase {
doInspectionTest("AddClass.py", PyUnresolvedReferencesInspection.class, "Create class 'Xyzzy'", true, true);
}
public void testFieldFromUnusedParameter() { // PY-1398
doInspectionTest("FieldFromUnusedParameter.py", PyUnusedLocalInspection.class, "Add field 'foo' to class A", true, true);
}
@NonNls
protected String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/inspections/";