From 0590c5ddd4a6b19c0818e90a47b2d0f81933f6f0 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Thu, 15 Feb 2018 13:09:55 +0300 Subject: [PATCH] Java: Use template when generating module-info files (IDEA-184148) --- .../Java9GenerateModuleDescriptorsAction.java | 115 +++++++++++------- .../src/messages/RefactoringBundle.properties | 2 +- 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/java19api/Java9GenerateModuleDescriptorsAction.java b/java/java-impl/src/com/intellij/codeInspection/java19api/Java9GenerateModuleDescriptorsAction.java index 669b30f1deaf..a459b7466cb6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java19api/Java9GenerateModuleDescriptorsAction.java +++ b/java/java-impl/src/com/intellij/codeInspection/java19api/Java9GenerateModuleDescriptorsAction.java @@ -3,7 +3,9 @@ package com.intellij.codeInspection.java19api; import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil; import com.intellij.codeInspection.AbstractDependencyVisitor; -import com.intellij.lang.java.JavaLanguage; +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; @@ -45,6 +47,9 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.*; +import static com.intellij.ide.fileTemplates.JavaTemplateUtil.INTERNAL_MODULE_INFO_TEMPLATE_NAME; +import static com.intellij.psi.PsiJavaModule.*; + /** * @author Pavel.Dolgov */ @@ -207,7 +212,7 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { } void generate(THashMap> classFiles, int totalFiles) { - List generatedCode; + List moduleInfos; try { myProgressTracker.startPhase(RefactoringBundle.message("generate.module.descriptors.collecting.message"), totalFiles); Map> packagesDeclaredInModules = collectDependencies(classFiles); @@ -218,22 +223,22 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { myProgressTracker.nextPhase(); myProgressTracker.startPhase(RefactoringBundle.message("generate.module.descriptors.preparing.message"), myModuleNodes.size()); - generatedCode = generateCode(); + moduleInfos = prepareModuleInfos(); myProgressTracker.nextPhase(); } finally { myProgressTracker.dispose(); } - createFilesLater(generatedCode); + createFilesLater(moduleInfos); } - private void createFilesLater(List generatedCode) { + private void createFilesLater(List moduleInfos) { ApplicationManager.getApplication().invokeLater(() -> { if (!myProject.isDisposed()) { CommandProcessor.getInstance().executeCommand(myProject, () -> ((ApplicationImpl)ApplicationManager.getApplication()).runWriteActionWithCancellableProgressInDispatchThread( COMMAND_TITLE, myProject, null, - indicator -> createFiles(myProject, generatedCode, indicator)), COMMAND_TITLE, null); + indicator -> createFiles(myProject, moduleInfos, indicator)), COMMAND_TITLE, null); } }); } @@ -246,7 +251,12 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { Module module = entry.getKey(); ModuleVisitor visitor = new ModuleVisitor(packageNamesCache); - for (File file : entry.getValue()) { + List files = entry.getValue(); + if (files.isEmpty()) { + LOG.info("Output directory for module " + module.getName() + " doesn't contain .class files"); + continue; + } + for (File file : files) { visitor.processFile(file); myProgressTracker.increment(); } @@ -285,7 +295,7 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { } else { if (set.size() != 1) { - LOG.debug("Split package " + packageName + " in " + set); + LOG.info("Split package " + packageName + " found in " + set); } moduleNode.getDependencies().addAll(set); } @@ -294,11 +304,11 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { } } - private List generateCode() { - List generatedCode = new ArrayList<>(); + private List prepareModuleInfos() { + List moduleInfo = new ArrayList<>(); for (ModuleNode moduleNode : myModuleNodes) { if (moduleNode.getDescriptor() != null) { - LOG.debug("Descriptor already exists in " + moduleNode); + LOG.info("Module descriptor already exists in " + moduleNode); continue; } for (String packageName : moduleNode.getDeclaredPackages()) { @@ -307,50 +317,60 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { } } - StringBuilder text = new StringBuilder(); - text.append("module ").append(moduleNode.getName()).append(" {"); - List sortedDependencies = moduleNode.getSortedDependencies(); - List sortedExports = moduleNode.getSortedExports(); - for (ModuleNode dependencyNode : sortedDependencies) { - if (!"java.base".equals(dependencyNode.getName())) { - text.append("\n requires ").append(dependencyNode.getName()).append(";"); - } - } - if (!sortedDependencies.isEmpty() && !sortedExports.isEmpty()) { - text.append('\n'); - } - for (String packageName : sortedExports) { - text.append("\n exports ").append(packageName).append(";"); - } - text.append("\n}"); - PsiDirectory rootDir = moduleNode.getRootDir(); if (rootDir != null) { - generatedCode.add(new GeneratedCode(rootDir, text.toString())); + List dependencies = StreamEx.of(moduleNode.getSortedDependencies()) + .map(ModuleNode::getName) + .filter(name -> !JAVA_BASE.equals(name)) + .toList(); + + List exports = moduleNode.getSortedExports(); + moduleInfo.add(new ModuleInfo(rootDir, moduleNode.getName(), dependencies, exports)); } else { - LOG.debug("Skipped module " + moduleNode); + LOG.info("Skipped module " + moduleNode + " because it doesn't have production source root"); } myProgressTracker.increment(); } - return generatedCode; + return moduleInfo; } - private static void createFiles(Project project, List generatedCode, ProgressIndicator indicator) { + private static void createFiles(Project project, List moduleInfos, ProgressIndicator indicator) { indicator.setIndeterminate(false); int count = 0; - double total = generatedCode.size(); - PsiFileFactory factory = PsiFileFactory.getInstance(project); - for (GeneratedCode code : generatedCode) { - ProgressManager.getInstance().executeNonCancelableSection(() -> { - PsiFile file = factory.createFileFromText(PsiJavaModule.MODULE_INFO_FILE, JavaLanguage.INSTANCE, code.myText); - PsiElement added = code.myRootDir.add(file); - CodeStyleManager.getInstance(project).reformat(added); - }); + double total = moduleInfos.size(); + FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate(INTERNAL_MODULE_INFO_TEMPLATE_NAME); + for (ModuleInfo moduleInfo : moduleInfos) { + ProgressManager.getInstance().executeNonCancelableSection(() -> createFile(template, moduleInfo)); indicator.setFraction(++count / total); } } + private static void createFile(FileTemplate template, ModuleInfo moduleInfo) { + Project project = moduleInfo.myRootDir.getProject(); + Properties properties = FileTemplateManager.getInstance(project).getDefaultProperties(); + FileTemplateUtil.fillDefaultProperties(properties, moduleInfo.myRootDir); + properties.setProperty(FileTemplate.ATTRIBUTE_NAME, MODULE_INFO_CLASS); + try { + PsiJavaFile moduleInfoFile = + (PsiJavaFile)FileTemplateUtil.createFromTemplate(template, MODULE_INFO_FILE, properties, moduleInfo.myRootDir); + PsiJavaModule javaModule = moduleInfoFile.getModuleDeclaration(); + LOG.assertTrue(javaModule != null, "module-info file should contain module declaration"); + + javaModule.setName(moduleInfo.myName); + for (String export : moduleInfo.myExports) { + PsiUtil.addModuleStatement(javaModule, PsiKeyword.EXPORTS + ' ' + export); + } + for (String dependency : moduleInfo.myRequires) { + PsiUtil.addModuleStatement(javaModule, PsiKeyword.REQUIRES + ' ' + dependency); + } + CodeStyleManager.getInstance(project).reformat(moduleInfoFile); + } + catch (Exception e) { + LOG.info("Failed to create module-info.java in " + moduleInfo.myRootDir.getVirtualFile().getPath() + ": " + e.getMessage()); + } + } + @Nullable private static PsiJavaModule findDescriptor(PsiPackage psiPackage) { PsiManager psiManager = psiPackage.getManager(); @@ -543,13 +563,20 @@ public class Java9GenerateModuleDescriptorsAction extends AnAction { } } - private static class GeneratedCode { + private static class ModuleInfo { final PsiDirectory myRootDir; - final String myText; + final String myName; + final List myRequires; + final List myExports; - private GeneratedCode(@NotNull PsiDirectory rootDir, @NotNull String text) { + private ModuleInfo(@NotNull PsiDirectory rootDir, + @NotNull String name, + @NotNull List requires, + @NotNull List exports) { myRootDir = rootDir; - myText = text; + myName = name; + myRequires = requires; + myExports = exports; } } } diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties index ae731a8a6a10..47ca1ecd2111 100644 --- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties +++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties @@ -834,4 +834,4 @@ generate.module.descriptors.build.required.message=Couldn't generate module desc generate.module.descriptors.scanning.message=Scanning Compiler Output generate.module.descriptors.collecting.message=Collecting Dependencies generate.module.descriptors.analysing.message=Analysing Dependencies -generate.module.descriptors.preparing.message=Analysing Dependencies \ No newline at end of file +generate.module.descriptors.preparing.message=Preparing Code \ No newline at end of file