/******************************************************************************* * Copyright (c) 2000, 2010 QNX Software Systems 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: * QNX Software Systems - Initial API and implementation * Anton Leherbauer (Wind River Systems) * Markus Schorn (Wind River Systems) * IBM Corporation * James Blackburn (Broadcom Corporation) *******************************************************************************/ package org.eclipse.cdt.internal.core.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ElementChangedEvent; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICElementDelta; import org.eclipse.cdt.core.model.ICModelMarker; import org.eclipse.cdt.core.model.ICModelStatus; import org.eclipse.cdt.core.model.ICModelStatusConstants; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IContainerEntry; import org.eclipse.cdt.core.model.IElementChangedListener; import org.eclipse.cdt.core.model.IIncludeEntry; import org.eclipse.cdt.core.model.IIncludeFileEntry; import org.eclipse.cdt.core.model.ILibraryEntry; import org.eclipse.cdt.core.model.IMacroEntry; import org.eclipse.cdt.core.model.IMacroFileEntry; import org.eclipse.cdt.core.model.IOutputEntry; import org.eclipse.cdt.core.model.IPathEntry; import org.eclipse.cdt.core.model.IPathEntryContainer; import org.eclipse.cdt.core.model.IPathEntryContainerExtension; import org.eclipse.cdt.core.model.IProjectEntry; import org.eclipse.cdt.core.model.ISourceEntry; import org.eclipse.cdt.core.model.ISourceRoot; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.core.model.PathEntryContainerChanged; import org.eclipse.cdt.core.model.PathEntryContainerInitializer; import org.eclipse.cdt.core.resources.IPathEntryStore; import org.eclipse.cdt.core.resources.IPathEntryStoreListener; import org.eclipse.cdt.core.resources.PathEntryStoreChangedEvent; import org.eclipse.cdt.core.settings.model.util.PathEntryResolveInfo; import org.eclipse.cdt.core.settings.model.util.PathEntryResolveInfoElement; import org.eclipse.cdt.core.settings.model.util.ThreadLocalMap; import org.eclipse.cdt.internal.core.settings.model.AbstractCExtensionProxy; import org.eclipse.cdt.internal.core.settings.model.ConfigBasedPathEntryStore; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; /** * @author alain */ public class PathEntryManager implements IPathEntryStoreListener, IElementChangedListener { // PathEntry extension public final static String PATHENTRY_STORE_ID = "PathEntryStore"; //$NON-NLS-1$ public final static String PATHENTRY_STORE_UNIQ_ID = CCorePlugin.PLUGIN_ID + "." + PATHENTRY_STORE_ID; //$NON-NLS-1$ static String CONTAINER_INITIALIZER_EXTPOINT_ID = "PathEntryContainerInitializer"; //$NON-NLS-1$ /** * An empty array of strings indicating that a project doesn't have any * prerequesite projects. */ static final String[] NO_PREREQUISITES = new String[0]; /** * pathentry containers pool accessing the Container is done synch with the * class */ private static HashMap<ICProject, Map<IPath, IPathEntryContainer>> Containers = new HashMap<ICProject, Map<IPath, IPathEntryContainer>>(5); static final IPathEntry[] NO_PATHENTRIES = new IPathEntry[0]; static final IIncludeEntry[] NO_INCLUDE_ENTRIES = new IIncludeEntry[0]; static final IIncludeFileEntry[] NO_INCLUDE_FILE_ENTRIES = new IIncludeFileEntry[0]; static final IMacroEntry[] NO_MACRO_ENTRIES = new IMacroEntry[0]; static final IMacroFileEntry[] NO_MACRO_FILE_ENTRIES = new IMacroFileEntry[0]; static final IPathEntryContainer[] NO_PATHENTRYCONTAINERS = new IPathEntryContainer[0]; // Synchronized the access of the cache entries. protected Map<ICProject, ArrayList<IPathEntry>> resolvedMap = new Hashtable<ICProject, ArrayList<IPathEntry>>(); private Map<ICProject, PathEntryResolveInfo> resolvedInfoMap = new Hashtable<ICProject, PathEntryResolveInfo>(); private ThreadLocalMap resolveInfoValidState = new ThreadLocalMap(); // Accessing the map is synch with the class private Map<IProject, IPathEntryStore> storeMap = new HashMap<IProject, IPathEntryStore>(); private static PathEntryManager pathEntryManager; protected ConcurrentLinkedQueue<PathEntryProblem> markerProblems = new ConcurrentLinkedQueue<PathEntryProblem>(); //Setting up a generate markers job, it does not get scheduled Job markerTask = new GenerateMarkersJob("PathEntry Marker Job"); //$NON-NLS-1$ private PathEntryManager() { } private class PathEntryProblem { IProject project; ICModelStatus[] problems; public PathEntryProblem(IProject project, ICModelStatus[] problems) { this.project = project; this.problems = problems; } } private class PathEntryContainerLock implements IPathEntryContainer { boolean runInitializer; public boolean isContainerInitialize() { return runInitializer; } public void setContainerInitialize(boolean init) { runInitializer = init; } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.model.IPathEntryContainer#getPathEntries() */ public IPathEntry[] getPathEntries() { return NO_PATHENTRIES; } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.model.IPathEntryContainer#getDescription() */ public String getDescription() { return new String("Lock container"); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.model.IPathEntryContainer#getPath() */ public IPath getPath() { return Path.EMPTY; } } /** * Return the singleton. */ public static synchronized PathEntryManager getDefault() { if (pathEntryManager == null) { pathEntryManager = new PathEntryManager(); CoreModel.getDefault().addElementChangedListener(pathEntryManager); } return pathEntryManager; } public IIncludeFileEntry[] getIncludeFileEntries(IPath resPath) throws CModelException { ICElement celement = CoreModel.getDefault().create(resPath); if (celement instanceof ITranslationUnit) { return getIncludeFileEntries((ITranslationUnit)celement); } if (celement != null) { // get project include file entries List<IPathEntry> entryList = new ArrayList<IPathEntry>(); ICProject cproject = celement.getCProject(); ArrayList<IPathEntry> resolvedListEntries = getResolvedPathEntries(cproject, false); IPathEntry[] pathEntries= getCachedResolvedPathEntries(resolvedListEntries, cproject); for (int i = 0; i < pathEntries.length; ++i) { IPathEntry entry = pathEntries[i]; if ((entry.getEntryKind() & IPathEntry.CDT_INCLUDE_FILE) != 0) { entryList.add(entry); } } IIncludeFileEntry[] incFiles = entryList.toArray(new IIncludeFileEntry[entryList.size()]); return incFiles; } return NO_INCLUDE_FILE_ENTRIES; } public IIncludeFileEntry[] getIncludeFileEntries(ITranslationUnit cunit) throws CModelException { List<IPathEntry> list = getPathEntries(cunit, IPathEntry.CDT_INCLUDE_FILE); IIncludeFileEntry[] incFiles = list.toArray(new IIncludeFileEntry[list.size()]); return incFiles; } public IIncludeEntry[] getIncludeEntries(IPath resPath) throws CModelException { ICElement celement = CoreModel.getDefault().create(resPath); if (celement instanceof ITranslationUnit) { return getIncludeEntries((ITranslationUnit)celement); } if (celement != null) { // get project include entries List<IPathEntry> entryList = new ArrayList<IPathEntry>(); ICProject cproject = celement.getCProject(); ArrayList<IPathEntry> resolvedListEntries = getResolvedPathEntries(cproject, false); IPathEntry[] pathEntries= getCachedResolvedPathEntries(resolvedListEntries, cproject); for (int i = 0; i < pathEntries.length; ++i) { IPathEntry entry = pathEntries[i]; if ((entry.getEntryKind() & IPathEntry.CDT_INCLUDE) != 0) { entryList.add(entry); } } IIncludeEntry[] includes = entryList.toArray(new IIncludeEntry[entryList.size()]); return includes; } return NO_INCLUDE_ENTRIES; } public IIncludeEntry[] getIncludeEntries(ITranslationUnit cunit) throws CModelException { List<IPathEntry> list = getPathEntries(cunit, IPathEntry.CDT_INCLUDE); IIncludeEntry[] includes = list.toArray(new IIncludeEntry[list.size()]); return includes; } public IMacroEntry[] getMacroEntries(IPath resPath) throws CModelException { ICElement celement = CoreModel.getDefault().create(resPath); if (celement instanceof ITranslationUnit) { return getMacroEntries((ITranslationUnit)celement); } if (celement != null) { // get project macro entries List<IPathEntry> entryList = new ArrayList<IPathEntry>(); ICProject cproject = celement.getCProject(); ArrayList<IPathEntry> resolvedListEntries = getResolvedPathEntries(cproject, false); IPathEntry[] pathEntries= getCachedResolvedPathEntries(resolvedListEntries, cproject); for (int i = 0; i < pathEntries.length; ++i) { IPathEntry entry = pathEntries[i]; if ((entry.getEntryKind() & IPathEntry.CDT_MACRO) != 0) { entryList.add(entry); } } IMacroEntry[] macros= entryList.toArray(new IMacroEntry[entryList.size()]); return macros; } return NO_MACRO_ENTRIES; } private IMacroEntry[] getMacroEntries(ITranslationUnit cunit) throws CModelException { ArrayList<IPathEntry> macroList = new ArrayList<IPathEntry>(); ICProject cproject = cunit.getCProject(); IPath resPath = cunit.getPath(); // Do this first so the containers get inialized. ArrayList<IPathEntry> resolvedListEntries = getResolvedPathEntries(cproject, false); for (int i = 0; i < resolvedListEntries.size(); ++i) { IPathEntry entry = resolvedListEntries.get(i); if (entry.getEntryKind() == IPathEntry.CDT_MACRO) { macroList.add(entry); } } IPathEntryContainer[] containers = getPathEntryContainers(cproject); for (int i = 0; i < containers.length; ++i) { if (containers[i] instanceof IPathEntryContainerExtension) { IPathEntryContainerExtension extension = (IPathEntryContainerExtension)containers[i]; IPathEntry[] incs = extension.getPathEntries(resPath, IPathEntry.CDT_MACRO); macroList.addAll(Arrays.asList(incs)); } } IMacroEntry[] macros = macroList.toArray(new IMacroEntry[macroList.size()]); macroList.clear(); // For the macros the closest symbol will override // /projec/src/file.c --> NDEBUG=1 // /project/src --> NDEBUG=0 // // We will use NDEBUG=1 only int count = resPath.segmentCount(); Map<String, IMacroEntry> symbolMap = new HashMap<String, IMacroEntry>(); for (int i = 0; i < count; i++) { IPath newPath = resPath.removeLastSegments(i); for (IMacroEntry macro : macros) { IPath otherPath = macro.getPath(); if (newPath.equals(otherPath)) { String key = macro.getMacroName(); if (!symbolMap.containsKey(key)) { symbolMap.put(key, macro); } } } } // Add the Project contributions last. for (int i = 0; i < resolvedListEntries.size(); i++) { IPathEntry entry = resolvedListEntries.get(i); if (entry != null && entry.getEntryKind() == IPathEntry.CDT_PROJECT) { IResource res = cproject.getCModel().getWorkspace().getRoot().findMember(entry.getPath()); if (res != null && res.getType() == IResource.PROJECT) { ICProject refCProject = CoreModel.getDefault().create((IProject)res); if (refCProject != null) { IPathEntry[] projEntries = refCProject.getResolvedPathEntries(); for (IPathEntry projEntry : projEntries) { if (projEntry.isExported()) { if (projEntry.getEntryKind() == IPathEntry.CDT_MACRO) { IMacroEntry macro = (IMacroEntry)entry; String key = macro.getMacroName(); if (!symbolMap.containsKey(key)) { symbolMap.put(key, macro); } } } } } } } } return symbolMap.values().toArray(NO_MACRO_ENTRIES); } public IMacroFileEntry[] getMacroFileEntries(IPath resPath) throws CModelException { ICElement celement = CoreModel.getDefault().create(resPath); if (celement instanceof ITranslationUnit) { return getMacroFileEntries((ITranslationUnit)celement); } return NO_MACRO_FILE_ENTRIES; } public IMacroFileEntry[] getMacroFileEntries(ITranslationUnit cunit) throws CModelException { List<IPathEntry> list = getPathEntries(cunit, IPathEntry.CDT_MACRO_FILE); IMacroFileEntry[] macFiles = list.toArray(new IMacroFileEntry[list.size()]); return macFiles; } private List<IPathEntry> getPathEntries(ITranslationUnit cunit, int type) throws CModelException { ArrayList<IPathEntry> entryList = new ArrayList<IPathEntry>(); ICProject cproject = cunit.getCProject(); IPath resPath = cunit.getPath(); // Do this first so the containers get inialized. ArrayList<IPathEntry> resolvedListEntries = getResolvedPathEntries(cproject, false); for (int i = 0; i < resolvedListEntries.size(); ++i) { IPathEntry entry = resolvedListEntries.get(i); if ((entry.getEntryKind() & type) != 0) { entryList.add(entry); } } IPathEntryContainer[] containers = getPathEntryContainers(cproject); for (int i = 0; i < containers.length; ++i) { if (containers[i] instanceof IPathEntryContainerExtension) { IPathEntryContainerExtension extension = (IPathEntryContainerExtension)containers[i]; IPathEntry[] incs = extension.getPathEntries(resPath, type); entryList.addAll(Arrays.asList(incs)); } } IPathEntry[] entries = entryList.toArray(new IPathEntry[entryList.size()]); // Clear the list since we are reusing it. entryList.clear(); // We need to reorder the include/macros: // includes with the closest match to the resource will come first // /project/src/file.c --> /usr/local/include // /project --> /usr/include // // /usr/local/include must come first. // int count = resPath.segmentCount(); for (int i = 0; i < count; i++) { IPath newPath = resPath.removeLastSegments(i); for (IPathEntry entry : entries) { IPath otherPath = entry.getPath(); if (newPath.equals(otherPath)) { entryList.add(entry); } } } // Since the include that comes from a project contribution are not // tied to a resource they are added last. for (int i = 0; i < resolvedListEntries.size(); i++) { IPathEntry entry = resolvedListEntries.get(i); if (entry != null && entry.getEntryKind() == IPathEntry.CDT_PROJECT) { IResource res = cproject.getCModel().getWorkspace().getRoot().findMember(entry.getPath()); if (res != null && res.getType() == IResource.PROJECT) { ICProject refCProject = CoreModel.getDefault().create((IProject)res); if (refCProject != null) { IPathEntry[] projEntries = refCProject.getResolvedPathEntries(); for (IPathEntry projEntry : projEntries) { if (projEntry.isExported()) { if ((projEntry.getEntryKind() & type) != 0) { entryList.add(projEntry); } } } } } } } return entryList; } /** * Return the cached entries, if no cache null. * @param cproject */ protected IPathEntry[] getCachedResolvedPathEntries(ICProject cproject) { ArrayList<IPathEntry> resolvedListEntries = resolvedMap.get(cproject); if (resolvedListEntries != null) { try { return getCachedResolvedPathEntries(resolvedListEntries, cproject); } catch (CModelException e) { // } } return null; } public PathEntryResolveInfo getResolveInfo(ICProject cproject, boolean useCache) throws CModelException{ PathEntryResolveInfo info = resolvedInfoMap.get(cproject); if (info == null && useCache){ getResolvedPathEntries(cproject); info = resolvedInfoMap.get(cproject); } if (info == null || !useCache || !getResolveInfoValidState(cproject)){ Object[] resolved = getResolvedPathEntries(cproject, false, false); if (resolved != null) info = (PathEntryResolveInfo)resolved[1]; } return info; } private void setResolveInfoValidState(ICProject cproject, boolean valid){ Object v = valid ? null : Boolean.FALSE; resolveInfoValidState.set(cproject, v); } private boolean getResolveInfoValidState(ICProject cproject){ return resolveInfoValidState.get(cproject) == null; } protected IPathEntry[] removeCachedResolvedPathEntries(ICProject cproject) { ArrayList<IPathEntry> resolvedListEntries = resolvedMap.remove(cproject); resolvedInfoMap.remove(cproject); if (resolvedListEntries != null) { try { return getCachedResolvedPathEntries(resolvedListEntries, cproject); } catch (CModelException e) { // } } return null; } private IPathEntry[] getCachedResolvedPathEntries(ArrayList<IPathEntry> resolvedListEntries, ICProject cproject) throws CModelException { IPathEntry[] entries = resolvedListEntries.toArray(NO_PATHENTRIES); boolean hasContainerExtension = false; for (IPathEntry entry : entries) { if (entry.getEntryKind() == IPathEntry.CDT_CONTAINER) { IContainerEntry centry = (IContainerEntry)entry; IPathEntryContainer container = getPathEntryContainer(centry, cproject); if (container instanceof IPathEntryContainerExtension) { hasContainerExtension = true; break; } } } if (hasContainerExtension) { IPath projectPath = cproject.getPath(); ArrayList<IPathEntry> listEntries = new ArrayList<IPathEntry>(entries.length); for (int i = 0; i < entries.length; ++i) { if (entries[i].getEntryKind() == IPathEntry.CDT_CONTAINER) { IContainerEntry centry = (IContainerEntry)entries[i]; IPathEntryContainer container = getPathEntryContainer(centry, cproject); if (container != null) { IPathEntry[] containerEntries = container.getPathEntries(); if (containerEntries != null) { for (IPathEntry containerEntry : containerEntries) { IPathEntry newEntry = PathEntryUtil.cloneEntryAndExpand(projectPath, containerEntry); listEntries.add(newEntry); } } } } else { listEntries.add(entries[i]); } } entries = listEntries.toArray(NO_PATHENTRIES); } return entries; } public IPathEntry[] getResolvedPathEntries(ICProject cproject) throws CModelException { boolean treeLock = cproject.getProject().getWorkspace().isTreeLocked(); ArrayList<IPathEntry> resolvedListEntries = getResolvedPathEntries(cproject, !treeLock); return getCachedResolvedPathEntries(resolvedListEntries, cproject); } /** * This method will not expand container extending IPathEntryContainerExtension * * @param cproject * @param generateMarkers * @return * @throws CModelException */ @SuppressWarnings("unchecked") private ArrayList<IPathEntry> getResolvedPathEntries(ICProject cproject, boolean generateMarkers) throws CModelException { Object[] result = getResolvedPathEntries(cproject, generateMarkers, true); if (result != null) return (ArrayList<IPathEntry>) result[0]; return null; } private Object[] getResolvedPathEntries(ICProject cproject, boolean generateMarkers, boolean useCache) throws CModelException { ArrayList<IPathEntry> resolvedEntries = null; PathEntryResolveInfo rInfo = null; if (useCache){ resolvedEntries = resolvedMap.get(cproject); rInfo = resolvedInfoMap.get(cproject); } if (resolvedEntries == null) { List<PathEntryResolveInfoElement> resolveInfoList = new ArrayList<PathEntryResolveInfoElement>(); IPath projectPath = cproject.getPath(); IPathEntry[] rawEntries = getRawPathEntries(cproject); resolvedEntries = new ArrayList<IPathEntry>(); for (IPathEntry entry : rawEntries) { // Expand the containers. if (entry.getEntryKind() == IPathEntry.CDT_CONTAINER) { IContainerEntry centry = (IContainerEntry)entry; IPathEntryContainer container = getPathEntryContainer(centry, cproject); if (container != null) { // For backward compatibility we need to expand and cache container that // are not IPathEntryContainerExtension. if (!(container instanceof IPathEntryContainerExtension)) { IPathEntry[] containerEntries = container.getPathEntries(); List<IPathEntry> resolvedList = new ArrayList<IPathEntry>(); if (containerEntries != null) { for (IPathEntry containerEntry : containerEntries) { IPathEntry newEntry = PathEntryUtil.cloneEntryAndExpand(projectPath, containerEntry); resolvedEntries.add(newEntry); resolvedList.add(newEntry); } } resolveInfoList.add(new PathEntryResolveInfoElement(centry, resolvedList)); } else { IPathEntry resolved = PathEntryUtil.cloneEntryAndExpand(projectPath, entry); resolvedEntries.add(resolved); resolveInfoList.add(new PathEntryResolveInfoElement(entry, resolved)); } } } else { IPathEntry clone = PathEntryUtil.cloneEntryAndExpand(projectPath, entry); IPathEntry e = PathEntryUtil.getExpandedPathEntry(clone, cproject); if (e != null) { resolvedEntries.add(e); } resolveInfoList.add(new PathEntryResolveInfoElement(entry, e)); } } resolvedEntries.trimToSize(); if (generateMarkers) { IPathEntry[] finalEntries = resolvedEntries.toArray(NO_PATHENTRIES); ArrayList<ICModelStatus> problemList = new ArrayList<ICModelStatus>(); ICModelStatus status = validatePathEntry(cproject, finalEntries); if (!status.isOK()) { problemList.add(status); } for (IPathEntry finalEntry : finalEntries) { status = PathEntryUtil.validatePathEntry(cproject, finalEntry, true, false); if (!status.isOK()) { problemList.add(status); } } ICModelStatus[] problems = new ICModelStatus[problemList.size()]; problemList.toArray(problems); IProject project = cproject.getProject(); if (PathEntryUtil.hasPathEntryProblemMarkersChange(project, problems)) { addProblemMarkers(project, problems); } } // Check for duplication in the sources List<IPathEntry> dups = PathEntryUtil.checkForDuplication(resolvedEntries, IPathEntry.CDT_SOURCE); if (dups.size() > 0) { resolvedEntries.removeAll(dups); } // Check for duplication in the outputs dups = PathEntryUtil.checkForDuplication(resolvedEntries, IPathEntry.CDT_OUTPUT); if (dups.size() > 0) { resolvedEntries.removeAll(dups); } rInfo = new PathEntryResolveInfo(resolveInfoList); if (useCache){ resolvedMap.put(cproject, resolvedEntries); resolvedInfoMap.put(cproject, rInfo); } } return new Object[] { resolvedEntries, rInfo }; } public void setRawPathEntries(ICProject cproject, IPathEntry[] newEntries, IProgressMonitor monitor) throws CModelException { try { IPathEntry[] oldResolvedEntries = getCachedResolvedPathEntries(cproject); SetPathEntriesOperation op = new SetPathEntriesOperation(cproject, oldResolvedEntries, newEntries); op.runOperation(monitor); } catch (CoreException e) { throw new CModelException(e); } } public IPathEntry[] getRawPathEntries(ICProject cproject) throws CModelException { IProject project = cproject.getProject(); // Check if the Project is accessible. if (!CoreModel.hasCNature(project) && !CoreModel.hasCCNature(project)) { throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST)); } IPathEntry[] pathEntries; try { IPathEntryStore store = getPathEntryStore(project, true); pathEntries = store.getRawPathEntries(); } catch (CoreException e) { throw new CModelException(e); } // Checks/hacks for backward compatibility .. // if no output is specified we return the project // if no source is specified we return the project boolean foundSource = false; boolean foundOutput = false; for (IPathEntry rawEntry : pathEntries) { switch (rawEntry.getEntryKind()) { case IPathEntry.CDT_SOURCE: foundSource = true; break; case IPathEntry.CDT_OUTPUT: foundOutput = true; break; } } if (!foundSource) { IPathEntry[] newEntries = new IPathEntry[pathEntries.length + 1]; System.arraycopy(pathEntries, 0, newEntries, 0, pathEntries.length); newEntries[pathEntries.length] = CoreModel.newSourceEntry(cproject.getPath()); pathEntries = newEntries; } if (!foundOutput) { IPathEntry[] newEntries = new IPathEntry[pathEntries.length + 1]; System.arraycopy(pathEntries, 0, newEntries, 0, pathEntries.length); newEntries[pathEntries.length] = CoreModel.newOutputEntry(cproject.getPath()); pathEntries = newEntries; } return pathEntries; } public void setPathEntryContainer(ICProject[] affectedProjects, IPathEntryContainer newContainer, IProgressMonitor monitor) throws CModelException { SetPathEntryContainerOperation op = new SetPathEntryContainerOperation(affectedProjects, newContainer); op.runOperation(monitor); } public void clearPathEntryContainer(ICProject[] affectedProjects, IPath containerPath , IProgressMonitor monitor) throws CModelException { SetPathEntryContainerOperation op = new SetPathEntryContainerOperation(affectedProjects, containerPath); op.runOperation(monitor); } public synchronized IPathEntryContainer[] getPathEntryContainers(ICProject cproject) { IPathEntryContainer[] pcs = NO_PATHENTRYCONTAINERS; Map<IPath, IPathEntryContainer> projectContainers = Containers.get(cproject); if (projectContainers != null) { Collection<IPathEntryContainer> collection = projectContainers.values(); pcs= collection.toArray(NO_PATHENTRYCONTAINERS); } return pcs; } public IPathEntryContainer getPathEntryContainer(IContainerEntry entry, ICProject cproject) throws CModelException { return getPathEntryContainer(entry.getPath(), cproject); } public IPathEntryContainer getPathEntryContainer(final IPath containerPath, final ICProject project) throws CModelException { // Try the cache. IPathEntryContainer container = containerGet(project, containerPath, true); if (container instanceof PathEntryContainerLock) { boolean runInitializer = false; PathEntryContainerLock lock = (PathEntryContainerLock)container; synchronized (lock) { if (!lock.isContainerInitialize()) { runInitializer = true; lock.setContainerInitialize(runInitializer); } else if (! Thread.holdsLock(lock)){ // FIXME: Use Thread.holdsLock(lock) to break the cycle. // This seem to happend when the container(say the auto discovery) // trigger a resource change, the CoreModel will try to get the pathentries .. deadlock. // Wait for the inialization to finish. while (containerGet(project, containerPath, true) instanceof PathEntryContainerLock) { try { lock.wait(); } catch (InterruptedException e) { //e.printStackTrace(); } } } } if (runInitializer) { // remove the lock. final PathEntryContainerInitializer initializer = getPathEntryContainerInitializer(containerPath.segment(0)); final boolean[] ok = {false}; if (initializer != null) { // wrap initializer call with Safe runnable in case // initializer would be // causing some grief SafeRunner.run(new ISafeRunnable() { public void handleException(Throwable exception) { IStatus status = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, "Exception occurred in container initializer: " + initializer, exception); //$NON-NLS-1$ CCorePlugin.log(status); } public void run() throws Exception { initializer.initialize(containerPath, project); ok[0] = true; } }); } if (!ok[0]) { containerPut(project, containerPath, null); // flush and // notify } } // retrieve new value container = containerGet(project, containerPath, false); } return container; } /** * Helper method finding the container initializer registered for a given * container ID or <code>null</code> if none was found while iterating * over the contributions to extension point to the extension point * "org.eclipse.cdt.core.PathEntryContainerInitializer". * <p> * A containerID is the first segment of any container path, used to * identify the registered container initializer. * <p> * * @param containerID - * a containerID identifying a registered initializer * @return PathEntryContainerInitializer - the registered container * initializer or <code>null</code> if none was found. */ public PathEntryContainerInitializer getPathEntryContainerInitializer(String containerID) { Plugin core = CCorePlugin.getDefault(); if (core == null) { return null; } IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(CCorePlugin.PLUGIN_ID, CONTAINER_INITIALIZER_EXTPOINT_ID); if (extension != null) { IExtension[] extensions = extension.getExtensions(); for (IExtension extension2 : extensions) { IConfigurationElement[] configElements = extension2.getConfigurationElements(); for (IConfigurationElement configElement : configElements) { String initializerID = configElement.getAttribute("id"); //$NON-NLS-1$ if (initializerID != null && initializerID.equals(containerID)) { try { Object execExt = configElement.createExecutableExtension("class"); //$NON-NLS-1$ if (execExt instanceof PathEntryContainerInitializer) { return (PathEntryContainerInitializer)execExt; } } catch (CoreException e) { // executable extension could not be created: // ignore this initializer if //e.printStackTrace(); } } } } } return null; } synchronized IPathEntryContainer containerGet(ICProject cproject, IPath containerPath, boolean bCreateLock) { Map<IPath, IPathEntryContainer> projectContainers = Containers.get(cproject); if (projectContainers == null) { projectContainers = new HashMap<IPath, IPathEntryContainer>(); Containers.put(cproject, projectContainers); } IPathEntryContainer container = projectContainers.get(containerPath); // Initialize the first time with a lock if (bCreateLock && container == null) { container = new PathEntryContainerLock(); projectContainers.put(containerPath, container); } return container; } synchronized void containerPut(ICProject cproject, IPath containerPath, IPathEntryContainer container) { Map<IPath, IPathEntryContainer> projectContainers = Containers.get(cproject); if (projectContainers == null) { projectContainers = new HashMap<IPath, IPathEntryContainer>(); Containers.put(cproject, projectContainers); } IPathEntryContainer oldContainer; if (container == null) { oldContainer = projectContainers.remove(containerPath); } else { oldContainer = projectContainers.put(containerPath, container); } if (oldContainer instanceof PathEntryContainerLock) { synchronized (oldContainer) { oldContainer.notifyAll(); } } } synchronized void containerRemove(ICProject cproject) { Containers.remove(cproject); } public void pathEntryContainerUpdates(IPathEntryContainerExtension container, PathEntryContainerChanged[] events, IProgressMonitor monitor) { PathEntryContainerUpdatesOperation op = new PathEntryContainerUpdatesOperation(container, events); try { op.runOperation(monitor); } catch (CModelException e) { // } } public String[] projectPrerequisites(IPathEntry[] entries) throws CModelException { if (entries != null) { ArrayList<String> prerequisites = new ArrayList<String>(); for (IPathEntry entry : entries) { if (entry.getEntryKind() == IPathEntry.CDT_PROJECT) { IProjectEntry projectEntry = (IProjectEntry) entry; prerequisites.add(projectEntry.getPath().lastSegment()); } } int size = prerequisites.size(); if (size != 0) { String[] result = new String[size]; prerequisites.toArray(result); return result; } } return NO_PREREQUISITES; } public void saveRawPathEntries(ICProject cproject, IPathEntry[] entries) throws CModelException { // sanity if (entries == null) { entries = NO_PATHENTRIES; } ArrayList<IPathEntry> list = new ArrayList<IPathEntry>(entries.length); IPath projectPath = cproject.getPath(); for (IPathEntry pathEntry : entries) { int kind = pathEntry.getEntryKind(); // translate the project prefix. IPath resourcePath = pathEntry.getPath(); if (resourcePath == null) { resourcePath = Path.EMPTY; } // Do not do this for container, the path is the ID. if (kind != IPathEntry.CDT_CONTAINER) { // translate to project relative from absolute (unless a device // path) if (resourcePath.isAbsolute()) { if (projectPath != null && projectPath.isPrefixOf(resourcePath)) { if (resourcePath.segment(0).equals(projectPath.segment(0))) { resourcePath = resourcePath.removeFirstSegments(1); resourcePath = resourcePath.makeRelative(); } else { resourcePath = resourcePath.makeAbsolute(); } } } } // Specifics to the entries IPathEntry entry; switch (kind) { case IPathEntry.CDT_INCLUDE: { IIncludeEntry include = (IIncludeEntry)pathEntry; IPath baseRef = include.getBaseReference(); if (baseRef == null || baseRef.isEmpty()) { entry = CoreModel.newIncludeEntry(resourcePath, include.getBasePath(), include.getIncludePath(), include.isSystemInclude(), include.getExclusionPatterns(), include.isExported()); } else { entry = CoreModel.newIncludeRefEntry(resourcePath, baseRef, include.getIncludePath()); } break; } case IPathEntry.CDT_INCLUDE_FILE: { IIncludeFileEntry includeFile = (IIncludeFileEntry)pathEntry; entry = CoreModel.newIncludeFileEntry(resourcePath, includeFile.getBasePath(), includeFile.getBaseReference(), includeFile.getIncludeFilePath(), includeFile.getExclusionPatterns(), includeFile.isExported()); break; } case IPathEntry.CDT_LIBRARY: { ILibraryEntry library = (ILibraryEntry)pathEntry; IPath sourcePath = library.getSourceAttachmentPath(); if (sourcePath != null) { // translate to project relative from absolute if (projectPath != null && projectPath.isPrefixOf(sourcePath)) { if (sourcePath.segment(0).equals(projectPath.segment(0))) { sourcePath = sourcePath.removeFirstSegments(1); sourcePath = sourcePath.makeRelative(); } } } IPath baseRef = library.getBaseReference(); if (baseRef == null || baseRef.isEmpty()) { entry = CoreModel.newLibraryEntry(resourcePath, library.getBasePath(), library.getLibraryPath(), sourcePath, library.getSourceAttachmentRootPath(), library.getSourceAttachmentPrefixMapping(), library.isExported()); } else { entry = CoreModel.newLibraryRefEntry(resourcePath, baseRef, library.getLibraryPath()); } break; } case IPathEntry.CDT_MACRO: { IMacroEntry macro = (IMacroEntry)pathEntry; IPath baseRef = macro.getBaseReference(); if (baseRef == null || baseRef.isEmpty()) { entry = CoreModel.newMacroEntry(resourcePath, macro.getMacroName(), macro.getMacroValue(), macro.getExclusionPatterns(), macro.isExported()); } else { entry = CoreModel.newMacroRefEntry(resourcePath, baseRef, macro.getMacroName()); } break; } case IPathEntry.CDT_MACRO_FILE: { IMacroFileEntry macro = (IMacroFileEntry)pathEntry; entry = CoreModel.newMacroFileEntry(resourcePath, macro.getBasePath(), macro.getBaseReference(), macro.getMacroFilePath(), macro.getExclusionPatterns(), macro.isExported()); break; } case IPathEntry.CDT_OUTPUT: { IOutputEntry out = (IOutputEntry)pathEntry; entry = CoreModel.newOutputEntry(resourcePath, out.getExclusionPatterns()); break; } case IPathEntry.CDT_PROJECT: { IProjectEntry projEntry = (IProjectEntry)pathEntry; entry = CoreModel.newProjectEntry(projEntry.getPath(), projEntry.isExported()); break; } case IPathEntry.CDT_SOURCE: { ISourceEntry source = (ISourceEntry)pathEntry; entry = CoreModel.newSourceEntry(resourcePath, source.getExclusionPatterns()); break; } case IPathEntry.CDT_CONTAINER: entry = CoreModel.newContainerEntry(pathEntry.getPath(), pathEntry.isExported()); break; default: entry = pathEntry; } list.add(entry); } try { IPathEntry[] newRawEntries = new IPathEntry[list.size()]; list.toArray(newRawEntries); IProject project = cproject.getProject(); IPathEntryStore store = getPathEntryStore(project, true); setResolveInfoValidState(cproject, false); store.setRawPathEntries(newRawEntries); setResolveInfoValidState(cproject, true); } catch (CoreException e) { throw new CModelException(e); } } /** * Collects path entry errors for each project and generate error markers for these errors * @param project - Project with path entry errors * @param problems - The path entry errors associated with the project */ public void addProblemMarkers(final IProject project, final ICModelStatus[] problems) { PathEntryProblem problem = new PathEntryProblem(project, problems); //queue up the problems to be logged markerProblems.add(problem); //generate the error markers markerTask.schedule(); } private class GenerateMarkersJob extends WorkspaceJob { public GenerateMarkersJob(String name) { super(name); } @Override public IStatus runInWorkspace(IProgressMonitor monitor) { while (markerProblems.peek() != null && !monitor.isCanceled()) { PathEntryProblem problem = markerProblems.poll(); IProject project = problem.project; ICModelStatus[] problems = problem.problems; PathEntryUtil.flushPathEntryProblemMarkers(project); for (int i = 0; i < problems.length; ++i) { PathEntryUtil.createPathEntryProblemMarker(project, problems[i]); } } return Status.OK_STATUS; } } private boolean needDelta(ICProject cproject){ try { PathEntryStoreProxy store = (PathEntryStoreProxy)getPathEntryStore(cproject.getProject(), false); return store == null || !(store.getStore() instanceof ConfigBasedPathEntryStore); } catch (CoreException e) { } return false; } public ICElementDelta[] generatePathEntryDeltas(ICProject cproject, IPathEntry[] oldEntries, IPathEntry[] newEntries) { if (!needDelta(cproject)) return new ICElementDelta[0]; ArrayList<ICElementDelta> list = new ArrayList<ICElementDelta>(); // if nothing was known before do not generate any deltas. if (oldEntries == null) { return new ICElementDelta[0]; } // Sanity checks if (newEntries == null) { newEntries = NO_PATHENTRIES; } // Check the removed entries. for (IPathEntry oldEntry : oldEntries) { boolean found = false; for (IPathEntry newEntrie : newEntries) { if (oldEntry.equals(newEntrie)) { found = true; break; } } // Was it deleted. if (!found) { ICElementDelta delta = makePathEntryDelta(cproject, oldEntry, true); if (delta != null) { list.add(delta); } } } // Check the new entries. for (IPathEntry newEntry : newEntries) { boolean found = false; for (IPathEntry oldEntry : oldEntries) { if (newEntry.equals(oldEntry)) { found = true; break; } } // is it new? if (!found) { ICElementDelta delta = makePathEntryDelta(cproject, newEntry, false); if (delta != null) { list.add(delta); } } } // Check for reorder if (list.size() == 0 && oldEntries.length == newEntries.length) { for (int i = 0; i < newEntries.length; i++) { if (!newEntries[i].equals(oldEntries[i])) { ICElementDelta delta = makePathEntryDelta(cproject, null, false); if (delta != null) { list.add(delta); } } } } // They may have remove some duplications, catch here .. consider it as reordering. if (list.size() == 0 && oldEntries.length != newEntries.length) { ICElementDelta delta = makePathEntryDelta(cproject, null, true); if (delta != null) { list.add(delta); } } ICElementDelta[] deltas = new ICElementDelta[list.size()]; list.toArray(deltas); return deltas; } /** * return a delta, with the specified change flag. */ protected ICElementDelta makePathEntryDelta(ICProject cproject, IPathEntry entry, boolean removed) { ICElement celement = null; int flag = ICElementDelta.F_PATHENTRY_REORDER; if (entry == null) { celement = cproject; flag = ICElementDelta.F_PATHENTRY_REORDER; } else { int kind = entry.getEntryKind(); switch (kind) { case IPathEntry.CDT_SOURCE: { ISourceEntry source = (ISourceEntry)entry; IPath path = source.getPath(); celement = CoreModel.getDefault().create(path); flag = (removed) ? ICElementDelta.F_REMOVED_PATHENTRY_SOURCE : ICElementDelta.F_ADDED_PATHENTRY_SOURCE; break; } case IPathEntry.CDT_LIBRARY: { celement = cproject; flag = (removed) ? ICElementDelta.F_REMOVED_PATHENTRY_LIBRARY : ICElementDelta.F_ADDED_PATHENTRY_LIBRARY; break; } case IPathEntry.CDT_PROJECT: { //IProjectEntry pentry = (IProjectEntry) entry; celement = cproject; flag = ICElementDelta.F_CHANGED_PATHENTRY_PROJECT; break; } case IPathEntry.CDT_INCLUDE: { IIncludeEntry include = (IIncludeEntry)entry; IPath path = include.getPath(); celement = CoreModel.getDefault().create(path); flag = ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE; break; } case IPathEntry.CDT_INCLUDE_FILE: { IIncludeFileEntry includeFile = (IIncludeFileEntry)entry; IPath path = includeFile.getPath(); celement = CoreModel.getDefault().create(path); flag = ICElementDelta.F_CHANGED_PATHENTRY_INCLUDE; break; } case IPathEntry.CDT_MACRO: { IMacroEntry macro = (IMacroEntry)entry; IPath path = macro.getPath(); celement = CoreModel.getDefault().create(path); flag = ICElementDelta.F_CHANGED_PATHENTRY_MACRO; break; } case IPathEntry.CDT_MACRO_FILE: { IMacroFileEntry macro = (IMacroFileEntry)entry; IPath path = macro.getPath(); celement = CoreModel.getDefault().create(path); flag = ICElementDelta.F_CHANGED_PATHENTRY_MACRO; break; } case IPathEntry.CDT_CONTAINER: { //IContainerEntry container = (IContainerEntry) entry; //celement = cproject; //SHOULD NOT BE HERE Container are resolved. break; } } } if (celement == null) { celement = cproject; } CElementDelta delta = new CElementDelta(cproject.getCModel()); delta.changed(celement, flag); return delta; } static String[] getRegisteredContainerIDs() { Plugin core = CCorePlugin.getDefault(); if (core == null) { return null; } ArrayList<String> containerIDList = new ArrayList<String>(5); IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(CCorePlugin.PLUGIN_ID, CONTAINER_INITIALIZER_EXTPOINT_ID); if (extension != null) { IExtension[] extensions = extension.getExtensions(); for (IExtension extension2 : extensions) { IConfigurationElement[] configElements = extension2.getConfigurationElements(); for (IConfigurationElement configElement : configElements) { String idAttribute = configElement.getAttribute("id"); //$NON-NLS-1$ if (idAttribute != null) containerIDList.add(idAttribute); } } } String[] containerIDs = new String[containerIDList.size()]; containerIDList.toArray(containerIDs); return containerIDs; } public void setPathEntryStore(IProject project, IPathEntryStore newStore) { IPathEntryStore oldStore = null; synchronized (storeMap) { oldStore = storeMap.remove(project); if (newStore != null) { storeMap.put(project, newStore); } } if (oldStore != null) { // remove are self before closing oldStore.removePathEntryStoreListener(this); oldStore.close(); } } public IPathEntryStore getPathEntryStore(IProject project, boolean create) throws CoreException { synchronized (storeMap){ IPathEntryStore store = storeMap.get(project); if (store == null) { if (create == true){ store = createPathEntryStore(project); storeMap.put(project, store); store.addPathEntryStoreListener(this); } } else if (store instanceof AbstractCExtensionProxy){ ((AbstractCExtensionProxy)store).updateProject(project); } return store; } } public IPathEntryStore createPathEntryStore(IProject project) throws CoreException { return new PathEntryStoreProxy(project); // IPathEntryStore store = null; // if (project != null) { // try { // ICDescriptor cdesc = CCorePlugin.getDefault().getCProjectDescription(project, false); // if (cdesc != null) { // ICExtensionReference[] cextensions = cdesc.get(PATHENTRY_STORE_UNIQ_ID, true); // if (cextensions.length > 0) { // for (int i = 0; i < cextensions.length; i++) { // try { // store = (IPathEntryStore)cextensions[i].createExtension(); // break; // } catch (ClassCastException e) { // // // CCorePlugin.log(e); // } // } // } // } // } catch (CoreException e) { // // ignore since we fall back to a default.... // } // } // if (store == null) { // store = createDefaultStore(project); // } // return store; } // private IPathEntryStore createDefaultStore(IProject project){ // if (CProjectDescriptionManager.getInstance().isNewStyleIndexCfg(project)){ // return new ConfigBasedPathEntryStore(project); // } // return new DefaultPathEntryStore(project); // } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.resources.IPathEntryStoreListener#pathEntryStoreChanged(org.eclipse.cdt.core.resources.PathEntryChangedEvent) */ public void pathEntryStoreChanged(PathEntryStoreChangedEvent event) { IProject project = event.getProject(); // sanity if (project == null) { return; } CModelManager manager = CModelManager.getDefault(); final ICProject cproject = manager.create(project); if (event.hasClosed()) { setPathEntryStore(project, null); containerRemove(cproject); } if (project.isAccessible()) { try { CModelOperation op = new PathEntryStoreChangedOperation(cproject); op.runOperation(null); } catch (CModelException e) { CCorePlugin.log(e); } } else { resolvedMap.remove(cproject); resolvedInfoMap.remove(cproject); containerRemove(cproject); } } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.model.IElementChangedListener#elementChanged(org.eclipse.cdt.core.model.ElementChangedEvent) */ public void elementChanged(ElementChangedEvent event) { try { if (processDelta(event.getDelta()) == true) { ICProject[] cProjects = resolvedMap.keySet().toArray(new ICProject[0]); for (ICProject project2 : cProjects) { IPathEntry[] entries = getCachedResolvedPathEntries(project2); if (entries != null) { IProject project = project2.getProject(); try { IMarker[] markers = project.findMarkers(ICModelMarker.PATHENTRY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); if (markers != null && markers.length > 0) { ArrayList<ICModelStatus> problemList = new ArrayList<ICModelStatus>(); for (IPathEntry entry : entries) { ICModelStatus status = PathEntryUtil.validatePathEntry(project2, entry, true, false); if (!status.isOK()) { problemList.add(status); } } ICModelStatus[] problems = new ICModelStatus[problemList.size()]; problemList.toArray(problems); if (PathEntryUtil.hasPathEntryProblemMarkersChange(project, problems)) { addProblemMarkers(project, problems); } } } catch (CoreException e) { // ignore the exception. } } } } } catch (CModelException e) { } } protected boolean processDelta(ICElementDelta delta) throws CModelException { int kind = delta.getKind(); ICElement element = delta.getElement(); int type = element.getElementType(); // handle open, closing and removing of projects if ( type == ICElement.C_PROJECT) { ICProject cproject = (ICProject)element; if ((kind == ICElementDelta.REMOVED || kind == ICElementDelta.ADDED)) { if (kind == ICElementDelta.REMOVED) { IProject project = cproject.getProject(); IPathEntryStore store = null; try { store = getPathEntryStore(project, false); if (store != null) { store.close(); } } catch (CoreException e) { throw new CModelException(e); } finally { if (store == null) { resolvedMap.remove(cproject); resolvedInfoMap.remove(cproject); containerRemove(cproject); } } } return true; } // project change, traverse children. } if (element instanceof IWorkingCopy) { return false; } if (kind == ICElementDelta.ADDED || kind == ICElementDelta.REMOVED) { // If the element path maps to the some IPathEntry we need to remove that entry // but I'm not sure of the side effects so lets just do this for the ISourceEntry type if (element instanceof ISourceRoot) { ISourceRoot sourceRoot = (ISourceRoot)element; if (kind == ICElementDelta.REMOVED) { updatePathEntryFromDeleteSource(sourceRoot); } } return true; // add/remove we validate all paths } if (type == ICElement.C_MODEL || type == ICElement.C_CCONTAINER || type == ICElement.C_PROJECT) { ICElementDelta[] affectedChildren = delta.getAffectedChildren(); boolean result = false; for (ICElementDelta element2 : affectedChildren) { if (processDelta(element2)) { result = true; } } return result; } return false; } /** * The source root been deleted update the path entries * @param sourceRoot * @throws CModelException */ void updatePathEntryFromDeleteSource(final ISourceRoot sourceRoot) throws CModelException { final ICProject cproject = sourceRoot.getCProject(); IPathEntry[] rawEntries = getRawPathEntries(cproject); boolean change = false; ArrayList<IPathEntry> list = new ArrayList<IPathEntry>(rawEntries.length); for (int i = 0; i < rawEntries.length; ++i) { if (rawEntries[i].getEntryKind() == IPathEntry.CDT_SOURCE) { if (sourceRoot.getPath().equals(rawEntries[i].getPath())) { change = true; } else { list.add(rawEntries[i]); } } else { list.add(rawEntries[i]); } } if (change) { IPathEntry[] newEntries = new IPathEntry[list.size()]; list.toArray(newEntries); final IPathEntry[] finalEntries = newEntries; Job updatePathEntry = new WorkspaceJob("PathEntry Update source roots") { //$NON-NLS-1$ @Override public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { // If the path which triggered this change exists when we run this job then nothing to do if (sourceRoot.getResource() == null || !sourceRoot.getResource().exists()) setRawPathEntries(cproject, finalEntries, monitor); return Status.OK_STATUS; } }; IProject project = cproject.getProject(); ISchedulingRule rule = project.getWorkspace().getRoot(); updatePathEntry.setRule(rule); updatePathEntry.schedule(); } } public ICModelStatus validatePathEntry(ICProject cProject, IPathEntry[] entries) { return PathEntryUtil.validatePathEntry(cProject, entries); } public ICModelStatus validatePathEntry(ICProject cProject, IPathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers) { return PathEntryUtil.validatePathEntry(cProject, entry, checkSourceAttachment, recurseInContainers); } }