@NotNull private Map<VirtualFile, OrderEntry[]> getOrderEntries() { Map<VirtualFile, OrderEntry[]> result = myOrderEntries; if (result != null) return result; MultiMap<VirtualFile, OrderEntry> libClassRootEntries = MultiMap.createSmart(); MultiMap<VirtualFile, OrderEntry> libSourceRootEntries = MultiMap.createSmart(); MultiMap<VirtualFile, OrderEntry> depEntries = MultiMap.createSmart(); for (final Module module : ModuleManager.getInstance(myProject).getModules()) { final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); for (OrderEntry orderEntry : moduleRootManager.getOrderEntries()) { if (orderEntry instanceof ModuleOrderEntry) { final Module depModule = ((ModuleOrderEntry) orderEntry).getModule(); if (depModule != null) { VirtualFile[] importedClassRoots = OrderEnumerator.orderEntries(depModule) .exportedOnly() .recursively() .classes() .usingCache() .getRoots(); for (VirtualFile importedClassRoot : importedClassRoots) { depEntries.putValue(importedClassRoot, orderEntry); } } for (VirtualFile sourceRoot : orderEntry.getFiles(OrderRootType.SOURCES)) { depEntries.putValue(sourceRoot, orderEntry); } } else if (orderEntry instanceof LibraryOrSdkOrderEntry) { final LibraryOrSdkOrderEntry entry = (LibraryOrSdkOrderEntry) orderEntry; for (final VirtualFile sourceRoot : entry.getRootFiles(OrderRootType.SOURCES)) { libSourceRootEntries.putValue(sourceRoot, orderEntry); } for (final VirtualFile classRoot : entry.getRootFiles(OrderRootType.CLASSES)) { libClassRootEntries.putValue(classRoot, orderEntry); } } } } RootInfo rootInfo = buildRootInfo(myProject); result = ContainerUtil.newHashMap(); Set<VirtualFile> allRoots = rootInfo.getAllRoots(); for (VirtualFile file : allRoots) { List<VirtualFile> hierarchy = getHierarchy(file, allRoots, rootInfo); result.put( file, hierarchy == null ? OrderEntry.EMPTY_ARRAY : calcOrderEntries( rootInfo, depEntries, libClassRootEntries, libSourceRootEntries, hierarchy)); } myOrderEntries = result; return result; }
void submitPasses( @NotNull Map<FileEditor, HighlightingPass[]> passesMap, @NotNull DaemonProgressIndicator updateProgress) { if (isDisposed()) return; // null keys are ok MultiMap<Document, FileEditor> documentToEditors = MultiMap.createSet(); MultiMap<FileEditor, TextEditorHighlightingPass> documentBoundPasses = MultiMap.createSmart(); MultiMap<FileEditor, EditorBoundHighlightingPass> editorBoundPasses = MultiMap.createSmart(); List<Pair<FileEditor, TextEditorHighlightingPass>> passesWithNoDocuments = new ArrayList<>(); Set<VirtualFile> vFiles = new HashSet<>(); for (Map.Entry<FileEditor, HighlightingPass[]> entry : passesMap.entrySet()) { FileEditor fileEditor = entry.getKey(); HighlightingPass[] passes = entry.getValue(); Document document; if (fileEditor instanceof TextEditor) { Editor editor = ((TextEditor) fileEditor).getEditor(); LOG.assertTrue(!(editor instanceof EditorWindow)); document = editor.getDocument(); } else { VirtualFile virtualFile = ((FileEditorManagerEx) FileEditorManager.getInstance(myProject)).getFile(fileEditor); document = virtualFile == null ? null : FileDocumentManager.getInstance().getDocument(virtualFile); } if (document != null) { vFiles.add(FileDocumentManager.getInstance().getFile(document)); } int prevId = 0; for (final HighlightingPass pass : passes) { if (pass instanceof EditorBoundHighlightingPass) { EditorBoundHighlightingPass editorPass = (EditorBoundHighlightingPass) pass; editorPass.setId( nextPassId.incrementAndGet()); // have to make ids unique for this document editorBoundPasses.putValue(fileEditor, editorPass); } else { TextEditorHighlightingPass textEditorHighlightingPass = convertToTextHighlightingPass(pass, document, nextPassId, prevId); document = textEditorHighlightingPass.getDocument(); documentBoundPasses.putValue(fileEditor, textEditorHighlightingPass); if (document == null) { passesWithNoDocuments.add(Pair.create(fileEditor, textEditorHighlightingPass)); } else { documentToEditors.putValue(document, fileEditor); } prevId = textEditorHighlightingPass.getId(); } } } List<ScheduledPass> freePasses = new ArrayList<>(documentToEditors.size() * 5); List<ScheduledPass> dependentPasses = new ArrayList<>(documentToEditors.size() * 10); // (fileEditor, passId) -> created pass Map<Pair<FileEditor, Integer>, ScheduledPass> toBeSubmitted = new THashMap<>(passesMap.size()); final AtomicInteger threadsToStartCountdown = new AtomicInteger(0); for (Map.Entry<Document, Collection<FileEditor>> entry : documentToEditors.entrySet()) { Collection<FileEditor> fileEditors = entry.getValue(); Document document = entry.getKey(); FileEditor preferredFileEditor = getPreferredFileEditor(document, fileEditors); List<TextEditorHighlightingPass> passes = (List<TextEditorHighlightingPass>) documentBoundPasses.get(preferredFileEditor); if (passes.isEmpty()) { continue; } sortById(passes); for (TextEditorHighlightingPass currentPass : passes) { createScheduledPass( preferredFileEditor, currentPass, toBeSubmitted, passes, freePasses, dependentPasses, updateProgress, threadsToStartCountdown); } } for (Map.Entry<FileEditor, Collection<EditorBoundHighlightingPass>> entry : editorBoundPasses.entrySet()) { FileEditor fileEditor = entry.getKey(); Collection<EditorBoundHighlightingPass> createdEditorBoundPasses = entry.getValue(); List<TextEditorHighlightingPass> createdDocumentBoundPasses = (List<TextEditorHighlightingPass>) documentBoundPasses.get(fileEditor); List<TextEditorHighlightingPass> allCreatedPasses = new ArrayList<>(createdDocumentBoundPasses); allCreatedPasses.addAll(createdEditorBoundPasses); for (EditorBoundHighlightingPass pass : createdEditorBoundPasses) { createScheduledPass( fileEditor, pass, toBeSubmitted, allCreatedPasses, freePasses, dependentPasses, updateProgress, threadsToStartCountdown); } } for (Pair<FileEditor, TextEditorHighlightingPass> pair : passesWithNoDocuments) { FileEditor fileEditor = pair.first; TextEditorHighlightingPass pass = pair.second; createScheduledPass( fileEditor, pass, toBeSubmitted, ContainerUtil.emptyList(), freePasses, dependentPasses, updateProgress, threadsToStartCountdown); } if (CHECK_CONSISTENCY && !ApplicationInfoImpl.isInPerformanceTest()) { assertConsistency(freePasses, toBeSubmitted, threadsToStartCountdown); } log( updateProgress, null, vFiles + " ----- starting " + threadsToStartCountdown.get(), freePasses); for (ScheduledPass dependentPass : dependentPasses) { mySubmittedPasses.put(dependentPass, Job.NULL_JOB); } for (ScheduledPass freePass : freePasses) { submit(freePass); } }
// used in upsource protected void readExternal(@NotNull Element element) { final PluginBean pluginBean = XmlSerializer.deserialize(element, PluginBean.class); url = pluginBean.url; myName = pluginBean.name; String idString = pluginBean.id; if (idString == null || idString.isEmpty()) { idString = myName; } myId = idString == null ? null : PluginId.getId(idString); String internalVersionString = pluginBean.formatVersion; if (internalVersionString != null) { try { //noinspection ResultOfMethodCallIgnored Integer.parseInt(internalVersionString); } catch (NumberFormatException e) { LOG.error( new PluginException( "Invalid value in plugin.xml format version: '" + internalVersionString + "'", e, myId)); } } myUseIdeaClassLoader = pluginBean.useIdeaClassLoader; myAllowBundledUpdate = pluginBean.allowBundledUpdate; if (pluginBean.ideaVersion != null) { mySinceBuild = pluginBean.ideaVersion.sinceBuild; myUntilBuild = convertExplicitBigNumberInUntilBuildToStar(pluginBean.ideaVersion.untilBuild); } myResourceBundleBaseName = pluginBean.resourceBundle; myDescriptionChildText = pluginBean.description; myChangeNotes = pluginBean.changeNotes; myVersion = pluginBean.pluginVersion; if (myVersion == null) { myVersion = PluginManagerCore.getBuildNumber().asStringWithoutProductCode(); } myCategory = pluginBean.category; if (pluginBean.vendor != null) { myVendor = pluginBean.vendor.name; myVendorEmail = pluginBean.vendor.email; myVendorUrl = pluginBean.vendor.url; myVendorLogoPath = pluginBean.vendor.logo; } // preserve items order as specified in xml (filterBadPlugins will not fail if module comes // first) Set<PluginId> dependentPlugins = new LinkedHashSet<PluginId>(); Set<PluginId> optionalDependentPlugins = new LinkedHashSet<PluginId>(); if (pluginBean.dependencies != null) { myOptionalConfigs = new THashMap<PluginId, String>(); for (PluginDependency dependency : pluginBean.dependencies) { String text = dependency.pluginId; if (!StringUtil.isEmpty(text)) { PluginId id = PluginId.getId(text); dependentPlugins.add(id); if (dependency.optional) { optionalDependentPlugins.add(id); if (!StringUtil.isEmpty(dependency.configFile)) { myOptionalConfigs.put(id, dependency.configFile); } } } } } myDependencies = dependentPlugins.isEmpty() ? PluginId.EMPTY_ARRAY : dependentPlugins.toArray(new PluginId[dependentPlugins.size()]); myOptionalDependencies = optionalDependentPlugins.isEmpty() ? PluginId.EMPTY_ARRAY : optionalDependentPlugins.toArray(new PluginId[optionalDependentPlugins.size()]); if (pluginBean.helpSets == null || pluginBean.helpSets.length == 0) { myHelpSets = HelpSetPath.EMPTY; } else { myHelpSets = new HelpSetPath[pluginBean.helpSets.length]; PluginHelpSet[] sets = pluginBean.helpSets; for (int i = 0, n = sets.length; i < n; i++) { PluginHelpSet pluginHelpSet = sets[i]; myHelpSets[i] = new HelpSetPath(pluginHelpSet.file, pluginHelpSet.path); } } myAppComponents = pluginBean.applicationComponents; myProjectComponents = pluginBean.projectComponents; myModuleComponents = pluginBean.moduleComponents; if (myAppComponents == null) myAppComponents = ComponentConfig.EMPTY_ARRAY; if (myProjectComponents == null) myProjectComponents = ComponentConfig.EMPTY_ARRAY; if (myModuleComponents == null) myModuleComponents = ComponentConfig.EMPTY_ARRAY; StringInterner interner = new StringInterner(); List<Element> extensions = copyElements(pluginBean.extensions, interner); if (extensions != null) { myExtensions = MultiMap.createSmart(); for (Element extension : extensions) { myExtensions.putValue(ExtensionsAreaImpl.extractEPName(extension), extension); } } List<Element> extensionPoints = copyElements(pluginBean.extensionPoints, interner); if (extensionPoints != null) { myExtensionsPoints = MultiMap.createSmart(); for (Element extensionPoint : extensionPoints) { myExtensionsPoints.putValue( StringUtil.notNullize( extensionPoint.getAttributeValue(ExtensionsAreaImpl.ATTRIBUTE_AREA)), extensionPoint); } } myActionsElements = copyElements(pluginBean.actions, interner); if (pluginBean.modules != null && !pluginBean.modules.isEmpty()) { myModules = pluginBean.modules; } }
private static class RootInfo { // getDirectoriesByPackageName used to be in this order, some clients might rely on that @NotNull final LinkedHashSet<VirtualFile> classAndSourceRoots = ContainerUtil.newLinkedHashSet(); @NotNull final Set<VirtualFile> libraryOrSdkSources = ContainerUtil.newHashSet(); @NotNull final Set<VirtualFile> libraryOrSdkClasses = ContainerUtil.newHashSet(); @NotNull final Map<VirtualFile, Module> contentRootOf = ContainerUtil.newHashMap(); @NotNull final MultiMap<VirtualFile, Module> sourceRootOf = MultiMap.createSet(); @NotNull final TObjectIntHashMap<VirtualFile> rootTypeId = new TObjectIntHashMap<VirtualFile>(); @NotNull final MultiMap<VirtualFile, Library> excludedFromLibraries = MultiMap.createSmart(); @NotNull final MultiMap<VirtualFile, Library> classOfLibraries = MultiMap.createSmart(); @NotNull final MultiMap<VirtualFile, Library> sourceOfLibraries = MultiMap.createSmart(); @NotNull final Set<VirtualFile> excludedFromProject = ContainerUtil.newHashSet(); @NotNull final Map<VirtualFile, Module> excludedFromModule = ContainerUtil.newHashMap(); @NotNull final Map<VirtualFile, String> packagePrefix = ContainerUtil.newHashMap(); @NotNull Set<VirtualFile> getAllRoots() { LinkedHashSet<VirtualFile> result = ContainerUtil.newLinkedHashSet(); result.addAll(classAndSourceRoots); result.addAll(contentRootOf.keySet()); result.addAll(excludedFromLibraries.keySet()); result.addAll(excludedFromModule.keySet()); result.addAll(excludedFromProject); return result; } @Nullable private VirtualFile findModuleRootInfo(@NotNull List<VirtualFile> hierarchy) { for (VirtualFile root : hierarchy) { Module module = contentRootOf.get(root); Module excludedFrom = excludedFromModule.get(root); if (module != null && excludedFrom != module) { return root; } if (excludedFrom != null || excludedFromProject.contains(root)) { return null; } } return null; } @Nullable private VirtualFile findNearestContentRootForExcluded(@NotNull List<VirtualFile> hierarchy) { for (VirtualFile root : hierarchy) { if (contentRootOf.containsKey(root)) { return root; } } return null; } @Nullable private VirtualFile findLibraryRootInfo(@NotNull List<VirtualFile> hierarchy, boolean source) { Set<Library> librariesToIgnore = ContainerUtil.newHashSet(); for (VirtualFile root : hierarchy) { librariesToIgnore.addAll(excludedFromLibraries.get(root)); if (source && libraryOrSdkSources.contains(root) && (!sourceOfLibraries.containsKey(root) || !librariesToIgnore.containsAll(sourceOfLibraries.get(root)))) { return root; } else if (!source && libraryOrSdkClasses.contains(root) && (!classOfLibraries.containsKey(root) || !librariesToIgnore.containsAll(classOfLibraries.get(root)))) { return root; } } return null; } private String calcPackagePrefix( @NotNull VirtualFile root, @NotNull List<VirtualFile> hierarchy, VirtualFile moduleContentRoot, VirtualFile libraryClassRoot, VirtualFile librarySourceRoot) { VirtualFile packageRoot = findPackageRootInfo(hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); String prefix = packagePrefix.get(packageRoot); if (prefix != null && !root.equals(packageRoot)) { assert packageRoot != null; String relative = VfsUtilCore.getRelativePath(root, packageRoot, '.'); prefix = StringUtil.isEmpty(prefix) ? relative : prefix + '.' + relative; } return prefix; } @Nullable private VirtualFile findPackageRootInfo( @NotNull List<VirtualFile> hierarchy, VirtualFile moduleContentRoot, VirtualFile libraryClassRoot, VirtualFile librarySourceRoot) { for (VirtualFile root : hierarchy) { if (moduleContentRoot != null && sourceRootOf.get(root).contains(contentRootOf.get(moduleContentRoot)) && librarySourceRoot == null) { return root; } if (root.equals(libraryClassRoot) || root.equals(librarySourceRoot)) { return root; } if (root.equals(moduleContentRoot) && !sourceRootOf.containsKey(root) && librarySourceRoot == null && libraryClassRoot == null) { return null; } } return null; } @NotNull private LinkedHashSet<OrderEntry> getLibraryOrderEntries( @NotNull List<VirtualFile> hierarchy, @Nullable VirtualFile libraryClassRoot, @Nullable VirtualFile librarySourceRoot, @NotNull MultiMap<VirtualFile, OrderEntry> libClassRootEntries, @NotNull MultiMap<VirtualFile, OrderEntry> libSourceRootEntries) { LinkedHashSet<OrderEntry> orderEntries = ContainerUtil.newLinkedHashSet(); for (VirtualFile root : hierarchy) { if (root.equals(libraryClassRoot) && !sourceRootOf.containsKey(root)) { orderEntries.addAll(libClassRootEntries.get(root)); } if (root.equals(librarySourceRoot) && libraryClassRoot == null) { orderEntries.addAll(libSourceRootEntries.get(root)); } if (libClassRootEntries.containsKey(root) || sourceRootOf.containsKey(root) && librarySourceRoot == null) { break; } } return orderEntries; } @Nullable private ModuleSourceOrderEntry getModuleSourceEntry( @NotNull List<VirtualFile> hierarchy, @NotNull VirtualFile moduleContentRoot, @NotNull MultiMap<VirtualFile, OrderEntry> libClassRootEntries) { Module module = contentRootOf.get(moduleContentRoot); for (VirtualFile root : hierarchy) { if (sourceRootOf.get(root).contains(module)) { return ContainerUtil.findInstance( ModuleRootManager.getInstance(module).getOrderEntries(), ModuleSourceOrderEntry.class); } if (libClassRootEntries.containsKey(root)) { return null; } } return null; } }