public static void scopeCrawlUp(@NotNull PsiScopeProcessor processor, @NotNull PsiElement element, @Nullable String name,
                                  @Nullable PsiElement roof) {
    ScopeOwner originalOwner = ScopeUtil.getScopeOwner(element);
    PsiElement parent = element.getParent();
    ScopeOwner owner = originalOwner;
    if (parent instanceof PyNonlocalStatement) {
      /* wee need to search in one step out scope for nonlocal statements */
      final ScopeOwner outerScopeOwner = ScopeUtil.getScopeOwner(owner);
      if (outerScopeOwner != null) {
        owner = outerScopeOwner;
      }
    }
    else if (parent instanceof PyGlobalStatement) {
      /* wee need to search directly in global scope of the module for global statements */
      final PsiFile globalScope = element.getContainingFile();
      if (globalScope instanceof PyFile) {
        owner = (PyFile)globalScope;
      }
    }
    if (owner instanceof PyFunction function && function.getTypeParameterList() != null) {
      // Type parameters of generic functions and methods need to be visible in their parameter and return type annotations,
      // so we resolve names in these annotations starting from the containing function's scope, "lowering" their scope in
      // ScopeUtil.getScopeOwner().
      // At the same time, these annotations still need to see names from the class scope, such as nested classes defined there,
      // as if these names were evaluated on a class-level scope.
      PyAnnotation annotation = PsiTreeUtil.getParentOfType(element, PyAnnotation.class);
      if (PsiTreeUtil.getParentOfType(annotation, PyFunction.class, true, PyStatement.class) == function) {
        originalOwner = ScopeUtil.getScopeOwner(function);
      }
    }
    if (owner instanceof PyClass pyClass && pyClass.getTypeParameterList() != null) {
      // The same logic applies to the list of base classes of a generic class
      PyArgumentList superclassList = PsiTreeUtil.getParentOfType(element, PyArgumentList.class);
      if (superclassList != null && superclassList.getParent() == pyClass) {
        originalOwner = ScopeUtil.getScopeOwner(pyClass);
      }
    }
    scopeCrawlUp(processor, owner, originalOwner, name, roof);
  }
public static void scopeCrawlUp(@NotNull PsiScopeProcessor processor, @NotNull PsiElement element, @Nullable String name,
                                  @Nullable PsiElement roof)