@Override
  public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    PsiFile file = holder.getFile();
    LocalRefUseInfo info = LocalRefUseInfo.forFile(file);
    Project project = holder.getProject();
    InspectionProfileImpl profile = InspectionProjectProfileManager.getInstance(project).getCurrentProfile();
    UnusedDeclarationInspectionBase deadCodeInspection = ObjectUtils.tryCast(
      profile.getUnwrappedTool(UnusedDeclarationInspectionBase.SHORT_NAME, file), UnusedDeclarationInspectionBase.class);
    GlobalUsageHelper helper = info.getGlobalUsageHelper(file, deadCodeInspection);
    return new JavaElementVisitor() {
      private final QuickFixFactory fixFactory = QuickFixFactory.getInstance();
      private final Map<PsiMethod, Boolean> isOverriddenOrOverrides = ConcurrentFactoryMap.createMap(
        method -> {
          boolean overrides = SuperMethodsSearch.search(method, null, true, false).findFirst() != null;
          return overrides || OverridingMethodsSearch.search(method).findFirst() != null;
        }
      );

      private boolean isOverriddenOrOverrides(@NotNull PsiMethod method) {
        return isOverriddenOrOverrides.get(method);
      }

      private static boolean compareVisibilities(PsiModifierListOwner listOwner, String visibility) {
        if (visibility != null) {
          while (listOwner != null) {
            if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(listOwner.getModifierList()), visibility) >= 0) {
              return true;
            }
            listOwner = PsiTreeUtil.getParentOfType(listOwner, PsiModifierListOwner.class, true);
          }
        }
        return false;
      }

      private void registerProblem(@NotNull PsiElement element,
                                   @NotNull @InspectionMessage String message,
                                   @NotNull List<? extends IntentionAction> fixes) {
        // Synthetic elements in JSP like JspHolderMethod may arrive here
        if (element instanceof SyntheticElement) return;
        if (element instanceof PsiNameIdentifierOwner owner) {
          PsiElement identifier = owner.getNameIdentifier();
          if (identifier != null) {
            element = identifier;
          }
        }
        for (UnusedDeclarationFixProvider provider : UnusedDeclarationFixProvider.EP_NAME.getExtensionList()) {
          IntentionAction[] additionalFixes = provider.getQuickFixes(element);
          fixes = ContainerUtil.append(fixes, additionalFixes);
        }
        holder.registerProblem(element, message, ContainerUtil.map2Array(fixes, LocalQuickFix.EMPTY_ARRAY,
                                                                         UnusedSymbolLocalInspection::toLocalQuickFix));
      }

      @Override
      public void visitLocalVariable(@NotNull PsiLocalVariable variable) {
        if (!LOCAL_VARIABLE) return;
        if (variable.isUnnamed() || PsiUtil.isIgnoredName(variable.getName())) return;
        if (UnusedSymbolUtil.isImplicitUsage(project, variable)) return;

        if (!info.isReferenced(variable)) {
          IntentionAction fix = variable instanceof PsiResourceVariable
                                ? fixFactory.createRenameToIgnoredFix(variable, false)
                                : QuickFixFactory.getInstance().createRemoveUnusedVariableFix(variable);
          registerProblem(variable, JavaErrorBundle.message("local.variable.is.never.used", variable.getName()), List.of(fix));
        }

        else if (!info.isReferencedForRead(variable) && !UnusedSymbolUtil.isImplicitRead(project, variable)) {
          registerProblem(variable, JavaErrorBundle.message("local.variable.is.not.used.for.reading", variable.getName()),
                          List.of(QuickFixFactory.getInstance().createRemoveUnusedVariableFix(variable)));
        }

        else if (!variable.hasInitializer() &&
                 !info.isReferencedForWrite(variable) &&
                 !UnusedSymbolUtil.isImplicitWrite(project, variable)) {
          registerProblem(variable, JavaErrorBundle.message("local.variable.is.not.assigned", variable.getName()),
                          List.of(fixFactory.createAddVariableInitializerFix(variable)));
        }
      }

      @Override
      public void visitField(@NotNull PsiField field) {
        if (!compareVisibilities(field, getFieldVisibility())) return;
        if (HighlightUtil.isSerializationImplicitlyUsedField(field)) return;
        if (field.hasModifierProperty(PsiModifier.PRIVATE)) {
          if (!info.isReferenced(field) && !UnusedSymbolUtil.isImplicitUsage(project, field)) {
            List<IntentionAction> fixes = new ArrayList<>(suggestionsToMakeFieldUsed(field));
            if (!field.hasInitializer() && !field.hasModifierProperty(PsiModifier.FINAL)) {
              fixes.add(fixFactory.createCreateConstructorParameterFromFieldFix(field));
            }
            registerProblem(field, JavaErrorBundle.message("private.field.is.not.used", field.getName()), fixes);
            return;
          }

          boolean readReferenced = info.isReferencedForRead(field);
          if (!readReferenced && !UnusedSymbolUtil.isImplicitRead(project, field)) {
            registerProblem(field, getNotUsedForReadingMessage(field), suggestionsToMakeFieldUsed(field));
            return;
          }

          if (field.hasInitializer()) {
            return;
          }
          boolean writeReferenced = info.isReferencedForWrite(field);
          if (!writeReferenced && !UnusedSymbolUtil.isImplicitWrite(project, field)) {
            List<IntentionAction> fixes = new ArrayList<>();
            fixes.add(fixFactory.createCreateGetterOrSetterFix(false, true, field));
            if (!field.hasModifierProperty(PsiModifier.FINAL)) {
              fixes.add(fixFactory.createCreateConstructorParameterFromFieldFix(field));
            }
            SpecialAnnotationsUtilBase.processUnknownAnnotations(field, annoName ->
              fixes.add(fixFactory.createAddToImplicitlyWrittenFieldsFix(project, annoName)));
            registerProblem(field, JavaErrorBundle.message("private.field.is.not.assigned", field.getName()), fixes);
          }
        }
        else if (!UnusedSymbolUtil.isFieldUsed(project, file, field, helper)) {
          if (UnusedSymbolUtil.isImplicitWrite(project, field)) {
            registerProblem(field, getNotUsedForReadingMessage(field), List.of(fixFactory.createSafeDeleteFix(field)));
          }
          else if (!UnusedSymbolUtil.isImplicitUsage(project, field)) {
            formatUnusedSymbolHighlightInfo("field.is.not.used", field);
          }
        }
      }

      private void formatUnusedSymbolHighlightInfo(@NotNull @PropertyKey(resourceBundle = JavaErrorBundle.BUNDLE) String pattern,
                                                   @NotNull PsiMember member) {
        List<IntentionAction> fixes = new ArrayList<>();
        fixes.add(QuickFixFactory.getInstance().createSafeDeleteFix(member));
        SpecialAnnotationsUtilBase.processUnknownAnnotations(member, annoName ->
          fixes.add(QuickFixFactory.getInstance().createAddToDependencyInjectionAnnotationsFix(project, annoName)));
        registerProblem(member, JavaErrorBundle.message(pattern, member.getName()), fixes);
      }

      private static boolean isUsedMainOrPremainMethod(@NotNull PsiMethod method) {
        if (!PsiClassImplUtil.isMainOrPremainMethod(method)) {
          return false;
        }
        //premain
        if (!"main".equals(method.getName())) {
          return true;
        }
        return !PsiUtil.isAvailable(JavaFeature.IMPLICIT_CLASSES, method);
      }

      @Override
      public void visitMethod(@NotNull PsiMethod method) {
        if (isIgnoreAccessors() && PropertyUtilBase.isSimplePropertyAccessor(method)) return;
        if (!compareVisibilities(method, getMethodVisibility())) return;
        if (UnusedSymbolUtil.isMethodUsed(project, file, method, helper)) return;
        String key;
        if (method.hasModifierProperty(PsiModifier.PRIVATE)) {
          key = method.isConstructor() ? "private.constructor.is.not.used" : "private.method.is.not.used";
        }
        else {
          key = method.isConstructor() ? "constructor.is.not.used" : "method.is.not.used";
        }
        int options = PsiFormatUtilBase.SHOW_TYPE | PsiFormatUtilBase.SHOW_FQ_CLASS_NAMES;
        String symbolName = HighlightMessageUtil.getSymbolName(method, PsiSubstitutor.EMPTY, options);
        QuickFixFactory factory = QuickFixFactory.getInstance();
        List<IntentionAction> fixes = new ArrayList<>();
        fixes.add(factory.createSafeDeleteFix(method));
        if (ApplicationManager.getApplication().isHeadlessEnvironment() && method.hasModifierProperty(PsiModifier.PRIVATE)) {
          fixes.add(factory.createDeletePrivateMethodFix(method).asIntention());
        }
        SpecialAnnotationsUtilBase.processUnknownAnnotations(method, annoName ->
          fixes.add(factory.createAddToDependencyInjectionAnnotationsFix(project, annoName)));
        registerProblem(method, JavaErrorBundle.message(key, symbolName), fixes);
      }

      @Override
      public void visitParameter(@NotNull PsiParameter parameter) {
        PsiElement declarationScope = parameter.getDeclarationScope();
        boolean needToProcessParameter;
        if (declarationScope instanceof PsiMethod method) {
          needToProcessParameter = compareVisibilities(method, getParameterVisibility());
        }
        else if (declarationScope instanceof PsiLambdaExpression) {
          needToProcessParameter = compareVisibilities(
            PsiTreeUtil.getParentOfType(declarationScope, PsiModifierListOwner.class), getParameterVisibility());
        }
        else {
          needToProcessParameter = LOCAL_VARIABLE;
        }
        if (!needToProcessParameter) return;
        if (parameter.isUnnamed() || PsiUtil.isIgnoredName(parameter.getName())) return;
        QuickFixFactory quickFixFactory = QuickFixFactory.getInstance();
        if (declarationScope instanceof PsiMethod method) {
          if (PsiUtilCore.hasErrorElementChild(method)) return;
          if ((method.isConstructor() ||
               method.hasModifierProperty(PsiModifier.PRIVATE) ||
               method.hasModifierProperty(PsiModifier.STATIC) ||
               !method.hasModifierProperty(PsiModifier.ABSTRACT) &&
               (!isOverriddenOrOverrides(method) || shouldCheckParameterExcludingHierarchy())) &&
              !method.hasModifierProperty(PsiModifier.NATIVE) &&
              !JavaHighlightUtil.isSerializationRelatedMethod(method, method.getContainingClass()) &&
              !isUsedMainOrPremainMethod(method)) {
            if (UnusedSymbolUtil.isInjected(project, method)) return;
            String message = checkUnusedParameter(parameter);
            if (message != null) {
              registerProblem(
                parameter, message,
                ContainerUtil.append(
                  getFixesForUnusedParameter(method, parameter),
                  quickFixFactory.createRenameToIgnoredFix(parameter, true),
                  PriorityIntentionActionWrapper.highPriority(quickFixFactory.createSafeDeleteUnusedParameterInHierarchyFix(
                    parameter, shouldCheckParameterExcludingHierarchy() && isOverriddenOrOverrides(method)))));
            }
          }
        }
        else if (declarationScope instanceof PsiForeachStatement) {
          String message = checkUnusedParameter(parameter);
          if (message != null) {
            registerProblem(parameter, message, List.of(quickFixFactory.createRenameToIgnoredFix(parameter, false)));
          }
        }
        else if (parameter instanceof PsiPatternVariable variable) {
          String message = checkUnusedParameter(parameter);
          if (message != null) {
            PsiPattern pattern = variable.getPattern();
            IntentionAction action = null;
            if (PsiUtil.isAvailable(JavaFeature.UNNAMED_PATTERNS_AND_VARIABLES, parameter)) {
              if (pattern instanceof PsiTypeTestPattern ttPattern && pattern.getParent() instanceof PsiDeconstructionList) {
                PsiRecordComponent component = JavaPsiPatternUtil.getRecordComponentForPattern(pattern);
                PsiTypeElement checkType = ttPattern.getCheckType();
                if (component != null && checkType != null && checkType.getType().isAssignableFrom(component.getType())) {
                  action = new ReplaceWithUnnamedPatternFix(pattern).asIntention();
                }
              }
            }
            if (action == null && declarationScope.getParent() instanceof PsiSwitchBlock) {
              action = variable.getParent() instanceof PsiDeconstructionPattern
                       ? quickFixFactory.createDeleteFix(parameter)
                       : quickFixFactory.createRenameToIgnoredFix(parameter, false);
            }
            else if (!(pattern instanceof PsiTypeTestPattern && pattern.getParent() instanceof PsiDeconstructionList)) {
              action = quickFixFactory.createDeleteFix(parameter);
            }
            registerProblem(parameter, message, ContainerUtil.createMaybeSingletonList(action));
          }
        }
        else if ((shouldCheckParameterExcludingHierarchy() ||
                  PsiUtil.isAvailable(JavaFeature.UNNAMED_PATTERNS_AND_VARIABLES, declarationScope))
                 && declarationScope instanceof PsiLambdaExpression) {
          String message = checkUnusedParameter(parameter);
          if (message != null) {
            registerProblem(
              parameter, message,
              List.of(quickFixFactory.createRenameToIgnoredFix(parameter, true),
                      PriorityIntentionActionWrapper.lowPriority(
                        quickFixFactory.createSafeDeleteUnusedParameterInHierarchyFix(parameter, true))));
          }
        }
      }

      private @Nullable @InspectionMessage String checkUnusedParameter(@NotNull PsiParameter parameter) {
        if (!info.isReferenced(parameter) && !UnusedSymbolUtil.isImplicitUsage(project, parameter)) {
          return JavaErrorBundle.message(parameter instanceof PsiPatternVariable ?
                                         "pattern.variable.is.not.used" : "parameter.is.not.used", parameter.getName());
        }
        return null;
      }

      private static @NotNull List<IntentionAction> getFixesForUnusedParameter(@NotNull PsiMethod declarationMethod, @NotNull PsiParameter parameter) {
        IntentionAction assignFix = QuickFixFactory.getInstance().createAssignFieldFromParameterFix(parameter);
        IntentionAction createFieldFix = QuickFixFactory.getInstance().createCreateFieldFromParameterFix(parameter);
        if (!declarationMethod.isConstructor()) {
          assignFix = PriorityIntentionActionWrapper.lowPriority(assignFix);
          createFieldFix = PriorityIntentionActionWrapper.lowPriority(createFieldFix);
        }
        return List.of(assignFix, createFieldFix);
      }

      @Override
      public void visitClass(@NotNull PsiClass aClass) {
        String acceptedVisibility = aClass.getContainingClass() == null ? getClassVisibility()
                                                                        : getInnerClassVisibility();
        if (!compareVisibilities(aClass, acceptedVisibility)) return;
        if (UnusedSymbolUtil.isClassUsed(project, file, aClass, helper)) return;

        String pattern;
        if (aClass.getContainingClass() != null && aClass.hasModifierProperty(PsiModifier.PRIVATE)) {
          pattern = aClass.isInterface()
                    ? "private.inner.interface.is.not.used"
                    : "private.inner.class.is.not.used";
        }
        else if (aClass.getParent() instanceof PsiDeclarationStatement) { // local class
          pattern = "local.class.is.not.used";
        }
        else if (aClass instanceof PsiTypeParameter) {
          pattern = "type.parameter.is.not.used";
        }
        else if (aClass.isAnnotationType()) {
          pattern = "annotation.interface.is.not.used";
        }
        else if (aClass.isInterface()) {
          pattern = "interface.is.not.used";
        }
        else if (aClass.isEnum()) {
          pattern = "enum.is.not.used";
        }
        else if (aClass.isRecord()) {
          pattern = "record.is.not.used";
        }
        else {
          pattern = "class.is.not.used";
        }
        formatUnusedSymbolHighlightInfo(pattern, aClass);
      }

      @NotNull
      private static @NlsContexts.DetailedDescription String getNotUsedForReadingMessage(@NotNull PsiField field) {
        String visibility = VisibilityUtil.getVisibilityStringToDisplay(field);
        String message = JavaErrorBundle.message("field.is.not.used.for.reading", visibility, field.getName());
        return StringUtil.capitalize(message);
      }

      private List<IntentionAction> suggestionsToMakeFieldUsed(@NotNull PsiField field) {
        List<IntentionAction> quickFixes = new ArrayList<>();
        SpecialAnnotationsUtilBase.processUnknownAnnotations(field, annoName ->
          quickFixes.add(EntryPointsManagerBase.createAddEntryPointAnnotation(annoName).asIntention()));
        quickFixes.add(QuickFixFactory.getInstance().createRemoveUnusedVariableFix(field));
        quickFixes.add(fixFactory.createCreateGetterOrSetterFix(true, false, field));
        quickFixes.add(fixFactory.createCreateGetterOrSetterFix(false, true, field));
        quickFixes.add(fixFactory.createCreateGetterOrSetterFix(true, true, field));
        return quickFixes;
      }
    };
  }
@Override
  public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)