protected boolean isValidIntroduceContext(PsiElement element) { PyDecorator decorator = PsiTreeUtil.getParentOfType(element, PyDecorator.class); if (decorator != null && PsiTreeUtil.isAncestor(decorator.getCallee(), element, false)) { return false; } return PsiTreeUtil.getParentOfType(element, PyParameterList.class) == null; }
@Nullable private static PsiElement resolveDecorator(@NotNull PyDecorator decorator) { final PyExpression callee = decorator.getCallee(); if (callee == null) { return null; } final PsiReference reference = callee.getReference(); if (reference == null) { return null; } return reference.resolve(); }
/** * Map decorators of element to {@link * com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator}. * * @param element decoratable element to check * @param context type evaluation context. If it doesn't allow switch to AST, decorators will be * compared by the text of the last component of theirs qualified names. * @return list of known decorators in declaration order with duplicates (with any) */ @NotNull public static List<KnownDecorator> getKnownDecorators( @NotNull PyDecoratable element, @NotNull TypeEvalContext context) { final PyDecoratorList decoratorList = element.getDecoratorList(); if (decoratorList == null) { return Collections.emptyList(); } final List<KnownDecorator> result = new ArrayList<>(); final boolean allowResolve = context.maySwitchToAST((PsiElement) element); for (PyDecorator decorator : decoratorList.getDecorators()) { final QualifiedName qualifiedName = decorator.getQualifiedName(); if (qualifiedName == null) { continue; } final KnownDecorator knownDecorator = ourByShortName.get(qualifiedName.getLastComponent()); if (knownDecorator != null) { if (allowResolve) { PyQualifiedNameOwner resolved = as(resolveDecorator(decorator), PyQualifiedNameOwner.class); if (resolved instanceof PyFunction && PyNames.INIT.equals(resolved.getName())) { resolved = ((PyFunction) resolved).getContainingClass(); } if (resolved != null && resolved.getQualifiedName() != null) { final QualifiedName resolvedName = QualifiedName.fromDottedString(resolved.getQualifiedName()); if (resolvedName.equals(knownDecorator.getQualifiedName())) { result.add(knownDecorator); } } } else { result.add(knownDecorator); } } } return result; }
/** * When a function is decorated many decorators, finds the deepest builtin decorator: * * <pre> * @foo * @classmethod <b># <-- that's it</b> * @bar * def moo(cls): * pass * </pre> * * @return name of the built-in decorator, or null (even if there are non-built-in decorators). */ @Nullable private String getClassOrStaticMethodDecorator() { PyDecoratorList decolist = getDecoratorList(); if (decolist != null) { PyDecorator[] decos = decolist.getDecorators(); if (decos.length > 0) { for (int i = decos.length - 1; i >= 0; i -= 1) { PyDecorator deco = decos[i]; String deconame = deco.getName(); if (PyNames.CLASSMETHOD.equals(deconame) || PyNames.STATICMETHOD.equals(deconame)) { return deconame; } for (PyKnownDecoratorProvider provider : PyUtil.KnownDecoratorProviderHolder.KNOWN_DECORATOR_PROVIDERS) { String name = provider.toKnownDecorator(deconame); if (name != null) { return name; } } } } } return null; }
@Nullable public static PyType getTypeFromTarget( @NotNull final PsiElement target, final TypeEvalContext context, PyReferenceExpression anchor) { if (!(target instanceof PyTargetExpression)) { // PyTargetExpression will ask about its type itself final PyType pyType = getReferenceTypeFromProviders(target, context, anchor); if (pyType != null) { return pyType; } } if (target instanceof PyTargetExpression) { final String name = ((PyTargetExpression) target).getName(); if (PyNames.NONE.equals(name)) { return PyNoneType.INSTANCE; } if (PyNames.TRUE.equals(name) || PyNames.FALSE.equals(name)) { return PyBuiltinCache.getInstance(target).getBoolType(); } } if (target instanceof PyFile) { return new PyModuleType((PyFile) target); } if (target instanceof PyImportedModule) { return new PyImportedModuleType((PyImportedModule) target); } if ((target instanceof PyTargetExpression || target instanceof PyNamedParameter) && anchor != null && context.allowDataFlow(anchor)) { final ScopeOwner scopeOwner = PsiTreeUtil.getStubOrPsiParentOfType(anchor, ScopeOwner.class); if (scopeOwner != null && scopeOwner == PsiTreeUtil.getStubOrPsiParentOfType(target, ScopeOwner.class)) { final String name = ((PyElement) target).getName(); if (name != null) { final PyType type = getTypeByControlFlow(name, context, anchor, scopeOwner); if (type != null) { return type; } } } } if (target instanceof PyFunction) { final PyDecoratorList decoratorList = ((PyFunction) target).getDecoratorList(); if (decoratorList != null) { final PyDecorator propertyDecorator = decoratorList.findDecorator(PyNames.PROPERTY); if (propertyDecorator != null) { return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); } for (PyDecorator decorator : decoratorList.getDecorators()) { final QualifiedName qName = decorator.getQualifiedName(); if (qName != null && (qName.endsWith(PyNames.SETTER) || qName.endsWith(PyNames.DELETER) || qName.endsWith(PyNames.GETTER))) { return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); } } } } if (target instanceof PyTypedElement) { return context.getType((PyTypedElement) target); } if (target instanceof PsiDirectory) { final PsiDirectory dir = (PsiDirectory) target; PsiFile file = dir.findFile(PyNames.INIT_DOT_PY); if (file != null) { return getTypeFromTarget(file, context, anchor); } if (PyUtil.isPackage(dir, anchor)) { final PsiFile containingFile = anchor.getContainingFile(); if (containingFile instanceof PyFile) { final QualifiedName qualifiedName = QualifiedNameFinder.findShortestImportableQName(dir); if (qualifiedName != null) { final PyImportedModule module = new PyImportedModule(null, (PyFile) containingFile, qualifiedName); return new PyImportedModuleType(module); } } } } return null; }