/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.module;
import com.google.common.base.Predicates;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import com.intellij.util.graph.Graph;
import consulo.module.extension.ModuleExtension;
import consulo.module.extension.ModuleExtensionWithSdk;
import consulo.util.pointers.NamedPointer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.annotations.RequiredReadAction;
import consulo.roots.ContentFolderTypeProvider;
import java.util.*;
public class ModuleUtilCore {
public static final Key<Module> KEY_MODULE = new Key<Module>("Module");
public static boolean projectContainsFile(final Project project, VirtualFile file, boolean isLibraryElement) {
ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project);
if (isLibraryElement) {
List<OrderEntry> orders = projectRootManager.getFileIndex().getOrderEntriesForFile(file);
for (OrderEntry orderEntry : orders) {
if (orderEntry instanceof ModuleExtensionWithSdkOrderEntry || orderEntry instanceof LibraryOrderEntry) {
return true;
}
}
return false;
}
else {
return projectRootManager.getFileIndex().isInContent(file);
}
}
public static String getModuleNameInReadAction(@NotNull final Module module) {
return new ReadAction<String>() {
@Override
protected void run(final Result<String> result) throws Throwable {
result.setResult(module.getName());
}
}.execute().getResultObject();
}
public static boolean isModuleDisposed(PsiElement element) {
if (!element.isValid()) return true;
final Project project = element.getProject();
ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
final PsiFile file = element.getContainingFile();
if (file == null) return true;
VirtualFile vFile = file.getVirtualFile();
final Module module = vFile == null ? null : projectFileIndex.getModuleForFile(vFile);
// element may be in library
return module == null ? !projectFileIndex.isInLibraryClasses(vFile) : module.isDisposed();
}
@Nullable
public static Module findModuleForFile(@NotNull VirtualFile file, @NotNull Project project) {
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
return fileIndex.getModuleForFile(file);
}
@Nullable
@RequiredReadAction
public static Module findModuleForPsiElement(@NotNull PsiElement element) {
if (!element.isValid()) return null;
Project project = element.getProject();
if (project.isDefault()) return null;
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
if (element instanceof PsiFileSystemItem && (!(element instanceof PsiFile) || element.getContext() == null)) {
VirtualFile vFile = ((PsiFileSystemItem)element).getVirtualFile();
if (vFile == null) {
PsiFile containingFile = element.getContainingFile();
vFile = containingFile == null ? null : containingFile.getOriginalFile().getVirtualFile();
if (vFile == null) {
return element.getUserData(KEY_MODULE);
}
}
if (fileIndex.isInLibrarySource(vFile) || fileIndex.isInLibraryClasses(vFile)) {
final List<OrderEntry> orderEntries = fileIndex.getOrderEntriesForFile(vFile);
if (orderEntries.isEmpty()) {
return null;
}
if (orderEntries.size() == 1) {
return orderEntries.get(0).getOwnerModule();
}
Set<Module> modules = new HashSet<Module>();
for (OrderEntry orderEntry : orderEntries) {
modules.add(orderEntry.getOwnerModule());
}
final Module[] candidates = modules.toArray(new Module[modules.size()]);
Arrays.sort(candidates, ModuleManager.getInstance(project).moduleDependencyComparator());
return candidates[0];
}
return fileIndex.getModuleForFile(vFile);
}
PsiFile containingFile = element.getContainingFile();
if (containingFile != null) {
PsiElement context;
while ((context = containingFile.getContext()) != null) {
final PsiFile file = context.getContainingFile();
if (file == null) break;
containingFile = file;
}
if (containingFile.getUserData(KEY_MODULE) != null) {
return containingFile.getUserData(KEY_MODULE);
}
final PsiFile originalFile = containingFile.getOriginalFile();
if (originalFile.getUserData(KEY_MODULE) != null) {
return originalFile.getUserData(KEY_MODULE);
}
final VirtualFile virtualFile = originalFile.getVirtualFile();
if (virtualFile != null) {
return fileIndex.getModuleForFile(virtualFile);
}
}
return element.getUserData(KEY_MODULE);
}
//ignores export flag
public static void getDependencies(@NotNull Module module, Set<Module> modules) {
if (modules.contains(module)) return;
modules.add(module);
Module[] dependencies = ModuleRootManager.getInstance(module).getDependencies();
for (Module dependency : dependencies) {
getDependencies(dependency, modules);
}
}
/**
* collect transitive module dependants
*
* @param module to find dependencies on
* @param result resulted set
*/
@RequiredReadAction
public static void collectModulesDependsOn(@NotNull final Module module, final Set<Module> result) {
if (result.contains(module)) return;
result.add(module);
final ModuleManager moduleManager = ModuleManager.getInstance(module.getProject());
final List<Module> dependentModules = moduleManager.getModuleDependentModules(module);
for (final Module dependentModule : dependentModules) {
final OrderEntry[] orderEntries = ModuleRootManager.getInstance(dependentModule).getOrderEntries();
for (OrderEntry o : orderEntries) {
if (o instanceof ModuleOrderEntry) {
final ModuleOrderEntry orderEntry = (ModuleOrderEntry)o;
if (orderEntry.getModule() == module) {
if (orderEntry.isExported()) {
collectModulesDependsOn(dependentModule, result);
}
else {
result.add(dependentModule);
}
break;
}
}
}
}
}
@NotNull
@RequiredReadAction
public static List<Module> getAllDependentModules(@NotNull Module module) {
final ArrayList<Module> list = new ArrayList<Module>();
final Graph<Module> graph = ModuleManager.getInstance(module.getProject()).moduleGraph();
for (Iterator<Module> i = graph.getOut(module); i.hasNext(); ) {
list.add(i.next());
}
return list;
}
@RequiredReadAction
public static boolean visitMeAndDependentModules(@NotNull final Module module, final Processor<Module> visitor) {
if (!visitor.process(module)) {
return false;
}
final List<Module> list = getAllDependentModules(module);
for (Module dependentModule : list) {
if (!visitor.process(dependentModule)) {
return false;
}
}
return true;
}
public static boolean moduleContainsFile(@NotNull final Module module, VirtualFile file, boolean isLibraryElement) {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
if (isLibraryElement) {
OrderEntry orderEntry = moduleRootManager.getFileIndex().getOrderEntryForFile(file);
return orderEntry instanceof ModuleExtensionWithSdkOrderEntry || orderEntry instanceof LibraryOrderEntry;
}
else {
return moduleRootManager.getFileIndex().isInContent(file);
}
}
@RequiredReadAction
@NotNull
public static List<ContentFolder> getContentFolders(@NotNull Project project) {
ModuleManager moduleManager = ModuleManager.getInstance(project);
final List<ContentFolder> contentFolders = new ArrayList<ContentFolder>();
for (Module module : moduleManager.getModules()) {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
moduleRootManager.iterateContentEntries(new Processor<ContentEntry>() {
@Override
public boolean process(ContentEntry contentEntry) {
Collections.addAll(contentFolders, contentEntry.getFolders(Predicates.<ContentFolderTypeProvider>alwaysTrue()));
return false;
}
});
}
return contentFolders;
}
@Nullable
public static <E extends ModuleExtension<E>> E getExtension(@NotNull Module module, @NotNull Class<E> extensionClass) {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
return moduleRootManager.getExtension(extensionClass);
}
@Nullable
public static ModuleExtension<?> getExtension(@NotNull Module module, @NotNull String key) {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
return moduleRootManager.getExtension(key);
}
@Nullable
@RequiredReadAction
public static <E extends ModuleExtension<E>> E getExtension(@NotNull PsiElement element, @NotNull Class<E> extensionClass) {
Module moduleForPsiElement = findModuleForPsiElement(element);
if (moduleForPsiElement == null) {
return null;
}
return getExtension(moduleForPsiElement, extensionClass);
}
@Nullable
public static <E extends ModuleExtension<E>> E getExtension(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull Class<E> extensionClass) {
Module moduleForFile = findModuleForFile(virtualFile, project);
if (moduleForFile == null) {
return null;
}
return getExtension(moduleForFile, extensionClass);
}
@Nullable
public static Sdk getSdk(@NotNull Module module, @NotNull Class<? extends ModuleExtensionWithSdk> extensionClass) {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModuleExtensionWithSdk<?> extension = moduleRootManager.getExtension(extensionClass);
if (extension == null) {
return null;
}
else {
return extension.getSdk();
}
}
@Nullable
@RequiredReadAction
public static Sdk getSdk(@NotNull PsiElement element, @NotNull Class<? extends ModuleExtensionWithSdk> extensionClass) {
Module moduleForPsiElement = findModuleForPsiElement(element);
if (moduleForPsiElement == null) {
return null;
}
return getSdk(moduleForPsiElement, extensionClass);
}
@Nullable
public static Sdk getSdk(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull Class<? extends ModuleExtensionWithSdk> extensionClass) {
Module moduleForPsiElement = findModuleForFile(virtualFile, project);
if (moduleForPsiElement == null) {
return null;
}
return getSdk(moduleForPsiElement, extensionClass);
}
@NotNull
@RequiredReadAction
public static NamedPointer<Module> createPointer(@NotNull Module module) {
ModulePointerManager manager = ServiceManager.getService(module.getProject(), ModulePointerManager.class);
return manager.create(module);
}
@NotNull
@RequiredReadAction
public static NamedPointer<Module> createPointer(@NotNull Project project, @NotNull String name) {
ModulePointerManager manager = ServiceManager.getService(project, ModulePointerManager.class);
return manager.create(name);
}
}