@Override
  public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) {
    PsiClass psiClass = (PsiClass)SourceTreeToPsiMap.treeElementToPsi(this);
    if (anchor == null) {
      if (first.getElementType() != JavaDocElementType.DOC_COMMENT) {
        if (before == null) {
          if (first == last) {
            PsiElement firstPsi = SourceTreeToPsiMap.treeElementToPsi(first);
            if (firstPsi instanceof PsiEnumConstant) {
              anchor = findEnumConstantListDelimiterPlace();
              before = anchor != findChildByRole(ChildRole.LBRACE);
            }
            else {
              PsiElement psiElement = firstPsi instanceof PsiMember
                                      ? JavaPsiImplementationHelper.getInstance(psiClass.getProject()).getDefaultMemberAnchor(psiClass, (PsiMember)firstPsi)
                                      : null;
              anchor = psiElement != null ? SourceTreeToPsiMap.psiElementToTree(psiElement) : null;
              before = Boolean.TRUE;
            }
          }
          else {
            anchor = findChildByRole(ChildRole.RBRACE);
            before = Boolean.TRUE;
          }
        }
        else if (!before.booleanValue()) {
          anchor = findChildByRole(ChildRole.LBRACE);
        }
        else {
          anchor = findChildByRole(ChildRole.RBRACE);
        }
      }
    }

    if (isEnum()) {
      if (!ENUM_CONSTANT_LIST_ELEMENTS_BIT_SET.contains(first.getElementType())) {
        ASTNode semicolonPlace = findEnumConstantListDelimiterPlace();
        boolean commentsOrWhiteSpaces = true;
        for (ASTNode child = first; child != null; child = child.getTreeNext()) {
          if (!PsiImplUtil.isWhitespaceOrComment(child)) {
            commentsOrWhiteSpaces = false;
            break;
          }
        }
        if (!commentsOrWhiteSpaces && (semicolonPlace == null || semicolonPlace.getElementType() != SEMICOLON)) {
            final LeafElement semicolon = Factory.createSingleLeafElement(SEMICOLON, ";", 0, 1,
                                                                          SharedImplUtil.findCharTableByTree(this), getManager());
            addInternal(semicolon, semicolon, semicolonPlace, Boolean.FALSE);
            semicolonPlace = semicolon;
        }
        for (ASTNode run = anchor; run != null; run = run.getTreeNext()) {
          if (run == semicolonPlace) {
            anchor = before.booleanValue() ? semicolonPlace.getTreeNext() : semicolonPlace;
            if (anchor != null && PsiImplUtil.isWhitespaceOrComment(anchor)) {
              anchor = PsiTreeUtil.skipWhitespacesAndCommentsForward(anchor.getPsi()).getNode();
            }
            break;
          }
        }
      }
    }

    ASTNode afterLast = last.getTreeNext();
    ASTNode next;
    for (ASTNode child = first; child != afterLast; child = next) {
      next = child.getTreeNext();
      if (child.getElementType() == JavaElementType.METHOD && ((PsiMethod)SourceTreeToPsiMap.treeElementToPsi(child)).isConstructor()) {
        ASTNode oldIdentifier = ((CompositeElement)child).findChildByRole(ChildRole.NAME);
        ASTNode newIdentifier = findChildByRole(ChildRole.NAME).copyElement();
        newIdentifier.putUserData(CharTable.CHAR_TABLE_KEY, SharedImplUtil.findCharTableByTree(this));
        child.replaceChild(oldIdentifier, newIdentifier);
      }
    }

    if (psiClass.isEnum()) {
      for (ASTNode child = first; child != afterLast; child = next) {
        next = child.getTreeNext();
        if ((child.getElementType() == JavaElementType.METHOD && ((PsiMethod)SourceTreeToPsiMap.treeElementToPsi(child)).isConstructor()) ||
            child.getElementType() == JavaElementType.ENUM_CONSTANT) {
          CompositeElement modifierList = (CompositeElement)((CompositeElement)child).findChildByRole(ChildRole.MODIFIER_LIST);
          while (true) {
            ASTNode modifier = modifierList.findChildByType(MODIFIERS_TO_REMOVE_IN_ENUM_BIT_SET);
            if (modifier == null) break;
            modifierList.deleteChildInternal(modifier);
          }
        }
      }
    }
    else if (psiClass.isInterface()) {
      final boolean level8OrHigher = PsiUtil.isLanguageLevel8OrHigher(psiClass);
      for (ASTNode child = first; child != afterLast; child = next) {
        next = child.getTreeNext();
        final IElementType childElementType = child.getElementType();
        if (childElementType == JavaElementType.METHOD || childElementType == JavaElementType.FIELD) {
          CompositeElement modifierList = (CompositeElement)((CompositeElement)child).findChildByRole(ChildRole.MODIFIER_LIST);
          final TokenSet removeModifiersBitSet = level8OrHigher && childElementType == JavaElementType.METHOD
                                                 ? MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET_18_METHOD
                                                 : MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET;
          while (true) {
            ASTNode modifier = modifierList.findChildByType(removeModifiersBitSet);
            if (modifier == null) break;
            modifierList.deleteChildInternal(modifier);
          }
        }
      }
    }

    final TreeElement firstAdded = super.addInternal(first, last, anchor, before);
    if (firstAdded.getElementType() == ENUM_CONSTANT) {
      final CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this);
      for (ASTNode child = ((ASTNode)first).getTreeNext(); child != null; child = child.getTreeNext()) {
        final IElementType elementType = child.getElementType();
        if (elementType == COMMA || elementType == SEMICOLON) break;
        if (elementType == ENUM_CONSTANT) {
          TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, treeCharTab, getManager());
          super.addInternal(comma, comma, first, Boolean.FALSE);
          break;
        }
      }

      for (ASTNode child = ((ASTNode)first).getTreePrev(); child != null; child = child.getTreePrev()) {
        final IElementType elementType = child.getElementType();
        if (elementType == COMMA || elementType == SEMICOLON) break;
        if (elementType == ENUM_CONSTANT) {
          TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, treeCharTab, getManager());
          super.addInternal(comma, comma, child, Boolean.FALSE);
          break;
        }
      }
    }
    return firstAdded;
  }
@Override
  public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before)