public static void analyzeErrors(final @NotNull Module module,
                                   final @NotNull VirtualFile formFile,
                                   final @Nullable GuiEditor editor,
                                   final @NotNull IRootContainer rootContainer,
                                   final @Nullable ProgressIndicator progress) {
    if (module.isDisposed()) {
      return;
    }

    // 1. Validate class to bind
    final String classToBind = rootContainer.getClassToBind();
    final PsiClass psiClass;
    if (classToBind != null) {
      psiClass = FormEditingUtil.findClassToBind(module, classToBind);
      if (psiClass == null) {
        final QuickFix[] fixes = editor != null ? new QuickFix[]{new CreateClassToBindFix(editor, classToBind)} : QuickFix.EMPTY_ARRAY;
        final ErrorInfo errorInfo = new ErrorInfo(null, null, UIDesignerBundle.message("error.class.does.not.exist", classToBind),
                                                  HighlightDisplayLevel.ERROR, fixes);
        rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, errorInfo);
      }
      else {
        rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, null);
      }
    }
    else {
      rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, null);
      psiClass = null;
    }

    // 2. Validate bindings to fields
    // field name -> error message
    final ArrayList<String> usedBindings = new ArrayList<>(); // for performance reasons
    final Set<IButtonGroup> processedGroups = new HashSet<>();
    FormEditingUtil.iterate(
      rootContainer,
      new FormEditingUtil.ComponentVisitor<>() {
        @Override
        public boolean visit(final IComponent component) {
          if (progress != null && progress.isCanceled()) return false;

          // Reset previous error (if any)
          component.putClientProperty(CLIENT_PROP_BINDING_ERROR, null);

          final String binding = component.getBinding();

          // a. Check that field exists and field is not static
          if (psiClass != null && binding != null) {
            if (validateFieldInClass(component, binding, component.getComponentClassName(), psiClass, editor, module)) return true;
          }

          // b. Check that binding is unique
          if (binding != null) {
            if (usedBindings.contains(binding)) {
              // TODO[vova] implement
              component.putClientProperty(
                CLIENT_PROP_BINDING_ERROR,
                new ErrorInfo(
                  component, null, UIDesignerBundle.message("error.binding.already.exists", binding),
                  HighlightDisplayLevel.ERROR,
                  QuickFix.EMPTY_ARRAY
                )
              );
              return true;
            }

            usedBindings.add(binding);
          }

          IButtonGroup group = FormEditingUtil.findGroupForComponent(rootContainer, component);
          if (group != null && !processedGroups.contains(group)) {
            processedGroups.add(group);
            if (group.isBound()) {
              validateFieldInClass(component, group.getName(), ButtonGroup.class.getName(), psiClass, editor, module);
            }
          }

          return true;
        }
      }
    );
    if (progress != null) progress.checkCanceled();

    // Check that there are no panels in XY with children
    FormEditingUtil.iterate(
      rootContainer,
      new FormEditingUtil.ComponentVisitor<>() {
        @Override
        public boolean visit(final IComponent component) {
          if (progress != null && progress.isCanceled()) return false;

          // Clear previous error (if any)
          component.putClientProperty(CLIENT_PROP_ERROR_ARRAY, null);

          if (!(component instanceof IContainer container)) {
            return true;
          }

          if (container instanceof IRootContainer rootContainer) {
            if (rootContainer.getComponentCount() > 1) {
              // TODO[vova] implement
              putError(component, new ErrorInfo(
                component, null, UIDesignerBundle.message("error.multiple.toplevel.components"),
                HighlightDisplayLevel.ERROR,
                QuickFix.EMPTY_ARRAY
              ));
            }
          }
          else if (container.isXY() && container.getComponentCount() > 0) {
            // TODO[vova] implement
            putError(component, new ErrorInfo(
                       component, null, UIDesignerBundle.message("error.panel.not.laid.out"),
                       HighlightDisplayLevel.ERROR,
                       QuickFix.EMPTY_ARRAY
                     )
            );
          }
          return true;
        }
      }
    );
    if (progress != null) progress.checkCanceled();

    try {
      // Run inspections for form elements
      final PsiFile formPsiFile = PsiManager.getInstance(module.getProject()).findFile(formFile);
      if (formPsiFile != null && rootContainer instanceof RadRootContainer) {
        final List<FormInspectionTool> formInspectionTools = new ArrayList<>();
        for (FormInspectionTool formInspectionTool : FormInspectionTool.EP_NAME.getExtensionList()) {
          if (formInspectionTool.isActive(formPsiFile) && !isSuppressed(rootContainer, formInspectionTool, null)) {
            formInspectionTools.add(formInspectionTool);
          }
        }

        if (!formInspectionTools.isEmpty() && editor != null) {
          for (FormInspectionTool tool : formInspectionTools) {
            tool.startCheckForm(rootContainer);
          }
          FormEditingUtil.iterate(
            rootContainer,
            (FormEditingUtil.ComponentVisitor<RadComponent>)(RadComponent component) -> {
              if (progress != null && progress.isCanceled()) return false;

              for (FormInspectionTool tool : formInspectionTools) {
                if (isSuppressed(rootContainer, tool, component.getId())) continue;
                ErrorInfo[] errorInfos = tool.checkComponent(editor, component);
                if (errorInfos != null) {
                  ArrayList<ErrorInfo> errorList = getErrorInfos(component);
                  if (errorList == null) {
                    errorList = new ArrayList<>();
                    component.putClientProperty(CLIENT_PROP_ERROR_ARRAY, errorList);
                  }
                  Collections.addAll(errorList, errorInfos);
                }
              }
              return true;
            }
          );
          for (FormInspectionTool tool : formInspectionTools) {
            tool.doneCheckForm(rootContainer);
          }
        }
      }
    }
    catch (ProcessCanceledException e) {
      throw e;
    }
    catch (Exception e) {
      LOG.error(e);
    }
  }
public static void analyzeErrors(final @NotNull Module module,
                                   final @NotNull VirtualFile formFile,
                                   final @Nullable GuiEditor editor,
                                   final @NotNull IRootContainer rootContainer,
                                   final @Nullable ProgressIndicator progress)