private void copyUnmatchedElements(PsiElement original, PsiElement replacement, ReplacementInfo info) {
    final Map<String, PsiElement> originalNamedElements = collectNamedElements(original);
    final Map<String, PsiElement> replacedNamedElements = collectNamedElements(replacement);

    if (originalNamedElements.isEmpty() && replacedNamedElements.isEmpty()) {
      Replacer.handleComments(original, replacement, info);
      return;
    }

    final Map<String, PsiElement> patternNamedElements = collectNamedElements(patternElements);

    for (String name : originalNamedElements.keySet()) {
      final PsiElement originalNamedElement = originalNamedElements.get(name);
      PsiElement replacementNamedElement = replacedNamedElements.get(name);
      final PsiElement patternNamedElement =
        ObjectUtils.coalesce(patternNamedElements.get(name), patternNamedElements.get('$' + info.getSearchPatternName(name) + '$'));
      if (patternNamedElement == null) continue;

      if (replacementNamedElement == null && originalNamedElement == original) {
        replacementNamedElement = replacement;
      }

      PsiElement comment = null;
      if (originalNamedElement instanceof PsiDocCommentOwner) {
        comment = ((PsiDocCommentOwner)originalNamedElement).getDocComment();
        if (comment == null) {
          PsiElement prevElement = originalNamedElement.getPrevSibling();
          if (prevElement instanceof PsiWhiteSpace) {
            prevElement = prevElement.getPrevSibling();
          }
          if (prevElement instanceof PsiComment) {
            comment = prevElement;
          }
        }
      }

      if (replacementNamedElement != null) {
        Replacer.handleComments(originalNamedElement, replacementNamedElement, info);
      }

      if (comment != null && replacementNamedElement instanceof PsiDocCommentOwner &&
          !(replacementNamedElement.getFirstChild() instanceof PsiDocComment)) {
        final PsiElement nextSibling = comment.getNextSibling();
        final PsiElement prevSibling = comment.getPrevSibling();
        replacementNamedElement.addRangeBefore(
          prevSibling instanceof PsiWhiteSpace ? prevSibling : comment,
          nextSibling instanceof PsiWhiteSpace ? nextSibling : comment,
          replacementNamedElement.getFirstChild()
        );
      }

      if (originalNamedElement instanceof PsiAnnotation &&
          patternNamedElement instanceof PsiAnnotation &&
          replacementNamedElement instanceof PsiAnnotation) {
        copyAnnotationParameters((PsiAnnotation)originalNamedElement,
                                 (PsiAnnotation)patternNamedElement,
                                 (PsiAnnotation)replacementNamedElement);
      }

      if (originalNamedElement instanceof PsiModifierListOwner &&
          patternNamedElement instanceof PsiModifierListOwner &&
          replacementNamedElement instanceof PsiModifierListOwner) {
        copyModifiersAndAnnotations((PsiModifierListOwner)originalNamedElement,
                                    (PsiModifierListOwner)patternNamedElement,
                                    (PsiModifierListOwner)replacementNamedElement);
      }

      if (originalNamedElement instanceof PsiMethod &&
          patternNamedElement instanceof PsiMethod &&
          replacementNamedElement instanceof PsiMethod) {
        copyMethodBodyIfNotReplaced((PsiMethod)originalNamedElement, (PsiMethod)patternNamedElement, (PsiMethod)replacementNamedElement);
      }

      if (originalNamedElement instanceof PsiVariable originalVariable &&
          patternNamedElement instanceof PsiVariable queryVariable &&
          replacementNamedElement instanceof PsiVariable replacementVariable) {
        if (originalVariable.hasInitializer() && !queryVariable.hasInitializer() && !replacementVariable.hasInitializer()) {
          replacementVariable.setInitializer(originalVariable.getInitializer());
        }
      }

      if (originalNamedElement instanceof PsiClass originalClass &&
          patternNamedElement instanceof PsiClass queryClass &&
          replacementNamedElement instanceof PsiClass replacementClass) {

        copyClassType(originalClass, queryClass, replacementClass);
        copyExtendsListIfNotReplaced(originalClass, queryClass, replacementClass);
        copyImplementsListIfNotReplaced(originalClass, queryClass, replacementClass);

        copyUnmatchedMembers(originalClass, originalNamedElements, replacementClass);
      }

      if (originalNamedElement instanceof PsiTypeParameterListOwner &&
          patternNamedElement instanceof PsiTypeParameterListOwner &&
          replacementNamedElement instanceof PsiTypeParameterListOwner) {
        copyTypeParameterListIfNotReplaced((PsiTypeParameterListOwner)originalNamedElement,
                                           (PsiTypeParameterListOwner)patternNamedElement,
                                           (PsiTypeParameterListOwner)replacementNamedElement);
      }

      if (originalNamedElement instanceof PsiMethodCallExpression &&
          patternNamedElement instanceof PsiMethodCallExpression &&
          replacementNamedElement instanceof PsiMethodCallExpression) {
        copyQualifierIfNotReplaced((PsiMethodCallExpression)originalNamedElement,
                                   (PsiMethodCallExpression)patternNamedElement,
                                   (PsiMethodCallExpression)replacementNamedElement);
      }
    }
  }
private void copyUnmatchedElements(PsiElement original, PsiElement replacement, ReplacementInfo info)