mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fix bugs in stub-based property PSI, refactor and code cleanup
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user