int (@NotNull PsiMember member, PsiClass memberClass, @PsiUtil.AccessLevel int currentLevel) { if (member.hasModifierProperty(PsiModifier.PRIVATE) || member.hasModifierProperty(PsiModifier.NATIVE)) return currentLevel; if (member instanceof PsiMethod && member instanceof SyntheticElement || !member.isPhysical()) return currentLevel; if (member instanceof PsiMethod method) { if (!method.getHierarchicalMethodSignature().getSuperSignatures().isEmpty()) { if (LOG.isDebugEnabled()) { LOG.debug(member.getName() + " overrides"); } return currentLevel; // overrides } if (MethodUtils.isOverridden(method)) { if (LOG.isDebugEnabled()) { LOG.debug(member.getName() + " overridden"); } return currentLevel; } if (FindSuperElementsHelper.getSiblingInfoInheritedViaSubClass(method) != null || JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null) { return currentLevel; } } if (member instanceof PsiEnumConstant) return currentLevel; if (member instanceof PsiClass && (member instanceof PsiAnonymousClass || member instanceof PsiTypeParameter || member instanceof PsiSyntheticClass || PsiUtil.isLocalClass((PsiClass)member))) { return currentLevel; } if (memberClass != null && (memberClass.isInterface() || PsiUtil.isLocalClass(memberClass) && member instanceof PsiClass)) { return currentLevel; } if (memberClass != null && member instanceof PsiMethod) { if (memberClass.isRecord() && ((PsiMethod)member).isConstructor()) { final PsiModifierList modifierList = memberClass.getModifierList(); assert modifierList != null; // anonymous records don't exist return PsiUtil.getAccessLevel(modifierList); } // If class will be subclassed by some framework then it could apply some specific requirements for methods visibility // so we just skip it here (IDEA-182709, IDEA-160602) for (ImplicitSubclassProvider subclassProvider : ImplicitSubclassProvider.EP_NAME.getExtensionList()) { if (!subclassProvider.isApplicableTo(memberClass)) continue; ImplicitSubclassProvider.SubclassingInfo info = subclassProvider.getSubclassingInfo(memberClass); if (info == null) continue; Map<PsiMethod, ImplicitSubclassProvider.OverridingInfo> methodsInfo = info.getMethodsInfo(); if (methodsInfo == null || methodsInfo.containsKey(member)) { return currentLevel; } } } final PsiFile memberFile = member.getContainingFile(); Project project = memberFile.getProject(); int level = myVisibilityInspection.getMinVisibilityLevel(member); boolean entryPoint = myDeadCodeInspection.isEntryPoint(member) || member instanceof PsiField && (UnusedSymbolUtil.isImplicitWrite((PsiVariable)member) || UnusedSymbolUtil.isImplicitRead((PsiVariable)member)); if (entryPoint && level <= 0) { if (LOG.isDebugEnabled()) { LOG.debug(member.getName() + " is entry point"); } return currentLevel; } final PsiPackage memberPackage = getPackage(memberFile); if (LOG.isDebugEnabled()) { LOG.debug(member.getName() + ": checking effective level for " + member); } int minLevel = Math.max(PsiUtil.ACCESS_LEVEL_PRIVATE, level); AtomicInteger maxLevel = new AtomicInteger(minLevel); AtomicBoolean foundUsage = new AtomicBoolean(); boolean proceed = UnusedSymbolUtil.processUsages(project, memberFile, member, new EmptyProgressIndicator(), null, info -> { PsiElement element = info.getElement(); if (element == null) return true; PsiFile psiFile = info.getFile(); if (psiFile == null) return true; return handleUsage(member, memberClass, maxLevel, memberPackage, element, psiFile, foundUsage); }); if (proceed && member instanceof PsiClass && LambdaUtil.isFunctionalClass((PsiClass)member)) { // there can be lambda implementing this interface implicitly FunctionalExpressionSearch.search((PsiClass)member).forEach(functionalExpression -> { PsiFile psiFile = functionalExpression.getContainingFile(); return handleUsage(member, memberClass, maxLevel, memberPackage, functionalExpression, psiFile, foundUsage); }); } if (!foundUsage.get() && !entryPoint) { if (LOG.isDebugEnabled()) { LOG.debug(member.getName() + " unused; ignore"); } return currentLevel; // do not propose private for unused method } @PsiUtil.AccessLevel int suggestedLevel = maxLevel.get(); if (suggestedLevel == PsiUtil.ACCESS_LEVEL_PRIVATE && memberClass == null) { suggestedLevel = suggestPackageLocal(member); } String suggestedModifier = PsiUtil.getAccessModifier(suggestedLevel); if (LOG.isDebugEnabled()) { LOG.debug(member.getName() + ": effective level is '" + suggestedModifier + "'"); } return suggestedLevel; }