void (@NotNull MultiMap<PsiJavaModule, PsiDirectory> sourceDirsByModuleDescriptor, @NotNull List<? super UsageInfo> usageInfos, @NotNull MultiMap<PsiElement, String> conflicts, @NotNull MultiMap<PsiJavaModule, PsiDirectory> absentDirsByModuleDescriptor) { PackageIndex packageIndex = PackageIndex.getInstance(myProject); JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); PsiPackage targetPackage = psiFacade.findPackage(myMoveDestination.getTargetPackage().getQualifiedName()); for (var entry : sourceDirsByModuleDescriptor.entrySet()) { PsiJavaModule sourceModuleDescriptor = entry.getKey(); Collection<PsiDirectory> sourceDirs = entry.getValue(); MultiMap<PsiPackage, PsiPackageAccessibilityStatement> sourceExports = collectModuleStatements(sourceModuleDescriptor.getExports()); MultiMap<PsiPackage, PsiPackageAccessibilityStatement> sourceOpens = collectModuleStatements(sourceModuleDescriptor.getOpens()); Map<PsiJavaModule, DirectoryWithModuleStatements> targetModuleStatementsByModuleDescriptor = new HashMap<>(); for (PsiDirectory sourceDir : sourceDirs) { PsiDirectory targetDirectory = myMoveDestination.getTargetIfExists(sourceDir); if (targetDirectory == null) { absentDirsByModuleDescriptor.putValue(sourceModuleDescriptor, sourceDir); continue; } String sourcePkgName = packageIndex.getPackageNameByDirectory(sourceDir.getVirtualFile()); if (sourcePkgName == null) continue; PsiPackage sourcePkg = psiFacade.findPackage(sourcePkgName); if (sourcePkg == null) continue; List<PsiPackageAccessibilityStatement> sourceStatements = findModuleStatementsForPkg(sourcePkg, sourceExports, sourceOpens); if (sourceStatements.isEmpty()) continue; // if a package doesn't contain any other classes except moved ones then we need to delete a corresponding export statement Collection<PsiClass> sourceClasses = mySourceClassesByDir.get(sourceDir); if (dirContainsOnlyClasses(sourceDir, sourceClasses)) { sourceStatements.forEach(statement -> usageInfos.add(ModifyModuleStatementUsageInfo.createLastDeletionInfo(statement, sourceModuleDescriptor))); } PsiJavaModule targetModuleDescriptor = JavaModuleGraphUtil.findDescriptorByElement(targetDirectory); // so far we don't take into account a motion between separate JPMS-modules if (sourceModuleDescriptor == targetModuleDescriptor) { DirectoryWithModuleStatements dirWithStatements = targetModuleStatementsByModuleDescriptor .computeIfAbsent(sourceModuleDescriptor, __ -> new DirectoryWithModuleStatements(targetDirectory, new SmartList<>())); dirWithStatements.myModuleStatements.addAll(sourceStatements); } else if (targetModuleDescriptor != null) { sourceClasses.forEach(c -> conflicts.put(c, List.of( JavaRefactoringBundle.message("move.classes.or.packages.different.modules.exports.conflict", RefactoringUIUtil.getDescription(c, false), StringUtil.htmlEmphasize(sourceModuleDescriptor.getName()), StringUtil.htmlEmphasize(targetModuleDescriptor.getName()))))); } } for (var statementEntry : targetModuleStatementsByModuleDescriptor.entrySet()) { PsiJavaModule targetModuleDescriptor = statementEntry.getKey(); List<PsiPackageAccessibilityStatement> sourceModuleStatements = statementEntry.getValue().myModuleStatements; assert targetPackage != null; List<PsiPackageAccessibilityStatement> targetPkgModuleStatements = findModuleStatementsForPkg(targetModuleDescriptor, targetPackage); List<PsiPackageAccessibilityStatement> statementsToCreate = new SmartList<>(); List<PsiPackageAccessibilityStatement> statementsToDelete = new SmartList<>(); mergeModuleStatements(sourceModuleStatements, targetPkgModuleStatements, targetPackage, statementsToCreate, statementsToDelete); if (statementsToCreate.isEmpty()) continue; if (!dirContainsOnlyClasses(statementEntry.getValue().myDir, Collections.emptyList())) { conflicts.put(targetModuleDescriptor.getNameIdentifier(), List.of( JavaRefactoringBundle.message("move.classes.or.packages.new.module.exports.conflict", StringUtil.htmlEmphasize(targetPackage.getQualifiedName())))); } statementsToDelete.stream().map(pkgStatement -> ModifyModuleStatementUsageInfo.createDeletionInfo(pkgStatement, targetModuleDescriptor)) .forEach(usageInfos::add); statementsToCreate.stream().map(pkgStatement -> ModifyModuleStatementUsageInfo.createAdditionInfo(pkgStatement, targetModuleDescriptor)) .forEach(usageInfos::add); } } }