1
/*******************************************************************************
2
* Copyright (c) 2000, 2011 QNX Software Systems and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* QNX Software Systems - Initial API and implementation
10
* Anton Leherbauer (Wind River Systems)
11
*******************************************************************************/
12
package org.eclipse.cdt.internal.core.model;
15
import java.io.IOException;
16
import java.util.ArrayList;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.Iterator;
20
import java.util.List;
23
import org.eclipse.cdt.core.CCProjectNature;
24
import org.eclipse.cdt.core.CCorePlugin;
25
import org.eclipse.cdt.core.CProjectNature;
26
import org.eclipse.cdt.core.IBinaryParser;
27
import org.eclipse.cdt.core.IBinaryParser.IBinaryArchive;
28
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
29
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
30
import org.eclipse.cdt.core.model.CModelException;
31
import org.eclipse.cdt.core.model.CoreModel;
32
import org.eclipse.cdt.core.model.CoreModelUtil;
33
import org.eclipse.cdt.core.model.IArchiveContainer;
34
import org.eclipse.cdt.core.model.IBinaryContainer;
35
import org.eclipse.cdt.core.model.ICContainer;
36
import org.eclipse.cdt.core.model.ICElement;
37
import org.eclipse.cdt.core.model.ICModelStatusConstants;
38
import org.eclipse.cdt.core.model.ICProject;
39
import org.eclipse.cdt.core.model.IIncludeEntry;
40
import org.eclipse.cdt.core.model.IIncludeReference;
41
import org.eclipse.cdt.core.model.ILibraryEntry;
42
import org.eclipse.cdt.core.model.ILibraryReference;
43
import org.eclipse.cdt.core.model.IOutputEntry;
44
import org.eclipse.cdt.core.model.IPathEntry;
45
import org.eclipse.cdt.core.model.ISourceEntry;
46
import org.eclipse.cdt.core.model.ISourceRoot;
47
import org.eclipse.cdt.core.settings.model.CSourceEntry;
48
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
49
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
50
import org.eclipse.cdt.core.settings.model.ICSourceEntry;
51
import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager;
52
import org.eclipse.cdt.internal.core.util.MementoTokenizer;
53
import org.eclipse.core.resources.IFile;
54
import org.eclipse.core.resources.IProject;
55
import org.eclipse.core.resources.IResource;
56
import org.eclipse.core.resources.ProjectScope;
57
import org.eclipse.core.runtime.CoreException;
58
import org.eclipse.core.runtime.IPath;
59
import org.eclipse.core.runtime.IProgressMonitor;
60
import org.eclipse.core.runtime.Path;
61
import org.eclipse.core.runtime.Preferences;
62
import org.eclipse.core.runtime.QualifiedName;
63
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
64
import org.eclipse.core.runtime.preferences.IScopeContext;
65
import org.osgi.service.prefs.BackingStoreException;
67
public class CProject extends Openable implements ICProject {
69
private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$
71
public CProject(ICElement parent, IProject project) {
72
super(parent, project, ICElement.C_PROJECT);
75
public IBinaryContainer getBinaryContainer() throws CModelException {
76
return ((CProjectInfo) getElementInfo()).getBinaryContainer();
79
public IArchiveContainer getArchiveContainer() throws CModelException {
80
return ((CProjectInfo) getElementInfo()).getArchiveContainer();
83
public IProject getProject() {
84
return getUnderlyingResource().getProject();
87
public ICElement findElement(IPath path) throws CModelException {
88
ICElement celem = null;
89
if (path.isAbsolute()) {
90
celem = CModelManager.getDefault().create(path);
92
IProject project = getProject();
93
if (project != null) {
94
IPath p = project.getFullPath().append(path);
95
celem = CModelManager.getDefault().create(p);
99
CModelStatus status = new CModelStatus(ICModelStatusConstants.INVALID_PATH, path);
100
throw new CModelException(status);
105
public static boolean hasCNature(IProject p) {
107
return p.hasNature(CProjectNature.C_NATURE_ID);
108
} catch (CoreException e) {
109
//throws exception if the project is not open.
114
public static boolean hasCCNature(IProject p) {
116
return p.hasNature(CCProjectNature.CC_NATURE_ID);
117
} catch (CoreException e) {
118
//throws exception if the project is not open.
123
private boolean isCProject() {
124
return hasCNature(getProject()) || hasCCNature(getProject());
128
* Returns true if this handle represents the same C project
129
* as the given handle. Two handles represent the same
130
* project if they are identical or if they represent a project with
131
* the same underlying resource and occurrence counts.
133
* @see CElement#equals(Object)
136
public boolean equals(Object o) {
141
if (!(o instanceof CProject))
144
CProject other = (CProject) o;
145
return getProject().equals(other.getProject());
149
protected CElementInfo createElementInfo() {
150
return new CProjectInfo(this);
153
// CHECKPOINT: CProjects will return the hash code of their underlying IProject
155
public int hashCode() {
156
return getProject().hashCode();
159
public IIncludeReference[] getIncludeReferences() throws CModelException {
160
CProjectInfo pinfo = (CProjectInfo)CModelManager.getDefault().peekAtInfo(this);
161
IIncludeReference[] incRefs = null;
163
incRefs = pinfo.incReferences;
165
if (incRefs == null) {
166
IPathEntry[] entries = getResolvedPathEntries();
167
ArrayList<IncludeReference> list = new ArrayList<IncludeReference>(entries.length);
168
for (IPathEntry entrie : entries) {
169
if (entrie.getEntryKind() == IPathEntry.CDT_INCLUDE) {
170
IIncludeEntry entry = (IIncludeEntry) entrie;
171
list.add(new IncludeReference(this, entry));
174
incRefs = list.toArray(new IIncludeReference[0]);
176
pinfo.incReferences = incRefs;
182
public ILibraryReference[] getLibraryReferences() throws CModelException {
183
CProjectInfo pinfo = (CProjectInfo)CModelManager.getDefault().peekAtInfo(this);
184
ILibraryReference[] libRefs = null;
186
libRefs = pinfo.libReferences;
189
if (libRefs == null) {
190
BinaryParserConfig[] binConfigs = CModelManager.getDefault().getBinaryParser(getProject());
191
IPathEntry[] entries = getResolvedPathEntries();
192
ArrayList<ILibraryReference> list = new ArrayList<ILibraryReference>(entries.length);
193
for (IPathEntry entrie : entries) {
194
if (entrie.getEntryKind() == IPathEntry.CDT_LIBRARY) {
195
ILibraryEntry entry = (ILibraryEntry) entrie;
196
ILibraryReference lib = getLibraryReference(this, binConfigs, entry);
202
libRefs = list.toArray(new ILibraryReference[0]);
204
pinfo.libReferences = libRefs;
210
private static ILibraryReference getLibraryReference(ICProject cproject, BinaryParserConfig[] binConfigs, ILibraryEntry entry) {
211
if (binConfigs == null) {
212
binConfigs = CModelManager.getDefault().getBinaryParser(cproject.getProject());
214
ILibraryReference lib = null;
215
if (binConfigs != null) {
216
for (BinaryParserConfig binConfig : binConfigs) {
219
IBinaryParser parser = binConfig.getBinaryParser();
220
bin = parser.getBinary(entry.getFullLibraryPath());
222
if (bin.getType() == IBinaryFile.ARCHIVE) {
223
lib = new LibraryReferenceArchive(cproject, entry, (IBinaryArchive)bin);
224
} else if (bin instanceof IBinaryObject){
225
lib = new LibraryReferenceShared(cproject, entry, (IBinaryObject)bin);
229
} catch (IOException e) {
230
} catch (CoreException e) {
235
lib = new LibraryReference(cproject, entry);
241
* @see ICProject#getRequiredProjectNames()
243
public String[] getRequiredProjectNames() throws CModelException {
244
return projectPrerequisites(getResolvedPathEntries());
247
public String[] projectPrerequisites(IPathEntry[] entries) throws CModelException {
248
return PathEntryManager.getDefault().projectPrerequisites(entries);
253
* @see org.eclipse.cdt.core.model.ICProject#getOption(String, boolean)
255
public String getOption(String optionName, boolean inheritCCoreOptions) {
256
if (CModelManager.OptionNames.contains(optionName)) {
257
IEclipsePreferences preferences = getPreferences();
258
final String cCoreDefault= inheritCCoreOptions ? CCorePlugin.getOption(optionName) : null;
259
if (preferences == null) {
262
String value= preferences.get(optionName, cCoreDefault).trim();
263
return value == null ? null : value.trim();
270
* @see org.eclipse.cdt.core.model.ICProject#getOptions(boolean)
272
public Map<String, String> getOptions(boolean inheritCCoreOptions) {
273
// initialize to the defaults from CCorePlugin options pool
274
Map<String, String> options= inheritCCoreOptions ? CCorePlugin.getOptions() : new HashMap<String, String>(5);
276
IEclipsePreferences preferences = getPreferences();
277
if (preferences == null)
279
HashSet<String> optionNames= CModelManager.OptionNames;
281
// create project options
283
String[] propertyNames= preferences.keys();
284
for (String propertyName : propertyNames) {
285
String value= preferences.get(propertyName, null);
286
if (value != null && optionNames.contains(propertyName)){
287
options.put(propertyName, value.trim());
290
} catch (BackingStoreException e) {
297
* @see org.eclipse.cdt.core.model.ICProject#setOption(java.lang.String, java.lang.String)
299
public void setOption(String optionName, String optionValue) {
300
if (!CModelManager.OptionNames.contains(optionName))
301
return; // unrecognized option
303
IEclipsePreferences projectPreferences= getPreferences();
304
if (optionValue == null) {
306
projectPreferences.remove(optionName);
308
projectPreferences.put(optionName, optionValue);
313
projectPreferences.flush();
314
} catch (BackingStoreException e) {
315
// problem with pref store - quietly ignore
320
* @see org.eclipse.cdt.core.model.ICProject#setOptions(Map)
322
public void setOptions(Map<String, String> newOptions) {
323
Preferences preferences = new Preferences();
324
setPreferences(preferences); // always reset (26255)
326
if (newOptions != null) {
327
for (Map.Entry<String, String> e : newOptions.entrySet()) {
328
String key = e.getKey();
329
if (!CModelManager.OptionNames.contains(key))
330
continue; // unrecognized option
332
// no filtering for encoding (custom encoding for project is allowed)
333
String value = e.getValue();
334
preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251)
335
preferences.setValue(key, value);
340
savePreferences(preferences);
344
* Returns the project custom preference pool.
345
* Project preferences may include custom encoding.
346
* @return IEclipsePreferences or <code>null</code> if the project
347
* does not have a C nature.
349
private IEclipsePreferences getPreferences() {
350
if (!(isCProject())) {
353
IScopeContext context= new ProjectScope(getProject());
354
final IEclipsePreferences preferences= context.getNode(CCorePlugin.PLUGIN_ID);
359
* Save project custom preferences to persistent properties
361
private void savePreferences(Preferences preferences) {
362
if (preferences == null)
367
Iterator<String> iter = CModelManager.OptionNames.iterator();
369
while (iter.hasNext()) {
370
String qualifiedName = iter.next();
371
String dequalifiedName = qualifiedName.substring(CCorePlugin.PLUGIN_ID.length() + 1);
375
value = preferences.getString(qualifiedName);
377
if (value != null && !value.equals(preferences.getDefaultString(qualifiedName))) {
378
resource.setPersistentProperty(new QualifiedName(CCorePlugin.PLUGIN_ID, dequalifiedName), value);
380
resource.setPersistentProperty(new QualifiedName(CCorePlugin.PLUGIN_ID, dequalifiedName), null);
382
} catch (CoreException e) {
388
* Set cached preferences, no preferences are saved, only info is updated
390
private void setPreferences(Preferences preferences) {
398
* @see org.eclipse.cdt.core.model.ICProject#getResolvedCPathEntries()
400
public IPathEntry[] getResolvedPathEntries() throws CModelException {
401
return CoreModel.getResolvedPathEntries(this);
405
* @see org.eclipse.cdt.core.model.ICProject#getRawCPathEntries()
407
public IPathEntry[] getRawPathEntries() throws CModelException {
408
return CoreModel.getRawPathEntries(this);
412
* @see org.eclipse.cdt.core.model.ICProject#setRawCPathEntries(org.eclipse.cdt.core.model.IPathEntry[], org.eclipse.core.runtime.IProgressMonitor)
414
public void setRawPathEntries(IPathEntry[] newEntries, IProgressMonitor monitor) throws CModelException {
415
CoreModel.setRawPathEntries(this, newEntries, monitor);
419
* @see org.eclipse.cdt.core.model.ICProject#getSourceRoot(org.eclipse.cdt.core.model.ISourceEntry)
421
public ISourceRoot getSourceRoot(ISourceEntry entry) throws CModelException {
422
return getSourceRoot(new CSourceEntry(entry.getPath(), entry.getExclusionPatterns(), 0));
425
public ISourceRoot getSourceRoot(ICSourceEntry entry) throws CModelException {
427
IPath sp = entry.getFullPath();
428
if (p.isPrefixOf(sp)) {
429
int count = sp.matchingFirstSegments(p);
430
sp = sp.removeFirstSegments(count);
431
IResource res = null;
435
res = getProject().findMember(sp);
438
return new SourceRoot(this, res, entry);
445
* @see org.eclipse.cdt.core.model.ICProject#findSourceRoot()
447
public ISourceRoot findSourceRoot(IResource res) {
449
ISourceRoot[] roots = getAllSourceRoots();
450
for (ISourceRoot root : roots) {
451
if (root.isOnSourceEntry(res)) {
455
} catch (CModelException e) {
461
* @see org.eclipse.cdt.core.model.ICProject#findSourceRoot()
463
public ISourceRoot findSourceRoot(IPath path) {
465
ISourceRoot[] roots = getAllSourceRoots();
466
for (ISourceRoot root : roots) {
467
if (root.getPath().equals(path)) {
471
} catch (CModelException e) {
477
* @see org.eclipse.cdt.core.model.ICProject#getSourceRoots()
479
public ISourceRoot[] getSourceRoots() throws CModelException {
480
Object[] children = getChildren();
481
ArrayList<ISourceRoot> result = new ArrayList<ISourceRoot>(children.length);
482
for (Object element : children) {
483
if (element instanceof ISourceRoot) {
484
result.add((ISourceRoot) element);
487
return result.toArray(new ISourceRoot[result.size()]);
491
* Get all source roots.
493
* @return all source roots
494
* @throws CModelException
496
public ISourceRoot[] getAllSourceRoots() throws CModelException {
497
CProjectInfo pinfo = (CProjectInfo)CModelManager.getDefault().peekAtInfo(this);
498
ISourceRoot[] roots = null;
500
if (pinfo.sourceRoots != null) {
501
roots = pinfo.sourceRoots;
503
List<ISourceRoot> list = computeSourceRoots();
504
roots = pinfo.sourceRoots = list.toArray(new ISourceRoot[list.size()]);
507
List<ISourceRoot> list = computeSourceRoots();
508
roots = list.toArray(new ISourceRoot[list.size()]);
513
public IOutputEntry[] getOutputEntries() throws CModelException {
514
CProjectInfo pinfo = (CProjectInfo) CModelManager.getDefault().peekAtInfo(this);
515
IOutputEntry[] outs = null;
517
if (pinfo.outputEntries != null) {
518
outs = pinfo.outputEntries;
520
IPathEntry[] entries = getResolvedPathEntries();
521
outs = pinfo.outputEntries = getOutputEntries(entries);
524
IPathEntry[] entries = getResolvedPathEntries();
525
outs = getOutputEntries(entries);
533
public IOutputEntry[] getOutputEntries(IPathEntry[] entries) throws CModelException {
534
ArrayList<IPathEntry> list = new ArrayList<IPathEntry>(entries.length);
535
for (IPathEntry entrie : entries) {
536
if (entrie.getEntryKind() == IPathEntry .CDT_OUTPUT) {
540
IOutputEntry[] outputs = new IOutputEntry[list.size()];
541
list.toArray(outputs);
548
public boolean isOnOutputEntry(IResource resource) {
549
IPath path = resource.getFullPath();
551
// ensure that folders are only excluded if all of their children are excluded
552
if (resource.getType() == IResource.FOLDER || resource.getType() == IResource.PROJECT) {
553
path = path.append("*"); //$NON-NLS-1$
557
IOutputEntry[] entries = getOutputEntries();
558
for (IOutputEntry entrie : entries) {
559
boolean on = isOnOutputEntry(entrie, path);
564
} catch (CModelException e) {
570
private boolean isOnOutputEntry(IOutputEntry entry, IPath path) {
571
if (entry.getPath().isPrefixOf(path) && !CoreModelUtil.isExcluded(path, entry.fullExclusionPatternChars())) {
578
* @see org.eclipse.cdt.internal.core.model.Openable#buildStructure(org.eclipse.cdt.internal.core.model.OpenableInfo, org.eclipse.core.runtime.IProgressMonitor, java.util.Map, org.eclipse.core.resources.IResource)
581
protected boolean buildStructure(OpenableInfo info, IProgressMonitor pm,
582
Map<ICElement, CElementInfo> newElements, IResource underlyingResource)
583
throws CModelException {
584
boolean validInfo = false;
586
IResource res = getResource();
587
if (res != null && res.isAccessible()) {
588
validInfo = computeChildren(info, res);
590
throw newNotPresentException();
594
CModelManager.getDefault().removeInfo(this);
600
protected List<ISourceRoot> computeSourceRoots() throws CModelException {
601
//IPathEntry[] entries = getResolvedPathEntries();
602
ICSourceEntry[] entries = null;
603
ICProjectDescription des = CProjectDescriptionManager.getInstance().getProjectDescription(getProject(), false);
605
ICConfigurationDescription cfg = des.getDefaultSettingConfiguration();
607
entries = cfg.getResolvedSourceEntries();
611
ArrayList<ISourceRoot> list = new ArrayList<ISourceRoot>(entries.length);
612
for (ICSourceEntry sourceEntry : entries) {
613
ISourceRoot root = getSourceRoot(sourceEntry);
620
return new ArrayList<ISourceRoot>(0);
623
protected boolean computeChildren(OpenableInfo info, IResource res) throws CModelException {
624
List<ISourceRoot> sourceRoots = computeSourceRoots();
625
List<ICContainer> children = new ArrayList<ICContainer>(sourceRoots.size());
626
children.addAll(sourceRoots);
628
boolean projectIsSourceRoot = false;
629
for (ISourceRoot sourceRoot : sourceRoots)
630
if (sourceRoot.getResource().equals(getProject())) {
631
projectIsSourceRoot = true;
635
// Now look for output folders
637
IResource[] resources = getProject().members();
638
for (IResource child : resources) {
639
if (child.getType() == IResource.FOLDER) {
640
boolean found = false;
641
for (ISourceRoot sourceRoot : sourceRoots) {
642
if (sourceRoot.isOnSourceEntry(child)) {
648
// Not in source folder, check if it's a container on output entry
649
// Also make sure I'm not a source root since my SourceRoot object would
650
// have already added this.
651
if (!found && isOnOutputEntry(child) && !projectIsSourceRoot)
652
children.add(new CContainer(this, child));
655
} catch (CoreException e) {
659
info.setChildren(children);
660
if (info instanceof CProjectInfo) {
661
CProjectInfo pinfo = (CProjectInfo)info;
662
pinfo.sourceRoots= sourceRoots.toArray(new ISourceRoot[sourceRoots.size()]);
663
pinfo.setNonCResources(null);
671
public boolean isOnSourceRoot(ICElement element) {
673
ISourceRoot[] roots = getSourceRoots();
674
for (ISourceRoot root : roots) {
675
if (root.isOnSourceEntry(element)) {
679
} catch (CModelException e) {
688
public boolean isOnSourceRoot(IResource resource) {
690
ISourceRoot[] roots = getSourceRoots();
691
for (ISourceRoot root : roots) {
692
if (root.isOnSourceEntry(resource)) {
696
} catch (CModelException e) {
703
* @see org.eclipse.cdt.core.model.ICElement#exists()
706
public boolean exists() {
714
* @see org.eclipse.cdt.core.model.ICProject#getNonCResources()
716
public Object[] getNonCResources() throws CModelException {
717
return ((CProjectInfo) getElementInfo()).getNonCResources(getResource());
721
* @see org.eclipse.cdt.internal.core.model.CElement#closing(java.lang.Object)
724
protected void closing(Object info) throws CModelException {
725
if (info instanceof CProjectInfo) {
726
CModelManager.getDefault().removeBinaryRunner(this);
727
CProjectInfo pinfo = (CProjectInfo)info;
728
if (pinfo.vBin != null) {
731
if (pinfo.vLib != null) {
740
* Resets this project's caches
742
public void resetCaches() {
743
CProjectInfo pinfo = (CProjectInfo) CModelManager.getDefault().peekAtInfo(this);
750
public ICElement getHandleFromMemento(String token, MementoTokenizer memento) {
751
switch (token.charAt(0)) {
753
IPath rootPath = Path.EMPTY;
755
while (memento.hasMoreTokens()) {
756
token = memento.nextToken();
757
char firstChar = token.charAt(0);
758
if (firstChar != CEM_SOURCEFOLDER && firstChar != CEM_TRANSLATIONUNIT) {
759
rootPath= rootPath.append(token);
765
if (!rootPath.isAbsolute()) {
766
rootPath= getProject().getFullPath().append(rootPath);
768
CElement root = (CElement)findSourceRoot(rootPath);
771
return root.getHandleFromMemento(token, memento);
773
return root.getHandleFromMemento(memento);
777
case CEM_TRANSLATIONUNIT:
778
if (!memento.hasMoreTokens()) return this;
779
String tuName = memento.nextToken();
780
final IPath path= Path.fromPortableString(tuName);
782
if (!path.isAbsolute()) {
783
final IProject project= getProject();
784
if (project != null) {
785
IResource resource= project.findMember(path);
786
if (resource != null && resource.getType() == IResource.FILE) {
787
final IFile file= (IFile)resource;
788
tu= (CElement) CModelManager.getDefault().create(file, this);
790
String contentTypeId= CoreModel.getRegistedContentTypeId(project, file.getName());
791
if (contentTypeId != null) {
792
tu= new TranslationUnit(this, file, contentTypeId);
798
tu= (CElement) CoreModel.getDefault().createTranslationUnitFrom(this, path);
801
return tu.getHandleFromMemento(memento);
809
protected char getHandleMementoDelimiter() {