@Override
  public void visitXmlProcessingInstruction(XmlProcessingInstruction processingInstruction) {
    super.visitXmlProcessingInstruction(processingInstruction);
    PsiElement parent = processingInstruction.getParent();

    if (parent instanceof XmlProlog && processingInstruction.getText().startsWith("<?xml")) {
      for (PsiElement e = PsiTreeUtil.prevLeaf(processingInstruction);
          e != null;
          e = PsiTreeUtil.prevLeaf(e)) {
        if (e instanceof PsiWhiteSpace && PsiTreeUtil.prevLeaf(e) != null
            || e instanceof OuterLanguageElement) {
          continue;
        }
        PsiElement eParent = e.getParent();
        if (eParent instanceof PsiComment) e = eParent;
        if (eParent instanceof XmlProcessingInstruction) break;

        addToResults(
            HighlightInfo.createHighlightInfo(
                HighlightInfoType.ERROR,
                e,
                XmlErrorMessages.message("xml.declaration.should.precede.all.document.content")));
      }
    }
  }
  private void doCheckRefs(final PsiElement value, final PsiReference[] references, int start) {
    for (int i = start; i < references.length; ++i) {
      PsiReference reference = references[i];
      ProgressManager.checkCanceled();
      if (reference == null) {
        continue;
      }
      if (!hasBadResolve(reference, false)) {
        continue;
      }
      String description = getErrorDescription(reference);

      final int startOffset = reference.getElement().getTextRange().getStartOffset();
      final TextRange referenceRange = reference.getRangeInElement();

      // logging for IDEADEV-29655
      if (referenceRange.getStartOffset() > referenceRange.getEndOffset()) {
        LOG.error(
            "Reference range start offset > end offset:  "
                + reference
                + ", start offset: "
                + referenceRange.getStartOffset()
                + ", end offset: "
                + referenceRange.getEndOffset());
      }

      HighlightInfoType type =
          getTagProblemInfoType(PsiTreeUtil.getParentOfType(value, XmlTag.class));
      if (value instanceof XmlAttributeValue) {
        PsiElement parent = value.getParent();
        if (parent instanceof XmlAttribute) {
          String name = ((XmlAttribute) parent).getName().toLowerCase();
          if (type.getSeverity(null).compareTo(HighlightInfoType.WARNING.getSeverity(null)) > 0
              && name.endsWith("stylename")) {
            type = HighlightInfoType.WARNING;
          } else if (name.equals("href")
              && type.getSeverity(null) == HighlightInfoType.WARNING.getSeverity(null)) {
            continue;
          }
        }
      }
      HighlightInfo info =
          HighlightInfo.createHighlightInfo(
              type,
              startOffset + referenceRange.getStartOffset(),
              startOffset + referenceRange.getEndOffset(),
              description);
      addToResults(info);
      if (reference instanceof QuickFixProvider)
        ((QuickFixProvider) reference).registerQuickfix(info, reference);
      UnresolvedReferenceQuickFixProvider.registerReferenceFixes(
          reference, new QuickFixActionRegistrarImpl(info));
    }
  }
  @Override
  public void visitXmlToken(XmlToken token) {
    IElementType tokenType = token.getTokenType();
    if (tokenType == XmlTokenType.XML_NAME || tokenType == XmlTokenType.XML_TAG_NAME) {
      PsiElement element = token.getPrevSibling();
      while (element instanceof PsiWhiteSpace) element = element.getPrevSibling();

      if (element instanceof XmlToken) {
        if (((XmlToken) element).getTokenType() == XmlTokenType.XML_START_TAG_START) {
          PsiElement parent = element.getParent();

          if (parent instanceof XmlTag
              && !(token.getNextSibling() instanceof OuterLanguageElement)) {
            checkTag((XmlTag) parent);
          }
        }
      } else {
        PsiElement parent = token.getParent();

        if (parent instanceof XmlAttribute
            && !(token.getNextSibling() instanceof OuterLanguageElement)) {
          checkAttribute((XmlAttribute) parent);
        }
      }
    } else if (tokenType == XmlTokenType.XML_DATA_CHARACTERS
        && token.getParent() instanceof XmlText) {
      if (token.textContains(']') && token.textContains('>')) {
        String s = token.getText();
        String marker = "]]>";
        int i = s.indexOf(marker);

        if (i != -1) { // TODO: fix
          TextRange textRange = token.getTextRange();
          int start = textRange.getStartOffset() + i;
          HighlightInfoType type =
              PsiTreeUtil.getParentOfType(token, XmlTag.class) instanceof HtmlTag
                  ? HighlightInfoType.WARNING
                  : HighlightInfoType.ERROR;
          HighlightInfo info =
              HighlightInfo.createHighlightInfo(
                  type,
                  start,
                  start + marker.length(),
                  XmlErrorMessages.message(
                      "cdata.end.should.not.appear.in.content.unless.to.mark.end.of.cdata.section"));
          addToResults(info);
        }
      }
    }
  }