private void declareCompletionSpaces() {
    declareFinalScope(PsiFile.class);

    {
      // Class body
      final CompletionVariant variant = new CompletionVariant(CLASS_BODY.getValue());
      variant.includeScopeClass(PsiClass.class, true);
      registerVariant(variant);
    }
    {
      // Method body
      final CompletionVariant variant =
          new CompletionVariant(
              new AndFilter(
                  new InsideElementFilter(new ClassFilter(PsiCodeBlock.class)),
                  new NotFilter(
                      new InsideElementFilter(
                          new ClassFilter(JspClassLevelDeclarationStatement.class)))));
      variant.includeScopeClass(PsiMethod.class, true);
      variant.includeScopeClass(PsiClassInitializer.class, true);
      registerVariant(variant);
    }

    {
      // Field initializer
      final CompletionVariant variant =
          new CompletionVariant(new AfterElementFilter(new TextFilter("=")));
      variant.includeScopeClass(PsiField.class, true);
      registerVariant(variant);
    }

    declareFinalScope(PsiLiteralExpression.class);
    declareFinalScope(PsiComment.class);
  }
  private void initVariantsInMethodScope() {
    // Completion for classes in method throws section
    // position
    {
      final ElementFilter position =
          new LeftNeighbour(
              new AndFilter(
                  new TextFilter(")"),
                  new ParentElementFilter(new ClassFilter(PsiParameterList.class))));

      // completion
      CompletionVariant variant = new CompletionVariant(PsiMethod.class, position);
      variant.includeScopeClass(PsiClass.class); // for throws on separate line
      variant.addCompletion(PsiKeyword.THROWS);

      registerVariant(variant);

      // in annotation methods
      variant = new CompletionVariant(PsiAnnotationMethod.class, position);
      variant.addCompletion(PsiKeyword.DEFAULT);
      registerVariant(variant);
    }

    {
      // Keyword completion in returns  !!!!
      final CompletionVariant variant =
          new CompletionVariant(
              PsiMethod.class, new LeftNeighbour(new TextFilter(PsiKeyword.RETURN)));
      variant.addCompletion(PsiKeyword.TRUE, TailType.NONE);
      variant.addCompletion(PsiKeyword.FALSE, TailType.NONE);
      registerVariant(variant);
    }

    // Catch/Finally completion
    {
      final ElementFilter position = AFTER_TRY_BLOCK;

      final CompletionVariant variant = new CompletionVariant(position);
      variant.includeScopeClass(PsiCodeBlock.class, true);
      variant.addCompletion(PsiKeyword.CATCH, TailTypes.CATCH_LPARENTH);
      variant.addCompletion(PsiKeyword.FINALLY, TailTypes.FINALLY_LBRACE);
      registerVariant(variant);
    }

    // Catch/Finally completion
    {
      final ElementFilter position =
          new LeftNeighbour(
              new AndFilter(
                  new TextFilter("}"),
                  new ParentElementFilter(
                      new AndFilter(
                          new LeftNeighbour(new NotFilter(new TextFilter(PsiKeyword.TRY))),
                          new OrFilter(
                              new ParentElementFilter(new ClassFilter(PsiTryStatement.class)),
                              new ParentElementFilter(new ClassFilter(PsiCatchSection.class)))))));

      final CompletionVariant variant = new CompletionVariant(position);
      variant.includeScopeClass(PsiCodeBlock.class, false);
      variant.addCompletion(PsiKeyword.CATCH, TailTypes.CATCH_LPARENTH);
      variant.addCompletion(PsiKeyword.FINALLY, TailTypes.FINALLY_LBRACE);
      registerVariant(variant);
    }

    // Completion for else expression
    // completion
    {
      final ElementFilter position =
          new LeftNeighbour(
              new OrFilter(
                  new AndFilter(
                      new TextFilter("}"),
                      new ParentElementFilter(new ClassFilter(PsiIfStatement.class), 3)),
                  new AndFilter(
                      new TextFilter(";"),
                      new ParentElementFilter(new ClassFilter(PsiIfStatement.class), 2))));
      final CompletionVariant variant = new CompletionVariant(PsiMethod.class, position);
      variant.addCompletion(PsiKeyword.ELSE);

      registerVariant(variant);
    }
  }
  /** aClass == null for JspDeclaration scope */
  protected void initVariantsInClassScope() {
    // Completion for extends keyword
    // position
    {
      final ElementFilter position =
          new AndFilter(
              new NotFilter(CLASS_BODY.getValue()),
              new NotFilter(
                  new AfterElementFilter(new ContentFilter(new TextFilter(PsiKeyword.EXTENDS)))),
              new NotFilter(
                  new AfterElementFilter(new ContentFilter(new TextFilter(PsiKeyword.IMPLEMENTS)))),
              new NotFilter(new LeftNeighbour(new LeftNeighbour(new TextFilter("<", ",")))),
              new NotFilter(new ScopeFilter(new EnumOrAnnotationTypeFilter())),
              new LeftNeighbour(
                  new OrFilter(new ClassFilter(PsiIdentifier.class), new TextFilter(">"))));
      // completion
      final CompletionVariant variant = new CompletionVariant(position);
      variant.includeScopeClass(PsiClass.class, true);
      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
      variant.excludeScopeClass(PsiAnonymousClass.class);
      variant.excludeScopeClass(PsiTypeParameter.class);

      registerVariant(variant);
    }
    // Completion for implements keyword
    // position
    {
      final ElementFilter position =
          new AndFilter(
              new NotFilter(CLASS_BODY.getValue()),
              new NotFilter(
                  new BeforeElementFilter(new ContentFilter(new TextFilter(PsiKeyword.EXTENDS)))),
              new NotFilter(
                  new AfterElementFilter(new ContentFilter(new TextFilter(PsiKeyword.IMPLEMENTS)))),
              new NotFilter(new LeftNeighbour(new LeftNeighbour(new TextFilter("<", ",")))),
              new LeftNeighbour(
                  new OrFilter(new ClassFilter(PsiIdentifier.class), new TextFilter(">"))),
              new NotFilter(new ScopeFilter(new InterfaceFilter())));
      // completion
      final CompletionVariant variant = new CompletionVariant(position);
      variant.includeScopeClass(PsiClass.class, true);
      variant.addCompletion(PsiKeyword.IMPLEMENTS, TailType.HUMBLE_SPACE_BEFORE_WORD);
      variant.excludeScopeClass(PsiAnonymousClass.class);

      registerVariant(variant);
    }

    {
      final CompletionVariant variant =
          new CompletionVariant(
              PsiElement.class,
              psiElement()
                  .afterLeaf(
                      psiElement(PsiIdentifier.class)
                          .afterLeaf(
                              psiElement()
                                  .withText(string().oneOf(",", "<"))
                                  .withParent(PsiTypeParameterList.class))));
      // variant.includeScopeClass(PsiClass.class, true);
      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
      registerVariant(variant);
    }
  }