private static boolean allDecoratorsAreKnown(
     @NotNull PyDecoratable element, @NotNull List<KnownDecorator> decorators) {
   final PyDecoratorList decoratorList = element.getDecoratorList();
   return decoratorList == null
       ? decorators.isEmpty()
       : decoratorList.getDecorators().length == decorators.size();
 }
 /**
  * Checks that given element has any non-builtin decorators.
  *
  * @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.
  * @see PyKnownDecoratorUtil.KnownDecorator
  */
 public static boolean hasNonBuiltinDecorator(
     @NotNull PyDecoratable element, @NotNull TypeEvalContext context) {
   final List<KnownDecorator> knownDecorators = getKnownDecorators(element, context);
   if (!allDecoratorsAreKnown(element, knownDecorators)) {
     return true;
   }
   knownDecorators.removeAll(BUILTIN_DECORATORS);
   return !knownDecorators.isEmpty();
 }
 /**
  * Checks that given function has any decorators from {@code abc} module.
  *
  * @param element Python function 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.
  * @see PyKnownDecoratorUtil.KnownDecorator
  */
 public static boolean hasAbstractDecorator(
     @NotNull PyDecoratable element, @NotNull TypeEvalContext context) {
   final List<KnownDecorator> knownDecorators = getKnownDecorators(element, context);
   if (knownDecorators.isEmpty()) {
     return false;
   }
   knownDecorators.retainAll(ABSTRACT_DECORATORS);
   return !knownDecorators.isEmpty();
 }
  /**
   * 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;
  }