Android: Remove `kotlin-gradle-tooling.jar` from excludes
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / classpath / AnalyzeModuleDependencyAction.java
1 // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.roots.ui.configuration.classpath;
3
4 import com.intellij.CommonBundle;
5 import com.intellij.analysis.AnalysisScope;
6 import com.intellij.codeInsight.CodeInsightBundle;
7 import com.intellij.ide.JavaUiBundle;
8 import com.intellij.openapi.actionSystem.AnAction;
9 import com.intellij.openapi.actionSystem.AnActionEvent;
10 import com.intellij.openapi.diagnostic.Logger;
11 import com.intellij.openapi.module.Module;
12 import com.intellij.openapi.module.impl.scopes.LibraryScope;
13 import com.intellij.openapi.roots.*;
14 import com.intellij.openapi.roots.libraries.Library;
15 import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
16 import com.intellij.openapi.ui.Messages;
17 import com.intellij.openapi.util.text.StringUtil;
18 import com.intellij.openapi.vfs.VirtualFile;
19 import com.intellij.openapi.wm.ToolWindowId;
20 import com.intellij.packageDependencies.DependenciesBuilder;
21 import com.intellij.packageDependencies.DependencyVisitorFactory;
22 import com.intellij.packageDependencies.actions.AnalyzeDependenciesOnSpecifiedTargetHandler;
23 import com.intellij.psi.PsiFile;
24 import com.intellij.psi.search.GlobalSearchScope;
25 import org.jetbrains.annotations.Contract;
26 import org.jetbrains.annotations.Nls;
27 import org.jetbrains.annotations.NotNull;
28
29 import java.util.*;
30 import java.util.stream.Collectors;
31
32 class AnalyzeModuleDependencyAction extends AnAction {
33   private static final Logger LOG = Logger.getInstance(AnalyzeModuleDependencyAction.class);
34   private final ClasspathPanel myPanel;
35
36   AnalyzeModuleDependencyAction(final ClasspathPanel panel) {
37     super(JavaUiBundle.message("action.text.analyze.this.dependency"));
38     myPanel = panel;
39   }
40
41   @Override
42   public void actionPerformed(@NotNull AnActionEvent e) {
43     final OrderEntry selectedEntry = myPanel.getSelectedEntry();
44     GlobalSearchScope mainScope = getScopeForOrderEntry(selectedEntry);
45     LOG.assertTrue(mainScope != null);
46     Map<GlobalSearchScope, OrderEntry> additionalScopes;
47     ModulesProvider modulesProvider = myPanel.getModuleConfigurationState().getModulesProvider();
48     if (selectedEntry instanceof ModuleOrderEntry) {
49       Module depModule = ((ModuleOrderEntry)selectedEntry).getModule();
50       LOG.assertTrue(depModule != null);
51       Map<OrderEntry, OrderEntry> additionalDependencies = JavaProjectRootsUtil
52         .findExportedDependenciesReachableViaThisDependencyOnly(myPanel.getRootModel().getModule(),
53                                                                 depModule, modulesProvider);
54       additionalScopes = new LinkedHashMap<>();
55       for (Map.Entry<OrderEntry, OrderEntry> entry : additionalDependencies.entrySet()) {
56         additionalScopes.put(getScopeForOrderEntry(entry.getKey()), entry.getValue());
57       }
58     }
59     else {
60       additionalScopes = Collections.emptyMap();
61     }
62
63     List<GlobalSearchScope> scopes = new ArrayList<>(additionalScopes.keySet());
64     scopes.add(mainScope);
65     new AnalyzeDependenciesOnSpecifiedTargetHandler(myPanel.getProject(), new AnalysisScope(myPanel.getModuleConfigurationState().getRootModel().getModule()),
66                                                     GlobalSearchScope.union(scopes.toArray(GlobalSearchScope.EMPTY_ARRAY))) {
67       @Override
68       protected boolean shouldShowDependenciesPanel(List<? extends DependenciesBuilder> builders) {
69         Set<GlobalSearchScope> usedScopes = findUsedScopes(builders, scopes);
70         if (usedScopes.contains(mainScope)) {
71           Messages.showInfoMessage(myProject,
72                                    JavaUiBundle
73                                      .message("message.text.dependencies.were.successfully.collected.in.0.toolwindow", ToolWindowId.DEPENDENCIES),
74                                    getTemplateText());
75           return true;
76         }
77
78         List<OrderEntry> usedEntries = usedScopes.stream().map(additionalScopes::get).filter(Objects::nonNull).distinct().collect(Collectors.toList());
79         if (usedEntries.isEmpty()) {
80           final String message = JavaUiBundle.message("analyze.module.dependency.action.dialog.message.no.dependency.found", generateSkipImportsWarning());
81           if (Messages.showOkCancelDialog(myProject, message, getTemplateText(), CommonBundle.message("button.remove"),
82                                           Messages.getCancelButton(),
83                                           Messages.getWarningIcon()) == Messages.OK) {
84             myPanel.getRootModel().removeOrderEntry(selectedEntry);
85           }
86           return false;
87         }
88
89         final String firstEntry = usedEntries.get(0).getPresentableName();
90         final List<OrderEntry> tailEntries;
91         final String secondEntry;
92         if (usedEntries.size() > 1) {
93           tailEntries = usedEntries.subList(1, usedEntries.size() - 1);
94           secondEntry = usedEntries.get(1).getPresentableName();
95         }
96         else {
97           tailEntries = Collections.emptyList();
98           secondEntry = null;
99         }
100
101         final String usedExportedEntriesText = JavaUiBundle.message("analyze.module.dependency.exported.entries", firstEntry, secondEntry, tailEntries.size());
102         final String replacementText = JavaUiBundle.message("analyze.module.dependency.replacement.text", firstEntry, usedEntries.size());
103         final String message = JavaUiBundle.message("analyze.module.dependency.replace.dialog.message",
104                                                     generateSkipImportsWarning(),
105                                                     usedExportedEntriesText,
106                                                     StringUtil.decapitalize(selectedEntry.getPresentableName()),
107                                                     usedEntries.size(),
108                                                     selectedEntry.getPresentableName(),
109                                                     replacementText);
110         String[] options = {"Replace", "Show Dependencies", Messages.getCancelButton()};
111         switch (Messages.showDialog(myProject, message, getTemplateText(), options, 0, Messages.getWarningIcon())) {
112           case 0:
113             InlineModuleDependencyAction.inlineEntry(myPanel, selectedEntry, usedEntries::contains);
114             return false;
115           case 1:
116             return true;
117           default:
118             return false;
119         }
120       }
121
122       @Override
123       protected boolean canStartInBackground() {
124         return false;
125       }
126     }.analyze();
127   }
128
129   private @Nls(capitalization = Nls.Capitalization.Sentence) String generateSkipImportsWarning() {
130     if (DependencyVisitorFactory.VisitorOptions.fromSettings(myPanel.getProject()).skipImports()) {
131       return " " + CodeInsightBundle.message("dependencies.in.imports.message");
132     }
133     return "";
134   }
135
136   private static Set<GlobalSearchScope> findUsedScopes(List<? extends DependenciesBuilder> builders, List<? extends GlobalSearchScope> scopes) {
137     Set<GlobalSearchScope> usedScopes = new LinkedHashSet<>();
138     for (DependenciesBuilder builder : builders) {
139       for (Set<PsiFile> files : builder.getDependencies().values()) {
140         for (PsiFile file : files) {
141           VirtualFile virtualFile = file.getVirtualFile();
142           if (virtualFile != null) {
143             for (GlobalSearchScope scope : scopes) {
144               if (scope.contains(virtualFile)) {
145                 usedScopes.add(scope);
146               }
147             }
148           }
149         }
150       }
151     }
152     return usedScopes;
153   }
154
155   @Contract("null -> null")
156   private GlobalSearchScope getScopeForOrderEntry(OrderEntry selectedEntry) {
157     if (selectedEntry instanceof ModuleSourceOrderEntry) {
158       return GlobalSearchScope.moduleScope(selectedEntry.getOwnerModule());
159     }
160     if (selectedEntry instanceof ModuleOrderEntry) {
161       Module module = ((ModuleOrderEntry)selectedEntry).getModule();
162       return module != null ? GlobalSearchScope.moduleScope(module) : null;
163     }
164     if (selectedEntry instanceof LibraryOrderEntry) {
165       Library library = ((LibraryOrderEntry)selectedEntry).getLibrary();
166       return library != null ? new LibraryScope(myPanel.getProject(), library) : null;
167     }
168     return null;
169   }
170
171   @Override
172   public void update(@NotNull AnActionEvent e) {
173     final OrderEntry entry = myPanel.getSelectedEntry();
174     e.getPresentation().setVisible(entry instanceof ModuleOrderEntry && ((ModuleOrderEntry)entry).getModule() != null
175                                  || entry instanceof LibraryOrderEntry && ((LibraryOrderEntry)entry).getLibrary() != null);
176   }
177 }