lang-api
[idea/community.git] / platform / lang-api / src / com / intellij / openapi / module / ModuleUtil.java
1 /*
2  * Copyright 2000-2007 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * @author cdr
19  */
20 package com.intellij.openapi.module;
21
22 import com.intellij.openapi.application.ReadAction;
23 import com.intellij.openapi.application.Result;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.roots.*;
26 import com.intellij.openapi.util.Key;
27 import com.intellij.openapi.vfs.VirtualFile;
28 import com.intellij.psi.PsiDirectory;
29 import com.intellij.psi.PsiElement;
30 import com.intellij.psi.PsiFile;
31 import com.intellij.util.containers.HashSet;
32 import com.intellij.util.graph.Graph;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
35
36 import java.util.*;
37
38 public class ModuleUtil {
39   public static final Key<Module> KEY_MODULE = new Key<Module>("Module");
40
41   public static boolean projectContainsFile(final Project project, VirtualFile file, boolean isLibraryElement) {
42     final Module[] modules = ModuleManager.getInstance(project).getModules();
43     for (Module module : modules) {
44       if (moduleContainsFile(module, file, isLibraryElement)) return true;
45     }
46     return false;
47   }
48
49   public interface ModuleVisitor {
50     /**
51      *
52      * @param module module to be visited.
53      * @return false to stop visiting.
54      */
55     boolean visit(final Module module);
56   }
57
58   private ModuleUtil() {}
59
60   public static String getModuleNameInReadAction(@NotNull final Module module) {
61     return new ReadAction<String>(){
62       protected void run(final Result<String> result) throws Throwable {
63         result.setResult(module.getName());
64       }
65     }.execute().getResultObject();
66   }
67
68   public static boolean isModuleDisposed(PsiElement element) {
69     if (!element.isValid()) return true;
70     final Project project = element.getProject();
71     ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
72     final PsiFile file = element.getContainingFile();
73     if (file == null) return true;
74     VirtualFile vFile = file.getVirtualFile();
75     final Module module = vFile == null ? null : projectFileIndex.getModuleForFile(vFile);
76     // element may be in library
77     return module == null ? !projectFileIndex.isInLibraryClasses(vFile) : module.isDisposed();
78   }
79
80   @Nullable
81   public static Module getParentModuleOfType(ModuleType expectedModuleType, Module module) {
82     if (module == null) return null;
83     if (expectedModuleType.equals(module.getModuleType())) return module;
84     final List<Module> parents = getParentModulesOfType(expectedModuleType, module);
85     return parents.isEmpty() ? null : parents.get(0);
86   }
87
88   @NotNull
89   public static List<Module> getParentModulesOfType(ModuleType expectedModuleType, Module module) {
90     final List<Module> parents = ModuleManager.getInstance(module.getProject()).getModuleDependentModules(module);
91     ArrayList<Module> modules = new ArrayList<Module>();
92     for (Module parent : parents) {
93       if (expectedModuleType.equals(parent.getModuleType())) {
94         modules.add(parent);
95       }
96     }
97     return modules;
98   }
99
100   @Nullable
101   public static Module findModuleForFile(@NotNull VirtualFile file, @NotNull Project project) {
102     final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
103     return fileIndex.getModuleForFile(file);
104   }
105
106   @Nullable
107   public static Module findModuleForPsiElement(@NotNull PsiElement element) {
108     if (!element.isValid()) return null;
109
110     Project project = element.getProject();
111     final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project);
112     final ProjectFileIndex fileIndex = projectRootManager == null ? null : projectRootManager.getFileIndex();
113
114
115     /*
116      TODO[max]: Remove. This code seem to be unused and incorrect at the same time. At least module for PsiDirectory is being found using totally different way, which honors libraries
117     if (element instanceof PsiPackage) {
118       for (PsiDirectory directory : ((PsiPackage)element).getDirectories()) {
119         final Module module = fileIndex.getModuleForFile(directory.getVirtualFile());
120         if (module != null) {
121           return module;
122         }
123       }
124       return null;
125     }
126     */
127
128     if (element instanceof PsiDirectory) {
129       final VirtualFile vFile = ((PsiDirectory)element).getVirtualFile();
130       if (fileIndex.isInLibrarySource(vFile) || fileIndex.isInLibraryClasses(vFile)) {
131         final List<OrderEntry> orderEntries = fileIndex.getOrderEntriesForFile(vFile);
132         if (orderEntries.isEmpty()) {
133           return null;
134         }
135         Set<Module> modules = new HashSet<Module>();
136         for (OrderEntry orderEntry : orderEntries) {
137           modules.add(orderEntry.getOwnerModule());
138         }
139         final Module[] candidates = modules.toArray(new Module[modules.size()]);
140         Arrays.sort(candidates, ModuleManager.getInstance(project).moduleDependencyComparator());
141         return candidates[0];
142       }
143       return fileIndex.getModuleForFile(vFile);
144     }
145     PsiFile containingFile = element.getContainingFile();
146     if (containingFile != null) {
147       PsiElement context;
148       while ((context = containingFile.getContext()) != null) {
149         final PsiFile file = context.getContainingFile();
150         if (file == null) break;
151         containingFile = file;
152       }
153
154       if (containingFile.getUserData(KEY_MODULE) != null) {
155         return containingFile.getUserData(KEY_MODULE);
156       }
157
158       VirtualFile virtualFile = containingFile.getOriginalFile().getVirtualFile();
159       if (virtualFile != null) {
160         return fileIndex.getModuleForFile(virtualFile);
161       }
162     }
163
164     return element.getUserData(KEY_MODULE);
165   }
166
167   public static void getDependencies(@NotNull Module module, Set<Module> modules) {
168     if (modules.contains(module)) return;
169     modules.add(module);
170     Module[] dependencies = ModuleRootManager.getInstance(module).getDependencies();
171     for (Module dependency : dependencies) {
172       getDependencies(dependency, modules);
173     }
174   }
175
176   public static Collection<Module> collectModulesDependsOn(@NotNull final Collection<Module> modules) {
177     if (modules.isEmpty()) return Collections.emptyList();
178     final HashSet<Module> result = new HashSet<Module>();
179     final Project project = modules.iterator().next().getProject();
180     final ModuleManager moduleManager = ModuleManager.getInstance(project);
181     for (final Module module : modules) {
182       result.add(module);
183       result.addAll(moduleManager.getModuleDependentModules(module));
184     }
185     return result;
186   }
187
188   @NotNull
189   public static List<Module> getAllDependentModules(@NotNull Module module) {
190     final ArrayList<Module> list = new ArrayList<Module>();
191     final Graph<Module> graph = ModuleManager.getInstance(module.getProject()).moduleGraph();
192     for (Iterator<Module> i = graph.getOut(module); i.hasNext();) {
193       list.add(i.next());
194     }
195     return list;
196   }
197
198   public static boolean visitMeAndDependentModules(final @NotNull Module module, final ModuleVisitor visitor) {
199     if (!visitor.visit(module)) {
200       return false;
201     }
202     final List<Module> list = getAllDependentModules(module);
203     for (Module dependentModule : list) {
204       if (!visitor.visit(dependentModule)) {
205         return false;
206       }
207     }
208     return true;
209   }
210
211   public static boolean moduleContainsFile(final Module module, VirtualFile file, boolean isLibraryElement) {
212     ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
213     if (isLibraryElement) {
214       OrderEntry orderEntry = moduleRootManager.getFileIndex().getOrderEntryForFile(file);
215       return orderEntry instanceof ModuleJdkOrderEntry || orderEntry instanceof JdkOrderEntry ||
216              orderEntry instanceof LibraryOrderEntry;
217     }
218     else {
219       return moduleRootManager.getFileIndex().isInContent(file);
220     }
221   }
222 }