Property access inspection.

This commit is contained in:
Dmitry Cheryasov
2010-06-30 06:48:17 +03:00
parent ed0d414823
commit 0b96edb86a
3 changed files with 62 additions and 20 deletions
@@ -67,22 +67,12 @@ public class PyPropertyAccessInspection extends PyInspection {
@Override
public void visitPyReferenceExpression(PyReferenceExpression node) {
super.visitPyReferenceExpression(node);
check(node);
}
@Override
public void visitPyTargetExpression(PyTargetExpression node) {
super.visitPyTargetExpression(node);
check(node);
}
private void check(PyQualifiedExpression expr) {
PyExpression qualifier = expr.getQualifier();
PyExpression qualifier = node.getQualifier();
if (qualifier != null) {
PyType type = qualifier.getType(TypeEvalContext.fast());
if (type instanceof PyClassType) {
PyClass cls = ((PyClassType)type).getPyClass();
String name = expr.getName();
String name = node.getName();
if (cls != null && name != null) {
Map<Pair<PyClass, String>, Property> cache = PyPropertyAccessInspection.this.myPropertyCache.get();
final Pair<PyClass, String> key = new Pair<PyClass, String>(cls, name);
@@ -91,19 +81,27 @@ public class PyPropertyAccessInspection extends PyInspection {
else property = cls.findProperty(name);
cache.put(key, property); // we store nulls, too, to know that a property does not exist
if (property != null) {
AccessDirection dir = AccessDirection.of(expr);
final Maybe<PyFunction> accessor = property.getByDirection(dir);
if (accessor.isDefined() && accessor.value() == null) {
String message;
if (dir == AccessDirection.WRITE) message = PyBundle.message("INSP.property.$0.cant.be.set", name);
else if (dir == AccessDirection.DELETE) message = PyBundle.message("INSP.property.$0.cant.be.deleted", name);
else message = PyBundle.message("INSP.property.$0.cant.be.read", name);
registerProblem(expr, message);
AccessDirection dir = AccessDirection.of(node);
checkAccessor(node, name, dir, property);
if (dir == AccessDirection.READ && node.getParent() instanceof PyAugAssignmentStatement) {
checkAccessor(node, name, AccessDirection.WRITE, property);
}
}
}
}
}
}
private void checkAccessor(PyReferenceExpression node, String name, AccessDirection dir, Property property) {
Maybe<PyFunction> accessor = property.getByDirection(dir);
if (accessor.isDefined() && accessor.value() == null) {
String message;
if (dir == AccessDirection.WRITE) message = PyBundle.message("INSP.property.$0.cant.be.set", name);
else if (dir == AccessDirection.DELETE) message = PyBundle.message("INSP.property.$0.cant.be.deleted", name);
else message = PyBundle.message("INSP.property.$0.cant.be.read", name);
registerProblem(node, message);
}
}
}
}
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>props.py</file>
<line>23</line>
<description>Property 'readonly' cannot be set</description>
</problem>
<problem>
<file>props.py</file>
<line>24</line>
<description>Property 'readonly' cannot be deleted</description>
</problem>
<problem>
<file>props.py</file>
<line>28</line>
<description>Property 'writeonly' cannot be read</description>
</problem>
<problem>
<file>props.py</file>
<line>29</line>
<description>Property 'writeonly' cannot be read</description>
</problem>
<problem>
<file>props.py</file>
<line>30</line>
<description>Property 'writeonly' cannot be deleted</description>
</problem>
<problem>
<file>props.py</file>
<line>36</line>
<description>Property 'readwrite' cannot be deleted</description>
</problem>
</problems>
@@ -203,4 +203,15 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase {
myFixture.enableInspections(PyCallingNonCallableInspection.class);
myFixture.checkHighlighting(true, false, false);
}
public void testPyPropertyAccessInspection() throws Throwable {
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
try {
LocalInspectionTool inspection = new PyPropertyAccessInspection();
doTest(getTestName(false), inspection);
}
finally {
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
}
}
}