fix bugs in stub-based property PSI, refactor and code cleanup

This commit is contained in:
Dmitry Jemerov
2012-03-05 18:56:45 +01:00
parent 62f34c544a
commit 632b8571c1
8 changed files with 200 additions and 267 deletions
@@ -579,38 +579,38 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
return null;
}
private Maybe<PyFunction> fromPacked(Maybe<String> maybe_name) {
if (maybe_name.isDefined()) {
PyFunction method = findMethodByName(maybe_name.value(), true);
private Maybe<PyFunction> fromPacked(Maybe<String> maybeName) {
if (maybeName.isDefined()) {
final String value = maybeName.value();
if (value == null || PyNames.NONE.equals(value)) {
return NONE;
}
PyFunction method = findMethodByName(value, true);
if (method != null) return new Maybe<PyFunction>(method);
}
return UNKNOWN_CALL;
}
@Nullable
private Property lookInStubProperties(@Nullable String name, @Nullable Processor<Property> property_filter) {
Maybe<PyFunction> getter = NONE;
Maybe<PyFunction> setter = NONE;
Maybe<PyFunction> deleter = NONE;
String doc = null;
private Property lookInStubProperties(@Nullable String name, @Nullable Processor<Property> propertyProcessor) {
final PyClassStub stub = getStub();
if (stub != null) {
for (StubElement substub : stub.getChildrenStubs()) {
if (substub.getStubType() == PyElementTypes.TARGET_EXPRESSION) {
final PyTargetExpressionStub target_stub = (PyTargetExpressionStub)substub;
PropertyStubStorage prop = target_stub.getCustomStub(PropertyStubStorage.class);
if (prop != null && (name == null || name.equals(target_stub.getName()))) {
getter = fromPacked(prop.getGetter());
setter = fromPacked(prop.getSetter());
deleter = fromPacked(prop.getDeleter());
doc = prop.getDoc();
final PyTargetExpressionStub targetStub = (PyTargetExpressionStub)substub;
PropertyStubStorage prop = targetStub.getCustomStub(PropertyStubStorage.class);
if (prop != null && (name == null || name.equals(targetStub.getName()))) {
Maybe<PyFunction> getter = fromPacked(prop.getGetter());
Maybe<PyFunction> setter = fromPacked(prop.getSetter());
Maybe<PyFunction> deleter = fromPacked(prop.getDeleter());
String doc = prop.getDoc();
if (getter != NONE || setter != NONE || deleter != NONE) {
final PropertyImpl property = new PropertyImpl(getter, setter, deleter, doc, targetStub.getPsi());
if (propertyProcessor == null || propertyProcessor.process(property)) return property;
}
}
}
}
if (getter != NONE || setter != NONE || deleter != NONE) {
final PropertyImpl prop = new PropertyImpl(getter, setter, deleter, doc, null);
if (property_filter == null || property_filter.process(prop)) return prop;
}
}
return null;
}
@@ -30,28 +30,6 @@ public class PropertyStubStorage extends PropertyBunch<String> implements Custom
return name;
}
@NotNull
@Override
public Maybe<String> getGetter() {
return myGetter;
}
@NotNull
@Override
public Maybe<String> getSetter() {
return mySetter;
}
@NotNull
@Override
public Maybe<String> getDeleter() {
return myDeleter;
}
public String getDoc() {
return myDoc;
}
private static final String IMPOSSIBLE_NAME = "#";
private static void writeOne(Maybe<String> what, StubOutputStream stream) throws IOException {
-2
View File
@@ -15,5 +15,3 @@ class A(object):
v2 = property(fset=setter, fdel=deleter, fget=getter, doc="doc of v2")
v3 = property(lambda self: self._v, None, (deleter))
v4 = otherworldly # NOTE: not supported yet
<caret>a = A()
-2
View File
@@ -25,5 +25,3 @@ class A(object):
self._v = v
# deleter absent
<caret>a = A()
@@ -0,0 +1,111 @@
package com.jetbrains.python;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.toolbox.Maybe;
public class PyClassicPropertyTest extends PyTestCase {
protected PyClass myClass;
@Override
protected void setUp() throws Exception {
super.setUp();
final PyFile file = (PyFile)myFixture.configureByFile("property/Classic.py");
myClass = file.getTopLevelClasses().get(0);
}
public void testV1() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v1");
assertNotNull(p);
assertNull(p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("v1", site.getText());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("getter", accessor.value().getName());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("setter", accessor.value().getName());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
}
public void testV2() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v2");
assertNotNull(p);
assertEquals("doc of v2", p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("v2", site.getText());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("getter", accessor.value().getName());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("setter", accessor.value().getName());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("deleter", accessor.value().getName());
}
public void testV3() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v3");
assertNotNull(p);
assertNull(p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("v3", site.getText());
accessor = p.getGetter();
assertFalse(accessor.isDefined());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("deleter", accessor.value().getName());
}
/* NOTE: we don't support this yet
public void testV4() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v4");
assertNotNull(p);
assertEquals("otherworldly", p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("otherworldly", site.getText());
accessor = p.getGetter();
assertFalse(accessor.isDefined());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
}
*/
}
@@ -0,0 +1,68 @@
package com.jetbrains.python;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
import com.jetbrains.python.toolbox.Maybe;
public class PyDecoratedPropertyTest extends PyTestCase {
protected PyClass myClass;
@Override
protected void setUp() throws Exception {
super.setUp();
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
final PyFile file = (PyFile)myFixture.configureByFile("property/Decorated.py");
myClass = file.getTopLevelClasses().get(0);
}
public void testW1() throws Exception {
Property p;
Maybe<PyFunction> accessor;
final String name = "w1";
p = myClass.findProperty(name);
assertNotNull(p);
assertNull(p.getDoc());
assertNull(p.getDefinitionSite());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals(name, accessor.value().getName());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals(name, accessor.value().getName());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals(name, accessor.value().getName());
}
public void testW2() throws Exception {
Property p;
Maybe<PyFunction> accessor;
final String name = "w2";
p = myClass.findProperty(name);
assertNotNull(p);
assertNull(p.getDoc());
assertNull(p.getDefinitionSite());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("w2", accessor.value().getName());
assertEquals("doc of "+name, accessor.value().getDocStringExpression().getStringValue());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
}
}
@@ -1,220 +0,0 @@
package com.jetbrains.python;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.toolbox.Maybe;
import junit.framework.TestSuite;
/**
* Tests property API.
* User: dcheryasov
* Date: Jun 30, 2010 8:09:12 AM
*/
public class PyPropertyTestSuite {
public static TestSuite suite() {
return new TestSuite(PyClassicPropertyTest.class, PyDecoratedPropertyTest.class);
}
abstract static class PyPropertyTest extends PyTestCase {
protected PyClass myClass;
protected LanguageLevel myLanguageLevel = LanguageLevel.PYTHON26;
abstract String getFileName();
@Override
protected void setUp() throws Exception {
super.setUp();
PsiReference ref = myFixture.getReferenceAtCaretPosition("property/"+ getFileName());
final Project project = ref.getElement().getContainingFile().getProject();
PythonLanguageLevelPusher.setForcedLanguageLevel(project, myLanguageLevel);
PsiElement elt = ref.resolve();
assertInstanceOf(elt, PyExpression.class);
PyType type = ((PyExpression)elt).getType(TypeEvalContext.slow());
assertInstanceOf(type, PyClassType.class);
myClass = ((PyClassType)type).getPyClass();
assertNotNull(myClass);
}
}
public static class PyClassicPropertyTest extends PyPropertyTest {
public PyClassicPropertyTest() {
super();
}
@Override
String getFileName() {
return "Classic.py";
}
public void testV1() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v1");
assertNotNull(p);
assertNull(p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("v1", site.getText());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("getter", accessor.value().getName());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("setter", accessor.value().getName());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
}
public void testV2() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v2");
assertNotNull(p);
assertEquals("doc of v2", p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("v2", site.getText());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("getter", accessor.value().getName());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("setter", accessor.value().getName());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("deleter", accessor.value().getName());
}
public void testV3() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v3");
assertNotNull(p);
assertNull(p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("v3", site.getText());
accessor = p.getGetter();
assertFalse(accessor.isDefined());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("deleter", accessor.value().getName());
}
/* NOTE: we don't support this yet
public void testV4() throws Exception {
Property p;
Maybe<PyFunction> accessor;
p = myClass.findProperty("v4");
assertNotNull(p);
assertEquals("otherworldly", p.getDoc());
PyTargetExpression site = p.getDefinitionSite();
assertEquals("otherworldly", site.getText());
accessor = p.getGetter();
assertFalse(accessor.isDefined());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
}
*/
}
public static class PyDecoratedPropertyTest extends PyPropertyTest {
public PyDecoratedPropertyTest() {
super();
}
@Override
String getFileName() {
return "Decorated.py";
}
@Override
protected void setUp() throws Exception {
super.setUp();
myLanguageLevel = LanguageLevel.PYTHON26;
}
public void testW1() throws Exception {
Property p;
Maybe<PyFunction> accessor;
final String name = "w1";
p = myClass.findProperty(name);
assertNotNull(p);
assertNull(p.getDoc());
assertNull(p.getDefinitionSite());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals(name, accessor.value().getName());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals(name, accessor.value().getName());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals(name, accessor.value().getName());
}
public void testW2() throws Exception {
Property p;
Maybe<PyFunction> accessor;
final String name = "w2";
p = myClass.findProperty(name);
assertNotNull(p);
assertNull(p.getDoc());
assertNull(p.getDefinitionSite());
accessor = p.getGetter();
assertTrue(accessor.isDefined());
assertNotNull(accessor.value());
assertEquals("w2", accessor.value().getName());
assertEquals("doc of "+name, accessor.value().getDocStringExpression().getStringValue());
accessor = p.getSetter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
accessor = p.getDeleter();
assertTrue(accessor.isDefined());
assertNull(accessor.value());
}
}
}
@@ -73,8 +73,8 @@ public class PythonAllTestsSuite {
PyIntroduceConstantTest.class,
PyClassNameCompletionTest.class,
PySuppressInspectionsTest.class,
PyPropertyTestSuite.PyClassicPropertyTest.class,
PyPropertyTestSuite.PyDecoratedPropertyTest.class,
PyClassicPropertyTest.class,
PyDecoratedPropertyTest.class,
PythonRunConfigurationTest.class,
PyFoldingTest.class,
EpydocStringTest.class,