/******************************************************************************* * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Markus Schorn - initial API and implementation * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.index; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.internal.core.CCoreInternals; import org.eclipse.cdt.internal.core.index.provider.IndexProviderManager; import org.eclipse.cdt.internal.core.pdom.PDOMManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.osgi.util.NLS; /** * Class that creates indexes based on PDOMs * @since 4.0 */ public class IndexFactory { private static final int ADD_DEPENDENCIES = IIndexManager.ADD_DEPENDENCIES; private static final int ADD_DEPENDENT = IIndexManager.ADD_DEPENDENT; private static final int SKIP_PROVIDED = IIndexManager.SKIP_PROVIDED; private static final int ADD_EXTENSION_FRAGMENTS = IIndexManager.ADD_EXTENSION_FRAGMENTS; private PDOMManager fPDOMManager; public IndexFactory(PDOMManager manager) { fPDOMManager= manager; } public IIndex getIndex(ICProject[] projects, int options) throws CoreException { projects = (ICProject[]) ArrayUtil.removeNulls(ICProject.class, projects); boolean addDependencies= (options & ADD_DEPENDENCIES) != 0; boolean addDependent= (options & ADD_DEPENDENT) != 0; boolean skipProvided= (options & SKIP_PROVIDED) != 0; boolean addExtensionFragments= (options & ADD_EXTENSION_FRAGMENTS) != 0; HashMap<IProject, Integer> map= new HashMap<IProject, Integer>(); Collection<ICProject> selectedProjects= getProjects(projects, addDependencies, addDependent, map, new Integer(1)); HashMap<String, IIndexFragment> fragments= new LinkedHashMap<String, IIndexFragment>(); for (ICProject cproject : selectedProjects) { IIndexFragment pdom= fPDOMManager.getPDOM(cproject); if (pdom != null) { safeAddFragment(fragments, pdom); if (!skipProvided) { safeAddProvidedFragments(cproject, fragments, addExtensionFragments); } } } if (fragments.isEmpty()) { return EmptyCIndex.INSTANCE; } int primaryFragmentCount= fragments.size(); if (!addDependencies) { projects= selectedProjects.toArray(new ICProject[selectedProjects.size()]); selectedProjects.clear(); // Don't clear the map, so projects are not selected again. selectedProjects= getProjects(projects, true, false, map, new Integer(2)); for (ICProject cproject : selectedProjects) { IIndexFragment pdom= fPDOMManager.getPDOM(cproject); safeAddFragment(fragments, pdom); if (!skipProvided) { safeAddProvidedFragments(cproject, fragments, addExtensionFragments); } } } Collection<IIndexFragment> pdoms= fragments.values(); return new CIndex(pdoms.toArray(new IIndexFragment[pdoms.size()]), primaryFragmentCount); } public IWritableIndex getWritableIndex(ICProject project) throws CoreException { Map<String, IIndexFragment> readOnlyFrag= new LinkedHashMap<String, IIndexFragment>(); IWritableIndexFragment pdom= (IWritableIndexFragment) fPDOMManager.getPDOM(project); if (pdom == null) { throw new CoreException(CCorePlugin.createStatus( NLS.bind(Messages.IndexFactory_errorNoSuchPDOM0, project.getElementName()))); } safeAddProvidedFragments(project, readOnlyFrag, false); Collection<ICProject> selectedProjects= getProjects(new ICProject[] {project}, true, false, new HashMap<IProject, Integer>(), new Integer(1)); selectedProjects.remove(project); for (ICProject cproject : selectedProjects) { safeAddFragment(readOnlyFrag, fPDOMManager.getPDOM(cproject)); } Collection<IIndexFragment> readOnlyFragments= readOnlyFrag.values(); return new WritableCIndex(pdom, readOnlyFragments.toArray(new IIndexFragment[readOnlyFragments.size()])); } private Collection<ICProject> getProjects(ICProject[] projects, boolean addDependencies, boolean addDependent, HashMap<IProject, Integer> map, Integer markWith) { List<IProject> projectsToSearch= new ArrayList<IProject>(); for (ICProject cproject : projects) { IProject project= cproject.getProject(); checkAddProject(project, map, projectsToSearch, markWith); projectsToSearch.add(project); } if (addDependencies || addDependent) { for (int i= 0; i < projectsToSearch.size(); i++) { IProject project= projectsToSearch.get(i); IProject[] nextLevel; try { if (addDependencies) { nextLevel = project.getReferencedProjects(); for (int j = 0; j < nextLevel.length; j++) { checkAddProject(nextLevel[j], map, projectsToSearch, markWith); } } if (addDependent) { nextLevel= project.getReferencingProjects(); for (int j = 0; j < nextLevel.length; j++) { checkAddProject(nextLevel[j], map, projectsToSearch, markWith); } } } catch (CoreException e) { // silently ignore map.put(project, new Integer(0)); } } } CoreModel cm= CoreModel.getDefault(); Collection<ICProject> result= new ArrayList<ICProject>(); for (Map.Entry<IProject, Integer> entry : map.entrySet()) { if (entry.getValue() == markWith) { ICProject cproject= cm.create(entry.getKey()); if (cproject != null) { result.add(cproject); } } } return result; } private void checkAddProject(IProject project, HashMap<IProject, Integer> map, List<IProject> projectsToSearch, Integer markWith) { if (map.get(project) == null) { if (project.isOpen()) { map.put(project, markWith); projectsToSearch.add(project); } else { map.put(project, new Integer(0)); } } } /** * Add an entry for the specified fragment. This copes with problems occurring when reading * the fragment ID. * @param id2fragment the map to add the entry to * @param fragment the fragment or null (which will result in no action) */ private void safeAddFragment(Map<String, IIndexFragment> id2fragment, IIndexFragment fragment) { if (fragment != null) { try { fragment.acquireReadLock(); try { String id= fragment.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID); id2fragment.put(id, fragment); } finally { fragment.releaseReadLock(); } } catch (CoreException e) { CCorePlugin.log(e); } catch (InterruptedException e) { CCorePlugin.log(e); } } } /** * Adds ID -> IIndexFragment entries to the specified Map, for fragments provided under * the CIndex extension point for the specified ICProject. * @param cproject The project to get the provided index fragments for. * @param fragments * @param includeNonPDOMFragments */ private void safeAddProvidedFragments(ICProject cproject, Map<String, IIndexFragment> fragments, boolean includeNonPDOMFragments) { ICProjectDescription pd= CoreModel.getDefault().getProjectDescription(cproject.getProject(), false); if (pd != null) { IndexProviderManager ipm = CCoreInternals.getPDOMManager().getIndexProviderManager(); ICConfigurationDescription cfg= pd.getDefaultSettingConfiguration(); if (cfg != null) { try { IIndexFragment[] pFragments= ipm.getProvidedIndexFragments(cfg, includeNonPDOMFragments); for (IIndexFragment fragment : pFragments) { safeAddFragment(fragments, fragment); } } catch (CoreException e) { CCorePlugin.log(e); } } } } }