@Nullable private static PyType getParameterizedType( @NotNull PsiElement element, @NotNull Context context) { if (element instanceof PySubscriptionExpression) { final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression) element; final PyExpression operand = subscriptionExpr.getOperand(); final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); final PyType operandType = getType(operand, context); if (operandType instanceof PyClassType) { final PyClass cls = ((PyClassType) operandType).getPyClass(); final List<PyType> indexTypes = getIndexTypes(subscriptionExpr, context); if (PyNames.TUPLE.equals(cls.getQualifiedName())) { if (indexExpr instanceof PyTupleExpression) { final PyExpression[] elements = ((PyTupleExpression) indexExpr).getElements(); if (elements.length == 2 && isEllipsis(elements[1])) { return PyTupleType.createHomogeneous(element, indexTypes.get(0)); } } return PyTupleType.create(element, indexTypes); } else if (indexExpr != null) { return new PyCollectionTypeImpl(cls, false, indexTypes); } } } return null; }
public Property getProperty() { final PyClass containingClass = getContainingClass(); if (containingClass != null) { return containingClass.findPropertyByCallable(this); } return null; }
@NotNull private static List<PyGenericType> collectGenericTypes( @NotNull PyClass cls, @NotNull Context context) { boolean isGeneric = false; for (PyClass ancestor : cls.getAncestorClasses(context.getTypeContext())) { if (GENERIC_CLASSES.contains(ancestor.getQualifiedName())) { isGeneric = true; break; } } if (isGeneric) { final ArrayList<PyGenericType> results = new ArrayList<>(); // XXX: Requires switching from stub to AST for (PyExpression expr : cls.getSuperClassExpressions()) { if (expr instanceof PySubscriptionExpression) { final PyExpression indexExpr = ((PySubscriptionExpression) expr).getIndexExpression(); if (indexExpr != null) { for (PsiElement resolved : tryResolving(indexExpr, context.getTypeContext())) { final PyGenericType genericType = getGenericType(resolved, context); if (genericType != null) { results.add(genericType); } } } } } return results; } return Collections.emptyList(); }
@Nullable private Ref<PyType> getTypeOfProperty( @Nullable PyType qualifierType, @NotNull String name, @NotNull TypeEvalContext context) { if (qualifierType instanceof PyClassType) { final PyClassType classType = (PyClassType) qualifierType; PyClass pyClass = classType.getPyClass(); Property property = pyClass.findProperty(name, true); if (property != null) { if (classType.isDefinition()) { return Ref.<PyType>create( PyBuiltinCache.getInstance(pyClass).getObjectType(PyNames.PROPERTY)); } if (AccessDirection.of(this) == AccessDirection.READ) { final PyType type = property.getType(context); if (type != null) { return Ref.create(type); } } return Ref.create(); } } else if (qualifierType instanceof PyUnionType) { final PyUnionType unionType = (PyUnionType) qualifierType; for (PyType type : unionType.getMembers()) { final Ref<PyType> result = getTypeOfProperty(type, name, context); if (result != null) { return result; } } } return null; }
/** * Looks for two standard decorators to a function, or a wrapping assignment that closely follows * it. * * @return a flag describing what was detected. */ @Nullable public Modifier getModifier() { final String deconame = getClassOrStaticMethodDecorator(); if (PyNames.CLASSMETHOD.equals(deconame)) { return CLASSMETHOD; } else if (PyNames.STATICMETHOD.equals(deconame)) { return STATICMETHOD; } // implicit staticmethod __new__ final PyClass cls = getContainingClass(); if (cls != null && PyNames.NEW.equals(getName()) && cls.isNewStyleClass(null)) { return STATICMETHOD; } // if (getStub() != null) { return getWrappersFromStub(); } final String funcName = getName(); if (funcName != null) { PyAssignmentStatement currentAssignment = PsiTreeUtil.getNextSiblingOfType(this, PyAssignmentStatement.class); while (currentAssignment != null) { final String modifier = currentAssignment .getTargetsToValuesMapping() .stream() .filter( pair -> pair.getFirst() instanceof PyTargetExpression && funcName.equals(pair.getFirst().getName())) .filter(pair -> pair.getSecond() instanceof PyCallExpression) .map( pair -> interpretAsModifierWrappingCall((PyCallExpression) pair.getSecond(), this)) .filter(interpreted -> interpreted != null && interpreted.getSecond() == this) .map(interpreted -> interpreted.getFirst()) .filter( wrapperName -> PyNames.CLASSMETHOD.equals(wrapperName) || PyNames.STATICMETHOD.equals(wrapperName)) .findAny() .orElse(null); if (PyNames.CLASSMETHOD.equals(modifier)) { return CLASSMETHOD; } else if (PyNames.STATICMETHOD.equals(modifier)) { return STATICMETHOD; } currentAssignment = PsiTreeUtil.getNextSiblingOfType(currentAssignment, PyAssignmentStatement.class); } } return null; }
protected String getElementLocation() { final PyClass containingClass = getContainingClass(); if (containingClass != null) { return "(" + containingClass.getName() + " in " + getPackageForFile(getContainingFile()) + ")"; } return super.getElementLocation(); }
/** * Looks for two standard decorators to a function, or a wrapping assignment that closely follows * it. * * @return a flag describing what was detected. */ @Nullable public Modifier getModifier() { String deconame = getClassOrStaticMethodDecorator(); if (PyNames.CLASSMETHOD.equals(deconame)) { return CLASSMETHOD; } else if (PyNames.STATICMETHOD.equals(deconame)) { return STATICMETHOD; } // implicit staticmethod __new__ PyClass cls = getContainingClass(); if (cls != null && PyNames.NEW.equals(getName()) && cls.isNewStyleClass()) { return STATICMETHOD; } // if (getStub() != null) { return getWrappersFromStub(); } String func_name = getName(); if (func_name != null) { PyAssignmentStatement assignment = PsiTreeUtil.getNextSiblingOfType(this, PyAssignmentStatement.class); if (assignment != null) { for (Pair<PyExpression, PyExpression> pair : assignment.getTargetsToValuesMapping()) { PyExpression value = pair.getSecond(); if (value instanceof PyCallExpression) { PyExpression target = pair.getFirst(); if (target instanceof PyTargetExpression && func_name.equals(target.getName())) { Pair<String, PyFunction> interpreted = interpretAsModifierWrappingCall((PyCallExpression) value, this); if (interpreted != null) { PyFunction original = interpreted.getSecond(); if (original == this) { String wrapper_name = interpreted.getFirst(); if (PyNames.CLASSMETHOD.equals(wrapper_name)) { return CLASSMETHOD; } else if (PyNames.STATICMETHOD.equals(wrapper_name)) { return STATICMETHOD; } } } } } } } } return null; }
private void buildFromAttributeDoc() { PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class); assert cls != null; 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); final String docString = ((PyTargetExpression) myElement).getDocStringValue(); if (docString != null) { addFormattedDocString(myElement, docString, myBody, myEpilog); } }
private void addPredefinedMethodDoc(PyFunction fun, String mothodName) { 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); if (predefinedMethod != null) { PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression(); 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")); } } } }
@Nullable @Override public String getQualifiedName() { String name = getName(); if (name == null) { return null; } PyClass containingClass = getContainingClass(); if (containingClass != null) { return containingClass.getQualifiedName() + "." + name; } if (PsiTreeUtil.getStubOrPsiParent(this) instanceof PyFile) { VirtualFile virtualFile = getContainingFile().getVirtualFile(); if (virtualFile != null) { final String packageName = QualifiedNameFinder.findShortestImportableName(this, virtualFile); return packageName + "." + name; } } return null; }
private void addInheritedDocString( @NotNull final PyFunction pyFunction, @Nullable final PyClass pyClass) { boolean notFound = true; 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; } 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(); if (isFromClass) { myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestor_link)); } else { myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestor_link, methodName)); } myEpilog.addItem(BR).addItem(BR); ChainIterable<String> formatted = new ChainIterable<String>(); 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(methodName)) { addPredefinedMethodDoc(pyFunction, methodName); } } }
private boolean buildFromProperty( PsiElement elementDefinition, @Nullable final PsiElement outerElement, @NotNull final TypeEvalContext context) { if (myOriginalElement == null) { return false; } 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 { 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; }