From 0b96edb86a9378029d8aa72bf5d3876a5b8b4ae6 Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Wed, 30 Jun 2010 06:48:17 +0300 Subject: [PATCH] Property access inspection. --- .../PyPropertyAccessInspection.java | 38 +++++++++---------- .../PyPropertyAccessInspection/expected.xml | 33 ++++++++++++++++ .../python/PythonInspectionsTest.java | 11 ++++++ 3 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 python/testData/inspections/PyPropertyAccessInspection/expected.xml diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java index 62188a2578f6..cd4ac0614387 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java @@ -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, Property> cache = PyPropertyAccessInspection.this.myPropertyCache.get(); final Pair key = new Pair(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 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 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); + } + } + } } diff --git a/python/testData/inspections/PyPropertyAccessInspection/expected.xml b/python/testData/inspections/PyPropertyAccessInspection/expected.xml new file mode 100644 index 000000000000..4a5e38cdbf6c --- /dev/null +++ b/python/testData/inspections/PyPropertyAccessInspection/expected.xml @@ -0,0 +1,33 @@ + + + + props.py + 23 + Property 'readonly' cannot be set + + + props.py + 24 + Property 'readonly' cannot be deleted + + + props.py + 28 + Property 'writeonly' cannot be read + + + props.py + 29 + Property 'writeonly' cannot be read + + + props.py + 30 + Property 'writeonly' cannot be deleted + + + props.py + 36 + Property 'readwrite' cannot be deleted + + diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index b75328303641..cb48aa47ae1d 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -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); + } + } }