@Override
  public void visitRegExpGroup(RegExpGroup group) {
    if (RegExpGroupImpl.isPcreConditionalGroup(group.getNode())) {
      if (RegExpGroupImpl.isPcreDefine(group.getNode())) {
        RegExpConditional conditional = ObjectUtils.tryCast(group.getParent(), RegExpConditional.class);
        if (conditional != null) {
          RegExpBranch[] branches = PsiTreeUtil.getChildrenOfType(conditional, RegExpBranch.class);
          if (branches != null && branches.length > 1) {
            myHolder.newAnnotation(HighlightSeverity.ERROR,
                                   RegExpBundle.message("error.define.subpattern.contains.more.than.one.branch")).create();
          }
        }
      }
      return;
    }
    final RegExpPattern pattern = group.getPattern();
    final RegExpBranch[] branches = pattern.getBranches();
    if (isEmpty(branches) && group.getNode().getLastChildNode().getElementType() == RegExpTT.GROUP_END) {
      // catches "()" as well as "(|)"
      myHolder.newAnnotation(HighlightSeverity.WARNING, RegExpBundle.message("error.empty.group")).create();
    }
    else if (branches.length == 1) {
      final RegExpAtom[] atoms = branches[0].getAtoms();
      if (atoms.length == 1 && atoms[0] instanceof RegExpGroup) {
        final RegExpGroup.Type type = group.getType();
        if (type == RegExpGroup.Type.CAPTURING_GROUP || type == RegExpGroup.Type.ATOMIC || type == RegExpGroup.Type.NON_CAPTURING) {
          final RegExpGroup innerGroup = (RegExpGroup)atoms[0];
          if (group.isCapturing() == innerGroup.isCapturing()) {
            myHolder.newAnnotation(HighlightSeverity.WARNING, RegExpBundle.message("error.redundant.group.nesting")).create();
          }
        }
      }
    }
    if (group.isAnyNamedGroup()) {
      if (!myLanguageHosts.supportsNamedGroupSyntax(group)) {
        myHolder.newAnnotation(HighlightSeverity.ERROR,
                               RegExpBundle.message("error.this.named.group.syntax.is.not.supported.in.this.regex.dialect")).create();
      }
    }
    if (group.getType() == RegExpGroup.Type.ATOMIC && !myLanguageHosts.supportsPossessiveQuantifiers(group)) {
      myHolder.newAnnotation(HighlightSeverity.ERROR, RegExpBundle.message("error.atomic.groups.are.not.supported.in.this.regex.dialect"))
        .create();
    }
    final String name = group.getName();
    if (name != null && !myLanguageHosts.isValidGroupName(name, group)) {
      final ASTNode node = group.getNode().findChildByType(RegExpTT.NAME);
      if (node != null) myHolder.newAnnotation(HighlightSeverity.ERROR, RegExpBundle.message("error.invalid.group.name")).range(node)
        .create();
    }
    final AnnotationSession session = myHolder.getCurrentAnnotationSession();
    final Map<String, RegExpGroup> namedGroups = NAMED_GROUP_MAP.get(session, new HashMap<>());
    if (namedGroups.isEmpty()) session.putUserData(NAMED_GROUP_MAP, namedGroups);
    if (namedGroups.put(name, group) != null && !myLanguageHosts.isDuplicateGroupNamesAllowed(group)) {
      final ASTNode node = group.getNode().findChildByType(RegExpTT.NAME);
      if (node != null) myHolder.newAnnotation(HighlightSeverity.ERROR,
                                               RegExpBundle.message("error.group.with.name.0.already.defined", name)).range(node).create();
    }
    final RegExpGroup.Type groupType = group.getType();
    if (groupType == RegExpGroup.Type.POSITIVE_LOOKBEHIND || groupType == RegExpGroup.Type.NEGATIVE_LOOKBEHIND) {
      final RegExpLanguageHost.Lookbehind support = myLanguageHosts.supportsLookbehind(group);
      if (support == RegExpLanguageHost.Lookbehind.NOT_SUPPORTED) {
        myHolder.newAnnotation(HighlightSeverity.ERROR,
                               RegExpBundle.message("error.look.behind.groups.are.not.supported.in.this.regex.dialect")).create();
      }
      else {
        group.accept(new LookbehindVisitor(support, myHolder));
      }
    }
  }
@Override
  public void visitRegExpGroup(RegExpGroup group)