PY-29717 Display information about property access type in sections

This commit is contained in:
Mikhail Golubev
2018-05-23 16:36:40 +03:00
parent 8785973ba3
commit 47327bbd2e
13 changed files with 58 additions and 35 deletions

View File

@@ -77,7 +77,7 @@ public class PyDocumentationBuilder {
private static final Pattern ourSpacesPattern = Pattern.compile("^\\s+");
public PyDocumentationBuilder(PsiElement element, PsiElement originalElement) {
public PyDocumentationBuilder(@NotNull PsiElement element, @Nullable PsiElement originalElement) {
myElement = element;
myOriginalElement = originalElement;
myProlog = new ChainIterable<>();
@@ -142,12 +142,17 @@ public class PyDocumentationBuilder {
return null; // got nothing substantial to say!
}
else {
ChainIterable<String> result = new ChainIterable<>();
final ChainIterable<String> result = new ChainIterable<>();
if (!myProlog.isEmpty() || !myBody.isEmpty()) {
result.addItem(DocumentationMarkup.DEFINITION_START)
.add(myProlog)
.add(myBody)
.addItem(DocumentationMarkup.DEFINITION_END);
.add(myProlog);
if (!myBody.isEmpty() && !myProlog.isEmpty()) {
result.addItem(BR);
}
result.add(myBody)
.addItem(DocumentationMarkup.DEFINITION_END);
}
if (!myContent.isEmpty()) {
result.addItem(DocumentationMarkup.CONTENT_START)
@@ -188,8 +193,7 @@ public class PyDocumentationBuilder {
.addWith(TagBold, $().addWith(TagCode, $(parameter.getName())))
.addItem(" of ")
// TODO links to functions
.addWith(TagCode, $(funcName))
.addItem(BR);
.addWith(TagCode, $(funcName));
if (func != null) {
final PyStringLiteralExpression docString = getEffectiveDocStringExpression(func);
@@ -251,16 +255,10 @@ public class PyDocumentationBuilder {
}
if (accessor.isDefined() && accessor.value() == null) elementDefinition = null;
final String accessorKind = getAccessorKind(direction);
if (elementDefinition != null) {
myEpilog.addWith(TagSmall, $(BR, BR, accessorKind, " of property")).addItem(BR);
}
mySectionsMap.get(PyBundle.message("QDOC.accessor.kind"))
.addItem(accessorKind)
.addItem(elementDefinition == null ? " (not defined)" : "");
if (!(elementDefinition instanceof PyDocStringOwner)) {
myBody.addWith(TagItalic, elementDefinition != null ? $("Declaration: ") : $(accessorKind + " is not defined.")).addItem(BR);
if (elementDefinition != null) {
myBody.addItem(combUp(PyUtil.getReadableRepr(elementDefinition, false)));
}
}
return true;
}
@@ -323,8 +321,7 @@ public class PyDocumentationBuilder {
.addItem(type)
.addWith(TagBold, $().addWith(TagCode, $(elementDefinition.getName())))
.addItem(" of class ")
.addItem(PyDocumentationLink.toContainingClass(WRAP_IN_CODE.apply(target.getContainingClass().getName())))
.addItem(BR);
.addItem(PyDocumentationLink.toContainingClass(WRAP_IN_CODE.apply(target.getContainingClass().getName())));
}
myBody.add(PythonDocumentationProvider.describeTarget(target, context));
}

View File

@@ -433,9 +433,8 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
// provides ctrl+Q doc
@Override
public String generateDoc(@Nullable PsiElement element, @Nullable PsiElement originalElement) {
if (element != null && PydevConsoleRunner.isInPydevConsole(element) ||
originalElement != null && PydevConsoleRunner.isInPydevConsole(originalElement)) {
public String generateDoc(@NotNull PsiElement element, @Nullable PsiElement originalElement) {
if (PydevConsoleRunner.isInPydevConsole(element) || originalElement != null && PydevConsoleRunner.isInPydevConsole(originalElement)) {
return PydevDocumentationProvider.createDoc(element, originalElement);
}
return new PyDocumentationBuilder(element, originalElement).build();

View File

@@ -1,3 +1 @@
<html><body><div class='definition'><pre>property <b><code>m</code></b> of class <a href="psi_element://#class#">C</a><br><i>Copied from getter:</i><br>
Foo
<br><br>@<i>m.setter</i><br>def&nbsp;<b>m</b>(self:&nbsp;<a href="psi_element://#typename#C">C</a>,&nbsp;x:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><small><br><br>Setter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>m</code></b> of class <a href="psi_element://#class#">C</a><br>@<i>m.setter</i><br>def&nbsp;<b>m</b>(self:&nbsp;<a href="psi_element://#typename#C">C</a>,&nbsp;x:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'><br>Foo<br></div><table class='sections'><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'>property getter</td><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Setter</td></table></body></html>

View File

@@ -1 +1 @@
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br><i>Copied from getter:</i><br>Does things to X<br><br>@<i>x.deleter</i><br>def&nbsp;<b>x</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>,&nbsp;v:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Deletes&nbsp;X</div><small><br><br>Deleter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br>@<i>x.deleter</i><br>def&nbsp;<b>x</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>,&nbsp;v:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Does&nbsp;things&nbsp;to&nbsp;XDeletes&nbsp;X</div><table class='sections'><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Deleter</td><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'>property getter</td></table></body></html>

View File

@@ -1 +1 @@
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br><br>@<i>property</i><br>def&nbsp;<b>x</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div><div class='content'>Does&nbsp;things&nbsp;to&nbsp;X</div><small><br><br>Getter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br>@<i>property</i><br>def&nbsp;<b>x</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div><div class='content'>Does&nbsp;things&nbsp;to&nbsp;X</div><table class='sections'><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Getter</td></table></body></html>

View File

@@ -1 +1 @@
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br><i>Copied from getter:</i><br>Does things to X<br><br>@<i>x.setter</i><br>def&nbsp;<b>x</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>,&nbsp;v:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Sets&nbsp;X</div><small><br><br>Setter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br>@<i>x.setter</i><br>def&nbsp;<b>x</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>,&nbsp;v:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Does&nbsp;things&nbsp;to&nbsp;XSets&nbsp;X</div><table class='sections'><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Setter</td><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'>property getter</td></table></body></html>

View File

@@ -0,0 +1,8 @@
class C(object):
@property
def attr(self):
"""Docstring."""
return 42
C().at<the_ref>tr = 42

View File

@@ -1 +1 @@
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br><br>def&nbsp;<b>__getX</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>)&nbsp;-&gt;&nbsp;Any</pre></div><div class='content'>Doc&nbsp;of&nbsp;getter</div><small><br><br>Deleter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br>def&nbsp;<b>__getX</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>)&nbsp;-&gt;&nbsp;Any</pre></div><div class='content'>Doc&nbsp;of&nbsp;getter</div><table class='sections'><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Deleter</td></table></body></html>

View File

@@ -1 +1 @@
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br><br>def&nbsp;<b>__getX</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>)&nbsp;-&gt;&nbsp;Any</pre></div><div class='content'>Doc&nbsp;of&nbsp;getter</div><small><br><br>Getter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br>def&nbsp;<b>__getX</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>)&nbsp;-&gt;&nbsp;Any</pre></div><div class='content'>Doc&nbsp;of&nbsp;getter</div><table class='sections'><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Getter</td></table></body></html>

View File

@@ -1 +1 @@
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br><br>def&nbsp;<b>__getX</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>,&nbsp;x:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;getter</div><small><br><br>Setter of property</small><br></body></html>
<html><body><div class='definition'><pre>property <b><code>x</code></b> of class <a href="psi_element://#class#">A</a>(<a href="psi_element://#typename#object">object</a>)<br>def&nbsp;<b>__getX</b>(self:&nbsp;<a href="psi_element://#typename#A">A</a>,&nbsp;x:&nbsp;Any)&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;getter</div><table class='sections'><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Setter</td></table></body></html>

View File

@@ -0,0 +1,8 @@
class C(object):
def _get(self):
"""Docstring."""
return 42
attr = property(fget=_get)
C().at<the_ref>tr = 42

View File

@@ -0,0 +1 @@
<html><body><div class='definition'><pre>property <b><code>attr</code></b> of class <a href="psi_element://#class#">C</a>(<a href="psi_element://#typename#object">object</a>)<br>attr: <a href="psi_element://#typename#int">int</a></pre></div><div class='content'>Docstring.</div><table class='sections'><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'>property getter</td><tr><td valign='top' class='section'><p>Accessor kind:</td><td valign='top'>Setter (not defined)</td></table></body></html>

View File

@@ -1,6 +1,8 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.documentation.PythonDocumentationProvider;
@@ -62,12 +64,14 @@ public class PyQuickDocTest extends LightMarkedTestCase {
}
private void checkHTMLOnly() {
Map<String, PsiElement> marks = loadTest();
final Map<String, PsiElement> marks = loadTest();
final PsiElement originalElement = marks.get("<the_ref>");
PsiElement referenceElement = originalElement.getParent(); // ident -> expr
assertInstanceOf(referenceElement, PyReferenceOwner.class);
final PsiElement docOwner = referenceElement.getReference().resolve();
checkByHTML(myProvider.generateDoc(docOwner, originalElement));
final DocumentationManager manager = DocumentationManager.getInstance(myFixture.getProject());
final PsiElement target = manager.findTargetElement(myFixture.getEditor(),
originalElement.getTextOffset(),
myFixture.getFile(),
originalElement);
checkByHTML(myProvider.generateDoc(target, originalElement));
}
private void checkHover() {
@@ -183,6 +187,14 @@ public class PyQuickDocTest extends LightMarkedTestCase {
checkHTMLOnly();
}
public void testPropNewUndefinedSetter() {
checkHTMLOnly();
}
public void testPropOldUndefinedSetter() {
checkHTMLOnly();
}
public void testParam() {
checkHTMLOnly();
}