@Override
  public void processVariants(@NotNull PsiScopeProcessor processor) {
    List<ElementFilter> filters = new ArrayList<>();

    if (isInCode() && !(getParent() instanceof PsiImportStatement) && !(getParent() instanceof PsiReferenceList)) {
      filters.add(new AndFilter(ElementClassFilter.METHOD, new NotFilter(new ConstructorFilter())));
      filters.add(ElementClassFilter.VARIABLE);
    }

    switch (getKindEnum(getContainingFile())) {
      case CLASS_OR_PACKAGE_NAME_KIND:
        filters.add(ElementClassFilter.CLASS);
        filters.add(ElementClassFilter.PACKAGE);
        break;
      case CLASS_NAME_KIND:
        filters.add(ElementClassFilter.CLASS);
        if (isQualified() || PsiTreeUtil.getParentOfType(this, PsiJavaModule.class) != null) {
          filters.add(ElementClassFilter.PACKAGE);
        }
        break;
      case PACKAGE_NAME_KIND:
        filters.add(ElementClassFilter.PACKAGE);
        break;
      case CLASS_FQ_NAME_KIND:
      case CLASS_FQ_OR_PACKAGE_NAME_KIND:
        filters.add(ElementClassFilter.PACKAGE);
        if (isQualified() || isCodeFragmentType(getTreeParent().getElementType())) {
          filters.add(ElementClassFilter.CLASS);
        }
        break;
      case CLASS_IN_QUALIFIED_NEW_KIND:
        PsiElement parent = getParent();
        if (parent instanceof PsiNewExpression) {
          PsiExpression qualifier = ((PsiNewExpression)parent).getQualifier();
          assert qualifier != null : parent;
          PsiType type = qualifier.getType();
          PsiClass aClass = PsiUtil.resolveClassInType(type);
          if (aClass != null) {
            AndFilter filter = new AndFilter(ElementClassFilter.CLASS, new ModifierFilter(PsiModifier.STATIC, false));
            aClass.processDeclarations(new FilterScopeProcessor<>(filter, processor), ResolveState.initial(), null, this);
          }
        }
        return;
      case MODULE_NAME_KIND:
        return;
      default:
        throw new RuntimeException("Unknown reference type");
    }

    OrFilter filter = new OrFilter(filters.toArray(ElementFilter.EMPTY_ARRAY));
    FilterScopeProcessor<PsiTypeParameter> proc = new FilterScopeProcessor<>(filter, processor);

    for (PsiTypeParameter typeParameter : getUnfinishedMethodTypeParameters()) {
      if (!proc.execute(typeParameter, ResolveState.initial())) {
        return;
      }
    }

    PsiScopesUtil.resolveAndWalk(proc, this, null, true);
  }
@Override
  public void processVariants(@NotNull PsiScopeProcessor processor)