import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
-import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.PyNames;
-import com.jetbrains.python.PythonFileType;
+import com.jetbrains.python.*;
import com.jetbrains.python.console.PyConsoleUtil;
+ import com.jetbrains.python.documentation.docstrings.DocStringUtil;
+ import com.jetbrains.python.documentation.docstrings.PyStructuredDocstringFormatter;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyCallExpressionHelper;
private final PsiElement myElement;
private final PsiElement myOriginalElement;
private ChainIterable<String> myResult;
- private ChainIterable<String> myProlog; // sequence for reassignment info, etc
- private ChainIterable<String> myBody; // sequence for doc string
- private ChainIterable<String> myEpilog; // sequence for doc "copied from" notices and such
+ private final ChainIterable<String> myProlog; // sequence for reassignment info, etc
+ private final ChainIterable<String> myBody; // sequence for doc string
+ private final ChainIterable<String> myEpilog; // sequence for doc "copied from" notices and such
private static final Pattern ourSpacesPattern = Pattern.compile("^\\s+");
- private ChainIterable<String> myReassignmentChain;
++ private final ChainIterable<String> myReassignmentChain;
public PyDocumentationBuilder(PsiElement element, PsiElement originalElement) {
myElement = element;
myResult.add(myProlog).addWith(TagCode, myBody).add(myEpilog); // pre-assemble; then add stuff to individual cats as needed
myResult = wrapInTag("html", wrapInTag("body", myResult));
+ myReassignmentChain = new ChainIterable<String>();
}
+ @Nullable
public String build() {
- final ChainIterable<String> reassignCat = new ChainIterable<String>(); // sequence for reassignment info, etc
- PsiElement followed = resolveToDocStringOwner(reassignCat);
-
- // check if we got a property ref.
- // if so, element is an accessor, and originalElement if an identifier
- // TODO: use messages from resources!
- PyClass cls;
- PsiElement outer = null;
- boolean isProperty = false;
- String accessorKind = "None";
final TypeEvalContext context = TypeEvalContext.userInitiated(myElement.getProject(), myElement.getContainingFile());
- if (myOriginalElement != null) {
- final String elementName = myOriginalElement.getText();
- if (PyUtil.isPythonIdentifier(elementName)) {
- outer = myOriginalElement.getParent();
- if (outer instanceof PyQualifiedExpression) {
- final PyExpression qual = ((PyQualifiedExpression)outer).getQualifier();
- if (qual != null) {
- final PyType type = context.getType(qual);
- if (type instanceof PyClassType) {
- cls = ((PyClassType)type).getPyClass();
- final Property property = cls.findProperty(elementName, true, null);
- if (property != null) {
- isProperty = true;
- final AccessDirection dir = AccessDirection.of((PyElement)outer);
- final Maybe<PyCallable> accessor = property.getByDirection(dir);
- myProlog
- .addItem("property ").addWith(TagBold, $().addWith(TagCode, $(elementName)))
- .addItem(" of ").add(PythonDocumentationProvider.describeClass(cls, TagCode, true, true));
- if (accessor.isDefined() && property.getDoc() != null) {
- myBody.addItem(": ").addItem(property.getDoc()).addItem(BR);
- }
- else {
- final PyCallable getter = property.getGetter().valueOrNull();
- if (getter != null && getter != myElement && getter instanceof PyFunction) {
- // not in getter, getter's doc comment may be useful
- final PyStringLiteralExpression docstring = ((PyFunction)getter).getDocStringExpression();
- if (docstring != null) {
- myProlog
- .addItem(BR).addWith(TagItalic, $("Copied from getter:")).addItem(BR)
- .addItem(docstring.getStringValue());
- }
- }
- myBody.addItem(BR);
- }
- myBody.addItem(BR);
- if (accessor.isDefined() && accessor.value() == null) followed = null;
- if (dir == AccessDirection.READ) {
- accessorKind = "Getter";
- }
- else if (dir == AccessDirection.WRITE) {
- accessorKind = "Setter";
- }
- else {
- accessorKind = "Deleter";
- }
- if (followed != null) myEpilog.addWith(TagSmall, $(BR, BR, accessorKind, " of property")).addItem(BR);
- }
- }
- }
- }
- }
- }
+ final PsiElement outerElement = myOriginalElement != null ? myOriginalElement.getParent() : null;
+
+ final PsiElement elementDefinition = resolveToDocStringOwner();
+ final boolean isProperty = buildFromProperty(elementDefinition, outerElement, context);
if (myProlog.isEmpty() && !isProperty && !isAttribute()) {
- myProlog.add(reassignCat);
- }
-
- // now followed may contain a doc string
- if (followed instanceof PyDocStringOwner) {
- String docString = null;
- final PyStringLiteralExpression docExpr = ((PyDocStringOwner)followed).getDocStringExpression();
- if (docExpr != null) docString = docExpr.getStringValue();
- // doc of what?
- if (followed instanceof PyClass) {
- cls = (PyClass)followed;
- myBody.add(PythonDocumentationProvider.describeDecorators(cls, TagItalic, BR, LCombUp));
- myBody.add(PythonDocumentationProvider.describeClass(cls, TagBold, true, false));
+ myProlog.add(myReassignmentChain);
+ }
+
+ if (elementDefinition instanceof PyDocStringOwner) {
+ buildFromDocstring(elementDefinition, isProperty);
+ }
+ else if (isAttribute()) {
+ buildFromAttributeDoc();
+ }
+ else if (elementDefinition instanceof PyNamedParameter) {
+ buildFromParameter(context, outerElement, elementDefinition);
+ }
+ else if (elementDefinition != null && outerElement instanceof PyReferenceExpression) {
+ myBody.addItem(combUp("\nInferred type: "));
+ PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outerElement, context);
+ }
+
+ if (elementDefinition != null &&
+ PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(elementDefinition.getNode().getElementType())) {
+ buildForKeyword(elementDefinition.getText());
+ }
+ final String url = PythonDocumentationProvider.getUrlFor(myElement, myOriginalElement, true);
+ if (url != null) {
+ myEpilog.addItem(BR);
+ myEpilog.addWith(TagBold, $("External documentation:"));
+ myEpilog.addItem(BR);
+ myEpilog.addItem("<a href=\"").addItem(url).addItem("\">").addItem(url).addItem("</a>");
+ }
+
+ if (myBody.isEmpty() && myEpilog.isEmpty()) {
+ return null; // got nothing substantial to say!
+ }
+ else {
+ return myResult.toString();
+ }
+ }
+
+ private void buildForKeyword(@NotNull final String name) {
+ try {
+ final FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/python_keywords/" + name));
+ try {
+ final String text = FileUtil.loadTextAndClose(reader);
+ myEpilog.addItem(text);
}
- else if (followed instanceof PyFunction) {
- final PyFunction fun = (PyFunction)followed;
- if (!isProperty) {
- cls = fun.getContainingClass();
- if (cls != null) {
- myBody.addWith(TagSmall, PythonDocumentationProvider.describeClass(cls, TagCode, true, true)).addItem(BR).addItem(BR);
- }
- }
- else {
- cls = null;
+ catch (IOException ignored) {
+ }
+ finally {
+ try {
+ reader.close();
}
- myBody
- .add(PythonDocumentationProvider.describeDecorators(fun, TagItalic, BR, LCombUp))
- .add(PythonDocumentationProvider.describeFunction(fun, TagBold, LCombUp));
- if (docString == null) {
- addInheritedDocString(fun, cls);
+ catch (IOException ignored) {
}
}
- else if (followed instanceof PyFile) {
- addModulePath((PyFile)followed);
- }
- if (docString != null) {
- myBody.addItem(BR);
- addFormattedDocString(myElement, docString, myBody, myEpilog);
- }
}
- else if (isProperty) {
- // if it was a normal accessor, ti would be a function, handled by previous branch
- final String accessorMessage;
- if (followed != null) {
- accessorMessage = "Declaration: ";
- }
- else {
- accessorMessage = accessorKind + " is not defined.";
- }
- myBody.addWith(TagItalic, $(accessorMessage)).addItem(BR);
- if (followed != null) myBody.addItem(combUp(PyUtil.getReadableRepr(followed, false)));
+ catch (FileNotFoundException ignored) {
}
- else if (isAttribute()) {
- addAttributeDoc();
- }
- else if (followed instanceof PyNamedParameter) {
- myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(followed, false)));
- final boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)followed);
- if (outer instanceof PyExpression) {
- final PyType type = context.getType((PyExpression)outer);
- if (type != null) {
- String s = null;
- if (type instanceof PyDynamicallyEvaluatedType) {
- if (!typeFromDocstringAdded) {
- //don't add dynamic type if docstring type specified
- s = "\nDynamically inferred type: ";
- }
+ }
+
+ private void buildFromParameter(@NotNull final TypeEvalContext context, @Nullable final PsiElement outerElement,
+ @NotNull final PsiElement elementDefinition) {
+ myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(elementDefinition, false)));
- boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)elementDefinition);
++ final boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)elementDefinition);
+ if (outerElement instanceof PyExpression) {
- PyType type = context.getType((PyExpression)outerElement);
++ final PyType type = context.getType((PyExpression)outerElement);
+ if (type != null) {
+ String typeString = null;
+ if (type instanceof PyDynamicallyEvaluatedType) {
+ if (!typeFromDocstringAdded) {
+ typeString = "\nDynamically inferred type: ";
}
- else {
- if (outer.getReference() != null) {
- final PsiElement target = outer.getReference().resolve();
+ }
+ else {
+ if (outerElement.getReference() != null) {
- PsiElement target = outerElement.getReference().resolve();
++ final PsiElement target = outerElement.getReference().resolve();
- if (target instanceof PyTargetExpression &&
- ((PyTargetExpression)target).getName().equals(((PyNamedParameter)followed).getName())) {
- s = "\nReassigned value has type: ";
+ if (target instanceof PyTargetExpression) {
+ final String targetName = ((PyTargetExpression)target).getName();
+ if (targetName != null && targetName.equals(((PyNamedParameter)elementDefinition).getName())) {
+ typeString = "\nReassigned value has type: ";
}
}
}
}
}
}
- else if (followed != null && outer instanceof PyReferenceExpression) {
- myBody.addItem(combUp("\nInferred type: "));
- PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outer, context);
+ }
+
+ private boolean buildFromProperty(PsiElement elementDefinition, @Nullable final PsiElement outerElement,
+ @NotNull final TypeEvalContext context) {
+ if (myOriginalElement == null) {
+ return false;
}
- if (myBody.isEmpty() && myEpilog.isEmpty()) {
- return null; // got nothing substantial to say!
+ final String elementName = myOriginalElement.getText();
+ if (!PyNames.isIdentifier(elementName)) {
+ return false;
+ }
+ if (!(outerElement instanceof PyQualifiedExpression)) {
+ return false;
+ }
+ final PyExpression qualifier = ((PyQualifiedExpression)outerElement).getQualifier();
+ if (qualifier == null) {
+ return false;
+ }
+ final PyType type = context.getType(qualifier);
+ if (!(type instanceof PyClassType)) {
+ return false;
+ }
+ final PyClass cls = ((PyClassType)type).getPyClass();
+ final Property property = cls.findProperty(elementName, true, null);
+ if (property == null) {
+ return false;
+ }
+
+ final AccessDirection direction = AccessDirection.of((PyElement)outerElement);
+ final Maybe<PyCallable> accessor = property.getByDirection(direction);
+ myProlog.addItem("property ").addWith(TagBold, $().addWith(TagCode, $(elementName)))
+ .addItem(" of ").add(PythonDocumentationProvider.describeClass(cls, TagCode, true, true));
+ if (accessor.isDefined() && property.getDoc() != null) {
+ myBody.addItem(": ").addItem(property.getDoc()).addItem(BR);
}
else {
- return myResult.toString();
+ final PyCallable getter = property.getGetter().valueOrNull();
+ if (getter != null && getter != myElement && getter instanceof PyFunction) {
+ // not in getter, getter's doc comment may be useful
+ final PyStringLiteralExpression docstring = ((PyFunction)getter).getDocStringExpression();
+ if (docstring != null) {
+ myProlog
+ .addItem(BR).addWith(TagItalic, $("Copied from getter:")).addItem(BR)
+ .addItem(docstring.getStringValue())
+ ;
+ }
+ }
+ myBody.addItem(BR);
+ }
+ myBody.addItem(BR);
+ 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);
+ }
+
+ 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;
+ }
+
+ @NotNull
+ private static String getAccessorKind(@NotNull final AccessDirection dir) {
+ final String accessorKind;
+ if (dir == AccessDirection.READ) {
+ accessorKind = "Getter";
+ }
+ else if (dir == AccessDirection.WRITE) {
+ accessorKind = "Setter";
+ }
+ else {
+ accessorKind = "Deleter";
+ }
+ return accessorKind;
+ }
+
+ private void buildFromDocstring(@NotNull final PsiElement elementDefinition, boolean isProperty) {
+ PyClass pyClass = null;
+ final PyStringLiteralExpression docStringExpression = ((PyDocStringOwner)elementDefinition).getDocStringExpression();
+
+ if (elementDefinition instanceof PyClass) {
+ pyClass = (PyClass)elementDefinition;
+ myBody.add(PythonDocumentationProvider.describeDecorators(pyClass, TagItalic, BR, LCombUp));
+ myBody.add(PythonDocumentationProvider.describeClass(pyClass, TagBold, true, false));
+ }
+ else if (elementDefinition instanceof PyFunction) {
- PyFunction pyFunction = (PyFunction)elementDefinition;
++ final PyFunction pyFunction = (PyFunction)elementDefinition;
+ if (!isProperty) {
+ pyClass = pyFunction.getContainingClass();
+ if (pyClass != null) {
+ myBody.addWith(TagSmall, PythonDocumentationProvider.describeClass(pyClass, TagCode, true, true)).addItem(BR).addItem(BR);
+ }
+ }
+ myBody.add(PythonDocumentationProvider.describeDecorators(pyFunction, TagItalic, BR, LCombUp))
+ .add(PythonDocumentationProvider.describeFunction(pyFunction, TagBold, LCombUp));
+ if (docStringExpression == null) {
+ addInheritedDocString(pyFunction, pyClass);
+ }
+ }
+ else if (elementDefinition instanceof PyFile) {
+ addModulePath((PyFile)elementDefinition);
+ }
+ if (docStringExpression != null) {
+ myBody.addItem(BR);
+ addFormattedDocString(myElement, docStringExpression.getStringValue(), myBody, myEpilog);
}
}
final PyCallExpression call = (PyCallExpression)myElement;
final Pair<String, PyFunction> wrapInfo = PyCallExpressionHelper.interpretAsModifierWrappingCall(call, myOriginalElement);
if (wrapInfo != null) {
- String wrapperName = wrapInfo.getFirst();
- PyFunction wrappedFunction = wrapInfo.getSecond();
+ final String wrapperName = wrapInfo.getFirst();
- final PyFunction wrappedFunc = wrapInfo.getSecond();
- //prologCat.addWith(TagSmall, $("Wrapped in ").addWith(TagCode, $(wrapperName)).add(BR));
- prologCat.addWith(TagSmall, $(PyBundle.message("QDOC.wrapped.in.$0", wrapperName)).addItem(BR));
- return wrappedFunc;
++ final PyFunction wrappedFunction = wrapInfo.getSecond();
+ myReassignmentChain.addWith(TagSmall, $(PyBundle.message("QDOC.wrapped.in.$0", wrapperName)).addItem(BR));
+ return wrappedFunction;
}
}
return myElement;
return resolveResult.isImplicit() ? null : resolveResult.getElement();
}
- private void addInheritedDocString(@NotNull PyFunction fun, @Nullable PyClass cls) {
+ private void addInheritedDocString(@NotNull final PyFunction pyFunction, @Nullable final PyClass pyClass) {
boolean notFound = true;
- final String methName = fun.getName();
- if (cls != null && methName != null) {
- final boolean isConstructor = PyNames.INIT.equals(methName);
- // look for inherited and its doc
- Iterable<PyClass> classes = cls.getAncestorClasses(null);
- if (isConstructor) {
- // look at our own class again and maybe inherit class's doc
- classes = new ChainIterable<PyClass>(cls).add(classes);
+ final String methodName = pyFunction.getName();
+ if (pyClass == null || methodName == null) {
+ return;
+ }
+ final boolean isConstructor = PyNames.INIT.equals(methodName);
+ Iterable<PyClass> classes = pyClass.getAncestorClasses(null);
+ if (isConstructor) {
+ // look at our own class again and maybe inherit class's doc
+ classes = new ChainIterable<PyClass>(pyClass).add(classes);
+ }
+ for (PyClass ancestor : classes) {
+ PyStringLiteralExpression docstringElement = null;
+ PyFunction inherited = null;
+ boolean isFromClass = false;
+ if (isConstructor) docstringElement = pyClass.getDocStringExpression();
+ if (docstringElement != null) {
+ isFromClass = true;
}
- for (PyClass ancestor : classes) {
- PyStringLiteralExpression docElt = null;
- PyFunction inherited = null;
- boolean isFromClass = false;
- if (isConstructor) docElt = cls.getDocStringExpression();
- if (docElt != null) {
- isFromClass = true;
- }
- else {
- inherited = ancestor.findMethodByName(methName, false);
- }
- if (inherited != null) {
- docElt = inherited.getDocStringExpression();
- }
- if (docElt != null) {
- final String inheritedDoc = docElt.getStringValue();
- if (inheritedDoc.length() > 1) {
- myEpilog.addItem(BR).addItem(BR);
- final String ancestorName = ancestor.getName();
- final String marker =
- (cls == ancestor) ? PythonDocumentationProvider.LINK_TYPE_CLASS : PythonDocumentationProvider.LINK_TYPE_PARENT;
- final String ancestorLink =
- $().addWith(new LinkWrapper(marker + ancestorName), $(ancestorName)).toString();
- if (isFromClass) {
- myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestorLink));
- }
- else {
- myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestorLink, methName));
- }
- myEpilog.addItem(BR).addItem(BR);
- final ChainIterable<String> formatted = new ChainIterable<String>();
- final ChainIterable<String> unformatted = new ChainIterable<String>();
- addFormattedDocString(fun, inheritedDoc, formatted, unformatted);
- myEpilog.addWith(TagCode, formatted).add(unformatted);
- notFound = false;
- break;
+ else {
+ inherited = ancestor.findMethodByName(methodName, false);
+ }
+ if (inherited != null) {
+ docstringElement = inherited.getDocStringExpression();
+ }
+ if (docstringElement != null) {
+ final String inheritedDoc = docstringElement.getStringValue();
+ if (inheritedDoc.length() > 1) {
+ myEpilog.addItem(BR).addItem(BR);
- String ancestor_name = ancestor.getName();
- String marker = (pyClass == ancestor) ? PythonDocumentationProvider.LINK_TYPE_CLASS : PythonDocumentationProvider.LINK_TYPE_PARENT;
- final String ancestor_link =
- $().addWith(new LinkWrapper(marker + ancestor_name), $(ancestor_name)).toString();
++ final String ancestorName = ancestor.getName();
++ final String marker = (pyClass == ancestor) ? PythonDocumentationProvider.LINK_TYPE_CLASS : PythonDocumentationProvider.LINK_TYPE_PARENT;
++ final String ancestorLink =
++ $().addWith(new LinkWrapper(marker + ancestorName), $(ancestorName)).toString();
+ if (isFromClass) {
- myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestor_link));
++ myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestorLink));
+ }
+ else {
- myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestor_link, methodName));
++ myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestorLink, methodName));
}
- ChainIterable<String> formatted = new ChainIterable<String>();
- ChainIterable<String> unformatted = new ChainIterable<String>();
+ myEpilog.addItem(BR).addItem(BR);
++ final ChainIterable<String> formatted = new ChainIterable<String>();
++ final ChainIterable<String> unformatted = new ChainIterable<String>();
+ addFormattedDocString(pyFunction, inheritedDoc, formatted, unformatted);
+ myEpilog.addWith(TagCode, formatted).add(unformatted);
+ notFound = false;
+ break;
}
}
+ }
- if (notFound) {
- // above could have not worked because inheritance is not searched down to 'object'.
- // for well-known methods, copy built-in doc string.
- // TODO: also handle predefined __xxx__ that are not part of 'object'.
- if (PyNames.UnderscoredAttributes.contains(methName)) {
- addPredefinedMethodDoc(fun, methName);
- }
+ if (notFound) {
+ // above could have not worked because inheritance is not searched down to 'object'.
+ // for well-known methods, copy built-in doc string.
+ // TODO: also handle predefined __xxx__ that are not part of 'object'.
+ if (PyNames.UnderscoredAttributes.contains(methodName)) {
+ addPredefinedMethodDoc(pyFunction, methodName);
}
}
}
- private void addPredefinedMethodDoc(@NotNull PyFunction fun, String methName) {
- final PyClassType objtype = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
- if (objtype != null) {
- final PyClass objcls = objtype.getPyClass();
- final PyFunction objUnderscored = objcls.findMethodByName(methName, false);
- if (objUnderscored != null) {
- final PyStringLiteralExpression predefinedDocExpr = objUnderscored.getDocStringExpression();
- final String predefinedDoc = predefinedDocExpr != null ? predefinedDocExpr.getStringValue() : null;
+ private void addPredefinedMethodDoc(PyFunction fun, String mothodName) {
- PyClassType objectType = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
++ final PyClassType objectType = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
+ if (objectType != null) {
- PyClass objectClass = objectType.getPyClass();
- PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
++ final PyClass objectClass = objectType.getPyClass();
++ final PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
+ if (predefinedMethod != null) {
- PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
- String predefinedDoc = predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
++ final PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
++ final String predefinedDoc = predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
if (predefinedDoc != null && predefinedDoc.length() > 1) { // only a real-looking doc string counts
addFormattedDocString(fun, predefinedDoc, myBody, myBody);
myEpilog.addItem(BR).addItem(BR).addItem(PyBundle.message("QDOC.copied.from.builtin"));
return false;
}
- private static Pair<String, String> getTypeAndDescr(String docString, @NotNull PyNamedParameter followed) {
- final StructuredDocString structuredDocString = docString != null ? DocStringUtil.parse(docString, followed) : null;
+ private static Pair<String, String> getTypeAndDescription(@Nullable final String docString, @NotNull final PyNamedParameter followed) {
- StructuredDocString structuredDocString = DocStringUtil.parse(docString);
String type = null;
String desc = null;
-- if (structuredDocString != null) {
++ if (docString != null) {
++ final StructuredDocString structuredDocString = DocStringUtil.parse(docString);
final String name = followed.getName();
type = structuredDocString.getParamType(name);
--
desc = structuredDocString.getParamDescription(name);
}
--
return Pair.create(type, desc);
}
- private void addAttributeDoc() {
+ private void buildFromAttributeDoc() {
- PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class);
+ final PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class);
assert cls != null;
- String type = PyUtil.isInstanceAttribute((PyExpression)myElement) ? "Instance attribute " : "Class attribute ";
+ final String type = PyUtil.isInstanceAttribute((PyExpression)myElement) ? "Instance attribute " : "Class attribute ";
myProlog
.addItem(type).addWith(TagBold, $().addWith(TagCode, $(((PyTargetExpression)myElement).getName())))
- .addItem(" of class ").addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName()))).addItem(BR)
- ;
+ .addItem(" of class ").addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName()))).addItem(BR);
final String docString = ((PyTargetExpression)myElement).getDocStringValue();
if (docString != null) {
}
}
- public static String[] removeCommonIndentation(String docstring) {
+ public static String[] removeCommonIndentation(@NotNull final String docstring) {
// detect common indentation
- String[] lines = LineTokenizer.tokenize(docstring, false);
+ final String[] lines = LineTokenizer.tokenize(docstring, false);
boolean isFirst = true;
int cutWidth = Integer.MAX_VALUE;
int firstIndentedLine = 0;