1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-29 20:05:35 +02:00

Changes from Oda introducing LRUCaching

and the notion of WorkingCopy in the mode.
This commit is contained in:
Alain Magloire 2003-03-19 20:19:48 +00:00
parent 305ae53cf5
commit 31945e2ce6
30 changed files with 3018 additions and 99 deletions

View file

@ -15,6 +15,9 @@ import java.util.EventObject;
* @see ICElementDelta
*/
public class ElementChangedEvent extends EventObject {
public static final int POST_CHANGE = 1;
public static final int PRE_AUTO_BUILD = 2;
public static final int POST_RECONCILE = 4;
/**
* Creates an new element changed event (based on a <code>ICElementDelta</code>).
*

View file

@ -0,0 +1,70 @@
package org.eclipse.cdt.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.internal.core.model.IBuffer;
import org.eclipse.cdt.internal.core.model.IBufferChangedListener;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* An openable is an element that can be opened, saved, and closed.
* An openable might or might not have an associated buffer.
*/
public interface ICOpenable extends IBufferChangedListener{
/**
* Closes this element and its buffer (if any).
*/
public void close() throws CModelException;
/**
* Returns the buffer opened for this element, or <code>null</code>
* if this element does not have a buffer.
*/
public IBuffer getBuffer() throws CModelException;
/**
* returns true if the associated buffer has some unsaved changes
*/
boolean hasUnsavedChanges() throws CModelException;
/**
* Returns whether the element is consistent with its underlying resource or buffer.
* The element is consistent when opened, and is consistent if the underlying resource
* or buffer has not been modified since it was last consistent.
*/
boolean isConsistent() throws CModelException;
/**
* Returns whether this CFile is open.
*/
boolean isOpen();
/**
* Makes this element consistent with its underlying resource or buffer
* by updating the element's structure and properties as necessary.
*/
void makeConsistent(IProgressMonitor progress) throws CModelException;
/**
* Opens this element and all parent elements that are not already open.
* For translation units, a buffer is opened on the contents of the
* underlying resource.
*/
public void open(IProgressMonitor progress) throws CModelException;
/**
* Saves any changes in this element's buffer to its underlying resource
* via a workspace resource operation.
* <p>
* The <code>force</code> parameter controls how this method deals with
* cases where the workbench is not completely in sync with the local file system.
*/
public void save(IProgressMonitor progress, boolean force) throws CModelException;
}

View file

@ -6,5 +6,5 @@
package org.eclipse.cdt.core.model;
public interface ICResource extends IParent, ICElement {
public interface ICResource extends IParent, ICElement, ICOpenable {
}

View file

@ -4,8 +4,9 @@ package org.eclipse.cdt.core.model;
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.cdt.internal.core.model.IBufferFactory;
import org.eclipse.cdt.internal.core.model.IWorkingCopy;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* Represents an entire C translation unit (<code>.c</code> source file).
* The children are of type <code>IStructureElement</code>,
@ -64,6 +65,26 @@ public interface ITranslationUnit extends ICFile , ISourceReference, ISourceMani
*/
IUsing createUsing (String name, IProgressMonitor monitor) throws CModelException;
/**
* Finds the shared working copy for this element, given a <code>IBuffer</code> factory.
* If no working copy has been created for this element associated with this
* buffer factory, returns <code>null</code>.
* <p>
* Users of this method must not destroy the resulting working copy.
*
* @param bufferFactory the given <code>IBuffer</code> factory
* @return the found shared working copy for this element, <code>null</code> if none
* @see IBufferFactory
* @since 2.0
*/
IWorkingCopy findSharedWorkingCopy(IBufferFactory bufferFactory);
/**
* Returns the contents of a translation unit as a char[]
* @return char[]
*/
char[] getContents();
/**
* Returns the smallest element within this translation unit that
* includes the given source position (that is, a method, field, etc.), or
@ -99,6 +120,55 @@ public interface ITranslationUnit extends ICFile , ISourceReference, ISourceMani
*/
IInclude[] getIncludes() throws CModelException;
/**
* Returns a shared working copy on this element using the given factory to create
* the buffer, or this element if this element is already a working copy.
* This API can only answer an already existing working copy if it is based on the same
* original translation unit AND was using the same buffer factory (i.e. as
* defined by <code>Object#equals</code>).
* <p>
* The life time of a shared working copy is as follows:
* <ul>
* <li>The first call to <code>getSharedWorkingCopy(...)</code> creates a new working copy for this
* element</li>
* <li>Subsequent calls increment an internal counter.</li>
* <li>A call to <code>destroy()</code> decrements the internal counter.</li>
* <li>When this counter is 0, the working copy is destroyed.
* </ul>
* So users of this method must destroy exactly once the working copy.
* <p>
* Note that the buffer factory will be used for the life time of this working copy, i.e. if the
* working copy is closed then reopened, this factory will be used.
* The buffer will be automatically initialized with the original's compilation unit content
* upon creation.
* <p>
* When the shared working copy instance is created, an ADDED ICElementDelta is reported on this
* working copy.
*
* @param monitor a progress monitor used to report progress while opening this compilation unit
* or <code>null</code> if no progress should be reported
* @param factory the factory that creates a buffer that is used to get the content of the working copy
* or <code>null</code> if the internal factory should be used
* @param problemRequestor a requestor which will get notified of problems detected during
* reconciling as they are discovered. The requestor can be set to <code>null</code> indicating
* that the client is not interested in problems.
* @exception CModelException if the contents of this element can not be
* determined. Reasons include:
* <ul>
* <li> This C element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
* </ul>
* @return a shared working copy on this element using the given factory to create
* the buffer, or this element if this element is already a working copy
* @see IBufferFactory
* @see IProblemRequestor
* @since 2.0
*/
IWorkingCopy getSharedWorkingCopy(
IProgressMonitor monitor,
IBufferFactory factory)
throws CModelException;
/**
* Returns the first namespace declaration in this translation unit with the given package name
* This is a handle-only method. The namespace declaration may or may not exist.
@ -117,4 +187,21 @@ public interface ITranslationUnit extends ICFile , ISourceReference, ISourceMani
* exception occurs while accessing its corresponding resource
*/
IUsing[] getUsings() throws CModelException;
/**
* Returns a new working copy for the Translation Unit.
* @return IWorkingCopy
*/
IWorkingCopy getWorkingCopy() throws CModelException;
/**
* Returns a new working copy for the Translation Unit.
* @return IWorkingCopy
*/
IWorkingCopy getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory) throws CModelException;
/**
* Checks if this is a working copy.
* @return boolean
*/
boolean isWorkingCopy();
}

View file

@ -0,0 +1,443 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICOpenable;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.Platform;
/**
* @see IBuffer
* This class is similar to the JDT Buffer class.
*/
public class Buffer implements IBuffer {
protected IFile file;
protected int flags;
protected char[] contents;
protected ArrayList changeListeners;
protected ICOpenable owner;
protected int gapStart= -1;
protected int gapEnd= -1;
protected Object lock= new Object();
protected static final int F_HAS_UNSAVED_CHANGES= 1;
protected static final int F_IS_READ_ONLY= 2;
protected static final int F_IS_CLOSED= 4;
/**
* Creates a new buffer on an underlying resource.
*/
protected Buffer(IFile file, ICOpenable owner, boolean readOnly) {
this.file = file;
this.owner = owner;
if (file == null) {
setReadOnly(readOnly);
}
}
/**
* @see IBuffer
*/
public void addBufferChangedListener(IBufferChangedListener listener) {
if (this.changeListeners == null) {
this.changeListeners = new ArrayList(5);
}
if (!this.changeListeners.contains(listener)) {
this.changeListeners.add(listener);
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#append(char)
*/
public void append(char[] text) {
if (!isReadOnly()) {
if (text == null || text.length == 0) {
return;
}
int length = getLength();
moveAndResizeGap(length, text.length);
System.arraycopy(text, 0, this.contents, length, text.length);
this.gapStart += text.length;
this.flags |= F_HAS_UNSAVED_CHANGES;
notifyChanged(new BufferChangedEvent(this, length, 0, new String(text)));
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#append(java.lang.String)
*/
public void append(String text) {
if (text == null) {
return;
}
this.append(text.toCharArray());
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#close()
*/
public void close() {
BufferChangedEvent event = null;
synchronized (this.lock) {
if (isClosed())
return;
event = new BufferChangedEvent(this, 0, 0, null);
this.contents = null;
this.flags |= F_IS_CLOSED;
}
notifyChanged(event); // notify outside of synchronized block
this.changeListeners = null;
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getChar(int)
*/
public char getChar(int position) {
synchronized (this.lock) {
if (position < this.gapStart) {
return this.contents[position];
}
int gapLength = this.gapEnd - this.gapStart;
return this.contents[position + gapLength];
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getCharacters()
*/
public char[] getCharacters() {
if (this.contents == null) return null;
synchronized (this.lock) {
if (this.gapStart < 0) {
return this.contents;
}
int length = this.contents.length;
char[] newContents = new char[length - this.gapEnd + this.gapStart];
System.arraycopy(this.contents, 0, newContents, 0, this.gapStart);
System.arraycopy(this.contents, this.gapEnd, newContents, this.gapStart, length - this.gapEnd);
return newContents;
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getContents()
*/
public String getContents() {
if (this.contents == null) return null;
return new String(this.getCharacters());
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getLength()
*/
public int getLength() {
synchronized (this.lock) {
int length = this.gapEnd - this.gapStart;
return (this.contents.length - length);
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getOwner()
*/
public ICOpenable getOwner() {
return this.owner;
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getText(int, int)
*/
public String getText(int offset, int length) {
if (this.contents == null)
return ""; //$NON-NLS-1$
synchronized (this.lock) {
if (offset + length < this.gapStart)
return new String(this.contents, offset, length);
if (this.gapStart < offset) {
int gapLength = this.gapEnd - this.gapStart;
return new String(this.contents, offset + gapLength, length);
}
StringBuffer buf = new StringBuffer();
buf.append(this.contents, offset, this.gapStart - offset);
buf.append(this.contents, this.gapEnd, offset + length - this.gapStart);
return buf.toString();
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#getUnderlyingResource()
*/
public IResource getUnderlyingResource() {
return this.file;
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#hasUnsavedChanges()
*/
public boolean hasUnsavedChanges() {
return (this.flags & F_HAS_UNSAVED_CHANGES) != 0;
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#isClosed()
*/
public boolean isClosed() {
return (this.flags & F_IS_CLOSED) != 0;
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#isReadOnly()
*/
public boolean isReadOnly() {
if (this.file == null) {
return (this.flags & F_IS_READ_ONLY) != 0;
} else {
return this.file.isReadOnly();
}
}
/**
* Notify the listeners that this buffer has changed.
* To avoid deadlock, this should not be called in a synchronized block.
*/
protected void notifyChanged(final BufferChangedEvent event) {
if (this.changeListeners != null) {
for (int i = 0, size = this.changeListeners.size(); i < size; ++i) {
final IBufferChangedListener listener = (IBufferChangedListener) this.changeListeners.get(i);
Platform.run(new ISafeRunnable() {
public void handleException(Throwable exception) {
Util.log(exception, "Exception occurred in listener of buffer change notification"); //$NON-NLS-1$
}
public void run() throws Exception {
listener.bufferChanged(event);
}
});
}
}
}
/**
* @see IBuffer
*/
public void removeBufferChangedListener(IBufferChangedListener listener) {
if (this.changeListeners != null) {
this.changeListeners.remove(listener);
if (this.changeListeners.size() == 0) {
this.changeListeners = null;
}
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#replace(int, int, char)
*/
public void replace(int position, int length, char[] text) {
if (!isReadOnly()) {
int textLength = text == null ? 0 : text.length;
synchronized (this.lock) {
// move gap
moveAndResizeGap(position + length, textLength - length);
// overwrite
int min = Math.min(textLength, length);
if (min > 0) {
System.arraycopy(text, 0, this.contents, position, min);
}
if (length > textLength) {
// enlarge the gap
this.gapStart -= length - textLength;
} else if (textLength > length) {
// shrink gap
this.gapStart += textLength - length;
System.arraycopy(text, 0, this.contents, position, textLength);
}
}
this.flags |= F_HAS_UNSAVED_CHANGES;
String string = null;
if (textLength > 0) {
string = new String(text);
}
notifyChanged(new BufferChangedEvent(this, position, length, string));
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#replace(int, int, java.lang.String)
*/
public void replace(int position, int length, String text) {
this.replace(position, length, text == null ? null : text.toCharArray());
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#save(org.eclipse.core.runtime.IProgressMonitor, boolean)
*/
public void save(IProgressMonitor progress, boolean force)
throws CModelException {
// determine if saving is required
if (isReadOnly() || this.file == null) {
return;
}
synchronized (this.lock) {
if (!hasUnsavedChanges())
return;
// use a platform operation to update the resource contents
try {
String contents = this.getContents();
if (contents == null) return;
byte[] bytes = contents.getBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
this.file.setContents(
stream,
force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
null);
}
catch (CoreException e) {
throw new CModelException(e);
}
// the resource no longer has unsaved changes
this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#setContents(char)
*/
public void setContents(char[] newContents) {
// allow special case for first initialization
// after creation by buffer factory
if (this.contents == null) {
this.contents = newContents;
this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
return;
}
if (!isReadOnly()) {
String string = null;
if (newContents != null) {
string = new String(newContents);
}
BufferChangedEvent event = new BufferChangedEvent(this, 0, this.getLength(), string);
synchronized (this.lock) {
this.contents = newContents;
this.flags |= F_HAS_UNSAVED_CHANGES;
this.gapStart = -1;
this.gapEnd = -1;
}
notifyChanged(event);
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IBuffer#setContents(java.lang.String)
*/
public void setContents(String newContents) {
this.setContents(newContents.toCharArray());
}
/**
* Moves the gap to location and adjust its size to the
* anticipated change size. The size represents the expected
* range of the gap that will be filled after the gap has been moved.
* Thus the gap is resized to actual size + the specified size and
* moved to the given position.
*/
protected void moveAndResizeGap(int position, int size) {
char[] content = null;
int oldSize = this.gapEnd - this.gapStart;
if (size < 0) {
if (oldSize > 0) {
content = new char[this.contents.length - oldSize];
System.arraycopy(this.contents, 0, content, 0, this.gapStart);
System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, content.length - this.gapStart);
this.contents = content;
}
this.gapStart = this.gapEnd = position;
return;
}
content = new char[this.contents.length + (size - oldSize)];
int newGapStart = position;
int newGapEnd = newGapStart + size;
if (oldSize == 0) {
System.arraycopy(this.contents, 0, content, 0, newGapStart);
System.arraycopy(this.contents, newGapStart, content, newGapEnd, content.length - newGapEnd);
} else
if (newGapStart < this.gapStart) {
int delta = this.gapStart - newGapStart;
System.arraycopy(this.contents, 0, content, 0, newGapStart);
System.arraycopy(this.contents, newGapStart, content, newGapEnd, delta);
System.arraycopy(this.contents, this.gapEnd, content, newGapEnd + delta, this.contents.length - this.gapEnd);
} else {
int delta = newGapStart - this.gapStart;
System.arraycopy(this.contents, 0, content, 0, this.gapStart);
System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, delta);
System.arraycopy(this.contents, this.gapEnd + delta, content, newGapEnd, content.length - newGapEnd);
}
this.contents = content;
this.gapStart = newGapStart;
this.gapEnd = newGapEnd;
}
/**
* Sets this <code>Buffer</code> to be read only.
*/
protected void setReadOnly(boolean readOnly) {
if (readOnly) {
this.flags |= F_IS_READ_ONLY;
} else {
this.flags &= ~(F_IS_READ_ONLY);
}
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Owner: " + ((CElement)this.owner).toString()); //$NON-NLS-1$
buffer.append("\nHas unsaved changes: " + this.hasUnsavedChanges()); //$NON-NLS-1$
buffer.append("\nIs readonly: " + this.isReadOnly()); //$NON-NLS-1$
buffer.append("\nIs closed: " + this.isClosed()); //$NON-NLS-1$
buffer.append("\nContents:\n"); //$NON-NLS-1$
char[] contents = this.getCharacters();
if (contents == null) {
buffer.append("<null>"); //$NON-NLS-1$
} else {
int length = contents.length;
for (int i = 0; i < length; i++) {
char car = contents[i];
switch (car) {
case '\n':
buffer.append("\\n\n"); //$NON-NLS-1$
break;
case '\r':
if (i < length-1 && this.contents[i+1] == '\n') {
buffer.append("\\r\\n\n"); //$NON-NLS-1$
i++;
} else {
buffer.append("\\r\n"); //$NON-NLS-1$
}
break;
default:
buffer.append(car);
break;
}
}
}
return buffer.toString();
}
}

View file

@ -0,0 +1,111 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import java.util.EventObject;
/**
* A buffer changed event describes how a buffer has changed. These events are
* used in <code>IBufferChangedListener</code> notifications.
* <p>
* For text insertions, <code>getOffset</code> is the offset
* of the first inserted character, <code>getText</code> is the
* inserted text, and <code>getLength</code> is 0.
* </p>
* <p>
* For text removals, <code>getOffset</code> is the offset
* of the first removed character, <code>getText</code> is <code>null</code>,
* and <code>getLength</code> is the length of the text that was removed.
* </p>
* <p>
* For replacements (including <code>IBuffer.setContents</code>),
* <code>getOffset</code> is the offset
* of the first replaced character, <code>getText</code> is the replacement
* text, and <code>getLength</code> is the length of the original text
* that was replaced.
* </p>
* <p>
* When a buffer is closed, <code>getOffset</code> is 0, <code>getLength</code>
* is 0, and <code>getText</code> is <code>null</code>.
* </p>
* <p>
* This class is not intended to be instantiated or subclassed by clients.
* Instances of this class are automatically created by the C model.
* </p>
*
* @see IBuffer
* This class is similar to the JDT BufferChangedEvent class.
*/
public class BufferChangedEvent extends EventObject {
/**
* The length of text that has been modified in the buffer.
*/
private int length;
/**
* The offset into the buffer where the modification took place.
*/
private int offset;
/**
* The text that was modified.
*/
private String text;
/**
* Creates a new buffer changed event indicating that the given buffer has changed.
*/
public BufferChangedEvent(IBuffer buffer, int offset, int length, String text) {
super(buffer);
this.offset = offset;
this.length = length;
this.text = text;
}
/**
* Returns the buffer which has changed.
*
* @return the buffer affected by the change
*/
public IBuffer getBuffer() {
return (IBuffer) source;
}
/**
* Returns the length of text removed or replaced in the buffer, or
* 0 if text has been inserted into the buffer.
*
* @return the length of the original text fragment modified by the
* buffer change (<code> 0 </code> in case of insertion).
*/
public int getLength() {
return this.length;
}
/**
* Returns the index of the first character inserted, removed, or replaced
* in the buffer.
*
* @return the source offset of the textual manipulation in the buffer
*/
public int getOffset() {
return this.offset;
}
/**
* Returns the text that was inserted, the replacement text,
* or <code>null</code> if text has been removed.
*
* @return the text corresponding to the buffer change (<code> null </code>
* in case of deletion).
*/
public String getText() {
return this.text;
}
}

View file

@ -0,0 +1,156 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import java.util.Enumeration;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICOpenable;
import org.eclipse.cdt.internal.core.util.LRUCache;
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
/**
* The buffer manager manages the set of open buffers.
* It implements an LRU cache of buffers.
*
* This class is similar to the JDT BufferManager class
*/
public class BufferManager implements IBufferFactory {
/**
* An LRU cache of <code>IBuffers</code>.
*/
public class BufferCache extends OverflowingLRUCache {
/**
* Constructs a new buffer cache of the given size.
*/
public BufferCache(int size) {
super(size);
}
/**
* Constructs a new buffer cache of the given size.
*/
public BufferCache(int size, int overflow) {
super(size, overflow);
}
/**
* Returns true if the buffer is successfully closed and
* removed from the cache, otherwise false.
*
* <p>NOTE: this triggers an external removal of this buffer
* by closing the buffer.
*/
protected boolean close(LRUCacheEntry entry) {
IBuffer buffer= (IBuffer) entry._fValue;
if (buffer.hasUnsavedChanges()) {
return false;
} else {
buffer.close();
return true;
}
}
/**
* Returns a new instance of the reciever.
*/
protected LRUCache newInstance(int size, int overflow) {
return new BufferCache(size, overflow);
}
}
protected static BufferManager DEFAULT_BUFFER_MANAGER;
/**
* LRU cache of buffers. The key and value for an entry
* in the table is the identical buffer.
*/
protected OverflowingLRUCache openBuffers = new BufferCache(60);
/**
* Creates a new buffer manager.
*/
public BufferManager() {
}
/**
* Adds a buffer to the table of open buffers.
*/
protected void addBuffer(IBuffer buffer) {
openBuffers.put(buffer.getOwner(), buffer);
}
/**
* @see org.eclipse.cdt.internal.core.model.IBufferFactory#createBuffer(org.eclipse.cdt.core.model.IOpenable)
*/
public IBuffer createBuffer(ICOpenable owner) {
ICElement element = (ICElement)owner;
try{
IResource resource = element.getResource();
return
new Buffer(
resource instanceof IFile ? (IFile)resource : null,
owner,
element.isReadOnly());
}
catch (CModelException e) {
return null;
}
}
/**
* Returns the open buffer associated with the given owner,
* or <code>null</code> if the owner does not have an open
* buffer associated with it.
*/
public IBuffer getBuffer(ICOpenable owner) {
return (IBuffer)openBuffers.get(owner);
}
/**
* Returns the default buffer factory.
*/
public IBufferFactory getDefaultBufferFactory() {
return this;
}
/**
* Returns the default buffer manager.
*/
public synchronized static BufferManager getDefaultBufferManager() {
if (DEFAULT_BUFFER_MANAGER == null) {
DEFAULT_BUFFER_MANAGER = new BufferManager();
}
return DEFAULT_BUFFER_MANAGER;
}
/**
* Returns an enumeration of all open buffers.
* <p>
* The <code>Enumeration</code> answered is thread safe.
*
* @see OverflowingLRUCache
* @return Enumeration of IBuffer
*/
public Enumeration getOpenBuffers() {
synchronized (openBuffers) {
openBuffers.shrink();
return openBuffers.elements();
}
}
/**
* Removes a buffer from the table of open buffers.
*/
protected void removeBuffer(IBuffer buffer) {
openBuffers.remove(buffer.getOwner());
}
}

View file

@ -4,15 +4,17 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.core.model.ICOpenable;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ICRoot;
import org.eclipse.cdt.core.model.IParent;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICRoot;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.CModelException;
public abstract class CElement extends PlatformObject implements ICElement {
@ -20,8 +22,6 @@ public abstract class CElement extends PlatformObject implements ICElement {
protected ICElement fParent;
protected CElementInfo fCElementInfo;
protected String fName;
protected int fStartPos;
@ -37,7 +37,6 @@ public abstract class CElement extends PlatformObject implements ICElement {
fParent= parent;
fName= name;
fType= type;
fCElementInfo = null;
}
// setters
@ -89,7 +88,14 @@ public abstract class CElement extends PlatformObject implements ICElement {
}
public boolean isReadOnly () {
return getElementInfo().isReadOnly();
try {
IResource r = getUnderlyingResource();
if (r != null) {
return r.isReadOnly();
}
} catch (CModelException e) {
}
return false;
}
public boolean isStructureKnown() throws CModelException {
@ -206,10 +212,22 @@ public abstract class CElement extends PlatformObject implements ICElement {
}
public CElementInfo getElementInfo () {
if (fCElementInfo == null) {
fCElementInfo = createElementInfo();
try {
CModelManager manager;
synchronized(manager = CModelManager.getDefault()){
Object info = manager.getInfo(this);
if (info == null) {
openHierarchy();
info= manager.getInfo(this);
if (info == null) {
throw newNotPresentException();
}
}
return (CElementInfo)info;
}
} catch(CModelException e) {
return null;
}
return fCElementInfo;
}
public String toString() {
@ -264,4 +282,116 @@ public abstract class CElement extends PlatformObject implements ICElement {
protected void runOperation(CModelOperation operation, IProgressMonitor monitor) throws CModelException {
CModelManager.getDefault().runOperation(operation, monitor);
}
/**
* Close the C Element
* @throws CModelException
*/
public void close() throws CModelException {
Object info = CModelManager.getDefault().peekAtInfo(this);
if (info != null) {
if (this instanceof IParent) {
ICElement[] children = ((CElementInfo) info).getChildren();
for (int i = 0, size = children.length; i < size; ++i) {
CElement child = (CElement) children[i];
child.close();
}
}
closing(info);
CModelManager.getDefault().removeInfo(this);
}
}
/**
* This element is being closed. Do any necessary cleanup.
*/
protected void closing(Object info) throws CModelException {
}
/**
* This element has just been opened. Do any necessary setup.
*/
protected void opening(Object info) {
}
/**
* Return the first instance of IOpenable in the parent
* hierarchy of this element.
*
* <p>Subclasses that are not IOpenable's must override this method.
*/
public ICOpenable getOpenableParent() {
return (ICOpenable)fParent;
}
/**
* Opens this element and all parents that are not already open.
*
* @exception CModelException this element is not present or accessible
*/
protected void openHierarchy() throws CModelException {
if (this instanceof ICOpenable) {
((CResource) this).openWhenClosed(null);
} else {
CResource openableParent = (CResource)getOpenableParent();
if (openableParent != null) {
CElementInfo openableParentInfo = (CElementInfo) CModelManager.getDefault().getInfo((ICElement) openableParent);
if (openableParentInfo == null) {
openableParent.openWhenClosed(null);
} else {
CModelManager.getDefault().putInfo( this, createElementInfo());
}
}
}
}
/**
* Returns true if this element is an ancestor of the given element,
* otherwise false.
*/
protected boolean isAncestorOf(ICElement e) {
ICElement parent= e.getParent();
while (parent != null && !parent.equals(this)) {
parent= parent.getParent();
}
return parent != null;
}
/**
* Creates and returns and not present exception for this element.
*/
protected CModelException newNotPresentException() {
return new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
}
/**
* Removes all cached info from the C Model, including all children,
* but does not close this element.
*/
protected void removeInfo() {
Object info = CModelManager.getDefault().peekAtInfo(this);
if (info != null) {
if (this instanceof IParent) {
ICElement[] children = ((CElementInfo)info).getChildren();
for (int i = 0, size = children.length; i < size; ++i) {
CElement child = (CElement) children[i];
child.removeInfo();
}
}
CModelManager.getDefault().removeInfo(this);
}
}
/**
* Returns the hash code for this Java element. By default,
* the hash code for an element is a combination of its name
* and parent's hash code. Elements with other requirements must
* override this method.
*/
// CHECKPOINT: making not equal objects seem equal
// What elements should override this?
public int hashCode() {
if (fParent == null) return super.hashCode();
return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
}
}

View file

@ -0,0 +1,37 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.core.model.ICElement;
/**
* A C element delta biulder creates a C element delta on a C element between
* the version of the C element at the time the comparator was created and the
* current version of the C element.
*
* It performs this operation by locally caching the contents of
* the C element when it is created. When the method buildDeltas() is called, it
* creates a delta over the cached contents and the new contents.
*
* This class is similar to the JDT CElementDeltaBuilder class.
*/
public class CElementDeltaBuilder {
CElementDelta delta;
public CElementDeltaBuilder(ICElement cElement) {
}
public void buildDeltas() {
}
}

View file

@ -94,20 +94,6 @@ class CElementInfo {
return fIsStructureKnown;
}
/**
* @see ICElement.isStructureKnown()
*/
public boolean isReadOnly () {
try {
IResource r = getElement().getUnderlyingResource();
if (r != null) {
return r.isReadOnly();
}
} catch (CModelException e) {
}
return true;
}
/**
* Returns an array with all the same elements as the specified array except for
* the element to remove. Assumes that the deletion is contained in the array.

View file

@ -4,15 +4,13 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
//import org.eclipse.core.runtime.CoreException;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICFile;
public class CFile extends CResource implements ICFile {

View file

@ -5,11 +5,11 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import org.eclipse.core.resources.IFolder;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICFolder;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.IProgressMonitor;
public class CFolder extends CResource implements ICFolder {
@ -29,4 +29,10 @@ public class CFolder extends CResource implements ICFolder {
protected CElementInfo createElementInfo () {
return new CFolderInfo(this);
}
// CHECKPOINT: folders will return the hash code of their path
public int hashCode() {
return getPath().hashCode();
}
}

View file

@ -0,0 +1,138 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import java.util.HashMap;
import java.util.Map;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;
/**
* The cache of C elements to their respective info.
*
* This class is similar to the JDT CModelCache class.
*/
public class CModelCache {
public static final int PROJ_CACHE_SIZE = 50;
public static final int FOLDER_CACHE_SIZE = 500;
public static final int FILE_CACHE_SIZE = 2000;
public static final int CHILDREN_CACHE_SIZE = FILE_CACHE_SIZE * 20;
/**
* Cache of open projects and roots.
*/
protected Map projectAndRootCache;
/**
* Cache of open containers
*/
protected Map folderCache;
/**
* Cache of open translation unit files
*/
protected OverflowingLRUCache fileCache;
/**
* Cache of children of C elements
*/
protected Map childrenCache;
public CModelCache() {
this.projectAndRootCache = new HashMap(PROJ_CACHE_SIZE);
this.folderCache = new HashMap(FOLDER_CACHE_SIZE);
this.fileCache = new ElementCache(FILE_CACHE_SIZE);
this.childrenCache = new HashMap(CHILDREN_CACHE_SIZE); // average 20 children per openable
}
public double openableFillingRatio() {
return this.fileCache.fillingRatio();
}
/**
* Returns the info for the element.
*/
public Object getInfo(ICElement element) {
switch (element.getElementType()) {
case ICElement.C_PROJECT:
case ICElement.C_ROOT:
return this.projectAndRootCache.get(element);
case ICElement.C_FOLDER:
return this.folderCache.get(element);
case ICElement.C_FILE:
return this.fileCache.get(element);
default:
return this.childrenCache.get(element);
}
}
/**
* Returns the info for this element without
* disturbing the cache ordering.
*/
protected Object peekAtInfo(ICElement element) {
switch (element.getElementType()) {
case ICElement.C_PROJECT:
case ICElement.C_ROOT:
return this.projectAndRootCache.get(element);
case ICElement.C_FOLDER:
return this.folderCache.get(element);
case ICElement.C_FILE:
return this.fileCache.peek(element);
default:
return this.childrenCache.get(element);
}
}
/**
* Remember the info for the element.
*/
protected void putInfo(ICElement element, Object info) {
switch (element.getElementType()) {
case ICElement.C_PROJECT:
case ICElement.C_ROOT:
this.projectAndRootCache.put(element, info);
break;
case ICElement.C_FOLDER:
this.folderCache.put(element, info);
break;
case ICElement.C_FILE:
this.fileCache.put(element, info);
break;
default:
this.childrenCache.put(element, info);
}
}
/**
* Removes the info of the element from the cache.
*/
protected void removeInfo(ICElement element) {
switch (element.getElementType()) {
case ICElement.C_PROJECT:
case ICElement.C_ROOT:
this.projectAndRootCache.remove(element);
break;
case ICElement.C_FOLDER:
this.folderCache.remove(element);
break;
case ICElement.C_FILE:
this.fileCache.remove(element);
break;
default:
this.childrenCache.remove(element);
}
}
}

View file

@ -53,7 +53,7 @@ public class CModelManager implements IResourceChangeListener {
//private static HashMap fParsers = new HashMap();
/**
* Used to convert <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
* Used to convert <code>IResourceDelta</code>s into <code>ICElementDelta</code>s.
*/
protected DeltaProcessor fDeltaProcessor= new DeltaProcessor();
@ -73,6 +73,25 @@ public class CModelManager implements IResourceChangeListener {
*/
protected ArrayList fElementChangedListeners= new ArrayList();
/**
* A map from ITranslationUnit to IWorkingCopy of the shared working copies.
*/
public Map sharedWorkingCopies = new HashMap();
/**
* Set of elements which are out of sync with their buffers.
*/
protected Map elementsOutOfSynchWithBuffers = new HashMap(11);
/**
* Infos cache.
*/
protected CModelCache cache = new CModelCache();
/**
* This is a cache of the projects before any project addition/deletion has started.
*/
public ICProject[] cProjectsCache;
public static final String [] sourceExtensions = {"c", "cxx", "cc", "C", "cpp"};
public static final String [] headerExtensions = {"h", "hh", "hpp"};
@ -658,11 +677,14 @@ public class CModelManager implements IResourceChangeListener {
case IResourceChangeEvent.PRE_AUTO_BUILD :
// No need now.
if(delta != null) {
this.checkProjectsBeingAddedOrRemoved(delta);
}
break;
case IResourceChangeEvent.POST_CHANGE :
if (delta != null) {
try {
try {
if (delta != null) {
ICElementDelta[] translatedDeltas = fDeltaProcessor.processResourceDelta(delta);
if (translatedDeltas.length > 0) {
for (int i= 0; i < translatedDeltas.length; i++) {
@ -670,10 +692,10 @@ public class CModelManager implements IResourceChangeListener {
}
}
fire();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
@ -795,4 +817,62 @@ public class CModelManager implements IResourceChangeListener {
} // else deltas are fired while processing the resource delta
}
}
/**
* Process the given delta and look for projects being added, opened,
* or closed
*/
public void checkProjectsBeingAddedOrRemoved(IResourceDelta delta) {
IResource resource = delta.getResource();
switch (resource.getType()) {
case IResource.ROOT :
if (this.cProjectsCache == null) {
this.cProjectsCache = this.getCRoot().getCProjects();
}
IResourceDelta[] children = delta.getAffectedChildren();
for (int i = 0, length = children.length; i < length; i++) {
this.checkProjectsBeingAddedOrRemoved(children[i]);
}
break;
case IResource.PROJECT :
// TO BE COMPLETED ...
break;
}
}
/**
* Returns the set of elements which are out of synch with their buffers.
*/
protected Map getElementsOutOfSynchWithBuffers() {
return this.elementsOutOfSynchWithBuffers;
}
/**
* Returns the info for the element.
*/
public Object getInfo(ICElement element) {
return this.cache.getInfo(element);
}
/**
* Returns the info for this element without
* disturbing the cache ordering.
*/
protected Object peekAtInfo(ICElement element) {
return this.cache.peekAtInfo(element);
}
/**
* Puts the info for a C Model Element
*/
protected void putInfo(ICElement element, Object info) {
this.cache.putInfo(element, info);
}
/**
* Removes the info of this model element.
*/
protected void removeInfo(ICElement element) {
this.cache.removeInfo(element);
}
}

View file

@ -77,4 +77,10 @@ public class CProject extends CResource implements ICProject {
protected CElementInfo createElementInfo() {
return new CProjectInfo(this);
}
// CHECKPOINT: CProjects will return the hash code of their underlying IProject
public int hashCode() {
return getProject().hashCode();
}
}

View file

@ -5,13 +5,19 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.core.model.ICResource;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.cdt.core.model.*;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.core.runtime.IProgressMonitor;
public abstract class CResource extends Parent implements ICResource {
@ -38,4 +44,246 @@ public abstract class CResource extends Parent implements ICResource {
}
protected abstract CElementInfo createElementInfo ();
/**
* The buffer associated with this element has changed. Registers
* this element as being out of synch with its buffer's contents.
* If the buffer has been closed, this element is set as NOT out of
* synch with the contents.
*
* @see IBufferChangedListener
*/
public void bufferChanged(BufferChangedEvent event) {
if (event.getBuffer().isClosed()) {
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().remove(this);
getBufferManager().removeBuffer(event.getBuffer());
} else {
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().put(this, this);
}
}
/**
* Updates the info objects for this element and all of its children by
* removing the current infos, generating new infos, and then placing
* the new infos into the C Model cache tables.
*/
protected void buildStructure(CResourceInfo info, IProgressMonitor monitor) throws CModelException {
if (monitor != null && monitor.isCanceled()) return;
// remove existing (old) infos
removeInfo();
HashMap newElements = new HashMap(11);
info.setIsStructureKnown(generateInfos(info, monitor, newElements, getResource()));
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().remove(this);
for (Iterator iter = newElements.keySet().iterator(); iter.hasNext();) {
ICElement key = (ICElement) iter.next();
Object value = newElements.get(key);
CModelManager.getDefault().putInfo(key, value);
}
// add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
// to be flushed. Might lead to performance issues.
CModelManager.getDefault().putInfo(this, info);
}
/**
* Close the buffer associated with this element, if any.
*/
protected void closeBuffer(CFileInfo info) {
if (!hasBuffer()) return; // nothing to do
IBuffer buffer = null;
buffer = getBufferManager().getBuffer(this);
if (buffer != null) {
buffer.close();
buffer.removeBufferChangedListener(this);
}
}
/**
* Derived classes may override.
*/
protected boolean generateInfos(CResourceInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws CModelException{
return false;
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#getBuffer()
*/
public IBuffer getBuffer() throws CModelException {
if (hasBuffer()) {
// ensure element is open
if (!isOpen()) {
getElementInfo();
}
IBuffer buffer = getBufferManager().getBuffer(this);
if (buffer == null) {
// try to (re)open a buffer
buffer = openBuffer(null);
}
return buffer;
} else {
return null;
}
}
/**
* Answers the buffer factory to use for creating new buffers
*/
public IBufferFactory getBufferFactory(){
return getBufferManager().getDefaultBufferFactory();
}
/**
* Returns the buffer manager for this element.
*/
protected BufferManager getBufferManager() {
return BufferManager.getDefaultBufferManager();
}
/**
* Returns true if this element may have an associated source buffer,
* otherwise false. Subclasses must override as required.
*/
protected boolean hasBuffer() {
return false;
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#hasUnsavedChanges()
*/
public boolean hasUnsavedChanges() throws CModelException{
if (isReadOnly() || !isOpen()) {
return false;
}
IBuffer buf = this.getBuffer();
if (buf != null && buf.hasUnsavedChanges()) {
return true;
}
// for roots and projects must check open buffers
// to see if they have an child with unsaved changes
if (fType == C_ROOT ||
fType == C_PROJECT) {
Enumeration openBuffers= getBufferManager().getOpenBuffers();
while (openBuffers.hasMoreElements()) {
IBuffer buffer= (IBuffer)openBuffers.nextElement();
if (buffer.hasUnsavedChanges()) {
ICElement owner= (ICElement)buffer.getOwner();
if (isAncestorOf(owner)) {
return true;
}
}
}
}
return false;
}
/**
* Subclasses must override as required.
*
* @see org.eclipse.cdt.core.model.ICOpenable#isConsistent()
*/
public boolean isConsistent() throws CModelException {
return true;
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#isOpen()
*/
public boolean isOpen() {
synchronized(CModelManager.getDefault()){
return CModelManager.getDefault().getInfo(this) != null;
}
}
/**
* Returns true if this represents a source element.
* Openable source elements have an associated buffer created
* when they are opened.
*/
protected boolean isSourceElement() {
return false;
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#makeConsistent(IProgressMonitor)
*/
public void makeConsistent(IProgressMonitor pm) throws CModelException {
if (!isConsistent()) {
buildStructure((CFileInfo)getElementInfo(), pm);
}
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#open(IProgressMonitor)
*/
public void open(IProgressMonitor pm) throws CModelException {
if (!isOpen()) {
this.openWhenClosed(pm);
}
}
/**
* Opens a buffer on the contents of this element, and returns
* the buffer, or returns <code>null</code> if opening fails.
* By default, do nothing - subclasses that have buffers
* must override as required.
*/
protected IBuffer openBuffer(IProgressMonitor pm) throws CModelException {
return null;
}
/**
* Open the parent element if necessary
*
*/
protected void openParent(IProgressMonitor pm) throws CModelException {
CResource openableParent = (CResource)getOpenableParent();
if (openableParent != null) {
if (!openableParent.isOpen()){
openableParent.openWhenClosed(pm);
}
}
}
/**
* Open a <code>IOpenable</code> that is known to be closed (no check for
* <code>isOpen()</code>).
*/
protected void openWhenClosed(IProgressMonitor pm) throws CModelException {
try {
// 1) Parent must be open - open the parent if necessary
openParent(pm);
// 2) create the new element info and open a buffer if needed
CResourceInfo info = (CResourceInfo) createElementInfo();
IResource resource = getResource();
if (resource != null && isSourceElement()) {
this.openBuffer(pm);
}
// 3) build the structure of the openable
buildStructure(info, pm);
// if any problems occuring openning the element, ensure that it's info
// does not remain in the cache (some elements, pre-cache their info
// as they are being opened).
} catch (CModelException e) {
CModelManager.getDefault().removeInfo(this);
throw e;
}
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#save(IProgressMonitor, boolean)
*/
public void save(IProgressMonitor pm, boolean force) throws CModelException {
if (isReadOnly() || this.getResource().isReadOnly()) {
throw new CModelException(new CModelStatus(ICModelStatusConstants.READ_ONLY, this));
}
IBuffer buf = getBuffer();
if (buf != null) {
buf.save(pm, force);
this.makeConsistent(pm); // update the element info of this element
}
}
}

View file

@ -5,6 +5,8 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import java.util.ArrayList;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
@ -29,10 +31,10 @@ public class CRoot extends CResource implements ICRoot {
}
public ICProject[] getCProjects() {
ICElement[] e = getChildren();
ICProject[] p = new ICProject[e.length];
System.arraycopy(e, 0, p, 0, e.length);
return p;
ArrayList list = getChildrenOfType(C_PROJECT);
ICProject[] array= new ICProject[list.size()];
list.toArray(array);
return array;
}
public IWorkspace getWorkspace() {
@ -109,4 +111,10 @@ public class CRoot extends CResource implements ICRoot {
protected CElementInfo createElementInfo () {
return new CRootInfo(this);
}
// CHECKPOINT: Roots will return the hashcode of their resource
public int hashCode() {
return resource.hashCode();
}
}

View file

@ -0,0 +1,145 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICModelStatus;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IResource;
/**
* Commits the contents of a working copy translation unit to its original
* element and resource, bringing the C Model up-to-date with the current
* contents of the working copy.
*
* <p>It is possible that the contents of the
* original resource have changed since the working copy was created,
* in which case there is an update conflict. This operation allows
* for two settings to resolve conflict set by the <code>fForce</code> flag:<ul>
* <li>force flag is <code>false</code> - in this case a <code>CModelException</code>
* is thrown</li>
* <li>force flag is <code>true</code> - in this case the contents of
* the working copy are applied to the underlying resource even though
* the working copy was created before a subsequent change in the
* resource</li>
* </ul>
*
* <p>The default conflict resolution setting is the force flag is <code>false</code>
*
* A CModelOperation exception is thrown either if the commit could not be
* performed.
*
* This class is similar to the JDT CommitWorkingCopyOperation class.
*/
public class CommitWorkingCopyOperation extends CModelOperation {
/**
* Constructs an operation to commit the contents of a working copy
* to its original translation unit.
*/
public CommitWorkingCopyOperation(ITranslationUnit element, boolean force) {
super(new ICElement[] {element}, force);
}
/**
* @see org.eclipse.cdt.internal.core.model.CModelOperation#executeOperation()
*/
protected void executeOperation() throws CModelException {
try {
beginTask("workingCopy.commit", 2); //$NON-NLS-1$
WorkingCopy copy = (WorkingCopy)getElementToProcess();
ITranslationUnit original = (ITranslationUnit) copy.getOriginalElement();
// creates the delta builder (this remembers the content of the cu)
if (!original.isOpen()) {
// force opening so that the delta builder can get the old info
original.open(null);
}
CElementDeltaBuilder deltaBuilder = new CElementDeltaBuilder(original);
// save the cu
IBuffer originalBuffer = original.getBuffer();
if (originalBuffer == null) return;
char[] originalContents = originalBuffer.getCharacters();
boolean hasSaved = false;
try {
IBuffer copyBuffer = copy.getBuffer();
if (copyBuffer == null) return;
originalBuffer.setContents(copyBuffer.getCharacters());
original.save(fMonitor, fForce);
this.hasModifiedResource = true;
hasSaved = true;
} finally {
if (!hasSaved){
// restore original buffer contents since something went wrong
originalBuffer.setContents(originalContents);
}
}
// make sure working copy is in sync
copy.updateTimeStamp((TranslationUnit)original);
copy.makeConsistent(this);
worked(1);
if (deltaBuilder != null) {
// build the deltas
deltaBuilder.buildDeltas();
// add the deltas to the list of deltas created during this operation
if (deltaBuilder.delta != null) {
addDelta(deltaBuilder.delta);
}
}
worked(1);
} finally {
done();
}
}
/**
* Possible failures: <ul>
* <li>INVALID_ELEMENT_TYPES - the Translation unit supplied to this
* operation is not a working copy
* <li>ELEMENT_NOT_PRESENT - the Translation unit the working copy is
* based on no longer exists.
* <li>UPDATE_CONFLICT - the original Translation unit has changed since
* the working copy was created and the operation specifies no force
* </ul>
*/
public ICModelStatus verify() {
IWorkingCopy wc = (IWorkingCopy) getElementToProcess();
if (!wc.isWorkingCopy()) {
return new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES, wc);
}
try {
ITranslationUnit original= (ITranslationUnit)wc.getOriginalElement();
IResource resource = original.getResource();
if (!wc.isBasedOn(resource) && !fForce) {
return new CModelStatus(ICModelStatusConstants.UPDATE_CONFLICT);
}
} catch (CModelException e){
// unable to get the underlying resource
return new CModelStatus(ICModelStatusConstants.INVALID_RESOURCE);
}
// no read-only check, since some repository adapters can change the flag on save
// operation.
return CModelStatus.VERIFIED_OK;
}
}

View file

@ -0,0 +1,71 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICOpenable;
import org.eclipse.cdt.internal.core.util.LRUCache;
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;
/**
* An LRU cache of <code>CElements</code>.
*
* This class is similar to the JDT ElementCache class.
*/
public class ElementCache extends OverflowingLRUCache {
/**
* Constructs a new element cache of the given size.
*/
public ElementCache(int size) {
super(size);
}
/**
* Constructs a new element cache of the given size.
*/
public ElementCache(int size, int overflow) {
super(size, overflow);
}
/**
* Returns true if the element is successfully closed and
* removed from the cache, otherwise false.
*
* <p>NOTE: this triggers an external removal of this element
* by closing the element.
*/
protected boolean close(LRUCacheEntry entry) {
ICOpenable element = (ICOpenable) entry._fKey;
try {
if (element.hasUnsavedChanges()) {
return false;
} /*else {
// We must close an entire JarPackageFragmentRoot at once.
if (element instanceof JarPackageFragment) {
JarPackageFragment packageFragment= (JarPackageFragment) element;
JarPackageFragmentRoot root = (JarPackageFragmentRoot) packageFragment.getParent();
root.close();
}*/ else {
element.close();
}
return true;
// }
} catch (CModelException npe) {
return false;
}
}
/**
* Returns a new instance of the reciever.
*/
protected LRUCache newInstance(int size, int overflow) {
return new ElementCache(size, overflow);
}
}

View file

@ -0,0 +1,259 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICOpenable;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* A buffer contains the text contents of a resource. It is not language-specific.
* The contents may be in the process of being edited, differing from the actual contents of the
* underlying resource. A buffer has an owner, which is an
* <code>IOpenable</code>. If a buffer does not have an underlying resource,
* saving the buffer has no effect. Buffers can be read-only.
* <p>
* This interface is similar to the JDT IBuffer interface.
*/
public interface IBuffer {
/**
* Adds the given listener for changes to this buffer.
* Has no effect if an identical listener is already registered or if the buffer
* is closed.
*
* @param listener the listener of buffer changes
*/
public void addBufferChangedListener(IBufferChangedListener listener);
/**
* Appends the given character array to the contents of the buffer.
* This buffer will now have unsaved changes.
* Any client can append to the contents of the buffer, not just the owner of the buffer.
* Reports a buffer changed event.
* <p>
* Has no effect if this buffer is read-only.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param text the given character array to append to contents of the buffer
*/
public void append(char[] text);
/**
* Appends the given string to the contents of the buffer.
* This buffer will now have unsaved changes.
* Any client can append to the contents of the buffer, not just the owner of the buffer.
* Reports a buffer changed event.
* <p>
* Has no effect if this buffer is read-only.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param text the <code>String</code> to append to the contents of the buffer
*/
public void append(String text);
/**
* Closes the buffer. Any unsaved changes are lost. Reports a buffer changed event
* with a 0 offset and a 0 length. When this event is fired, the buffer should already
* be closed.
* <p>
* Further operations on the buffer are not allowed, except for close. If an
* attempt is made to close an already closed buffer, the second attempt has no effect.
*/
public void close();
/**
* Returns the character at the given position in this buffer.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param position a zero-based source offset in this buffer
* @return the character at the given position in this buffer
*/
public char getChar(int position);
/**
* Returns the contents of this buffer as a character array, or <code>null</code> if
* the buffer has not been initialized.
* <p>
* Callers should make no assumption about whether the returned character array
* is or is not the genuine article or a copy. In other words, if the client
* wishes to change this array, they should make a copy. Likewise, if the
* client wishes to hang on to the array in its current state, they should
* make a copy.
* </p>
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @return the characters contained in this buffer
*/
public char[] getCharacters();
/**
* Returns the contents of this buffer as a <code>String</code>. Like all strings,
* the result is an immutable value object., It can also answer <code>null</code> if
* the buffer has not been initialized.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @return the contents of this buffer as a <code>String</code>
*/
public String getContents();
/**
* Returns number of characters stored in this buffer.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @return the number of characters in this buffer
*/
public int getLength();
/**
* Returns the resource element owning of this buffer.
*
* @return the resource element owning this buffer
*/
public ICOpenable getOwner();
/**
* Returns the given range of text in this buffer.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param offset the zero-based starting offset
* @param length the number of characters to retrieve
* @return the given range of text in this buffer
*/
public String getText(int offset, int length);
/**
* Returns the underlying resource for which this buffer was opened,
* or <code>null</code> if this buffer was not opened on a resource.
*
* @return the underlying resource for this buffer, or <code>null</code>
* if none.
*/
public IResource getUnderlyingResource();
/**
* Returns whether this buffer has been modified since it
* was opened or since it was last saved.
* If a buffer does not have an underlying resource, this method always
* returns <code>true</code>.
*
* @return a <code>boolean</code> indicating presence of unsaved changes (in
* the absence of any underlying resource, it will always return <code>true</code>).
*/
public boolean hasUnsavedChanges();
/**
* Returns whether this buffer has been closed.
*
* @return a <code>boolean</code> indicating whether this buffer is closed.
*/
public boolean isClosed();
/**
* Returns whether this buffer is read-only.
*
* @return a <code>boolean</code> indicating whether this buffer is read-only
*/
public boolean isReadOnly();
/**
* Removes the given listener from this buffer.
* Has no affect if an identical listener is not registered or if the buffer is closed.
*
* @param listener the listener
*/
public void removeBufferChangedListener(IBufferChangedListener listener);
/**
* Replaces the given range of characters in this buffer with the given text.
* <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
* <code>length</code> must not be negative.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param position the zero-based starting position of the affected text range in this buffer
* @param length the length of the affected text range in this buffer
* @param text the replacing text as a character array
*/
public void replace(int position, int length, char[] text);
/**
* Replaces the given range of characters in this buffer with the given text.
* <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
* <code>length</code> must not be negative.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param position the zero-based starting position of the affected text range in this buffer
* @param length the length of the affected text range in this buffer
* @param text the replacing text as a <code>String</code>
*/
public void replace(int position, int length, String text);
/**
* Saves the contents of this buffer to its underlying resource. If
* successful, this buffer will have no unsaved changes.
* The buffer is left open. Saving a buffer with no unsaved
* changes has no effect - the underlying resource is not changed.
* If the buffer does not have an underlying resource or is read-only, this
* has no effect.
* <p>
* The <code>force</code> parameter controls how this method deals with
* cases where the workbench is not completely in sync with the local file system.
* If <code>false</code> is specified, this method will only attempt
* to overwrite a corresponding file in the local file system provided
* it is in sync with the workbench. This option ensures there is no
* unintended data loss; it is the recommended setting.
* However, if <code>true</code> is specified, an attempt will be made
* to write a corresponding file in the local file system,
* overwriting any existing one if need be.
* In either case, if this method succeeds, the resource will be marked
* as being local (even if it wasn't before).
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param progress the progress monitor to notify
* @param force a <code> boolean </code> flag indicating how to deal with resource
* inconsistencies.
*
* @exception CModelException if an error occurs writing the buffer to
* the underlying resource
*
* @see org.eclipse.core.resources.IFile#setContents(java.io.InputStream, boolean, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public void save(IProgressMonitor progress, boolean force) throws CModelException;
/**
* Sets the contents of this buffer to the given character array.
* This buffer will now have unsaved changes.
* Any client can set the contents of the buffer, not just the owner of the buffer.
* Reports a buffer changed event.
* <p>
* Equivalent to <code>replace(0,getLength(),contents)</code>.
* </p>
* <p>
* Has no effect if this buffer is read-only.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param contents the new contents of this buffer as a character array
*/
public void setContents(char[] contents);
/**
* Sets the contents of this buffer to the given <code>String</code>.
* This buffer will now have unsaved changes.
* Any client can set the contents of the buffer, not just the owner of the buffer.
* Reports a buffer changed event.
* <p>
* Equivalent to <code>replace(0,getLength(),contents)</code>.
* </p>
* <p>
* Has no effect if this buffer is read-only.
* <p>
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
*
* @param contents the new contents of this buffer as a <code>String</code>
*/
public void setContents(String contents);
}

View file

@ -0,0 +1,32 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
/**
* A listener, which gets notified when the contents of a specific buffer
* have changed, or when the buffer is closed.
* When a buffer is closed, the listener is notified <em>after</em> the buffer has been closed.
* A listener is not notified when a buffer is saved.
* <p>
* This interface may be implemented by clients.
* </p>
*
* This interface is similar to the JDT IBufferChangedListener interface
*/
public interface IBufferChangedListener {
/**
* Notifies that the given event has occurred.
*
* @param event the change event
*/
public void bufferChanged(BufferChangedEvent event);
}

View file

@ -0,0 +1,35 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.core.model.ICOpenable;
/**
* A factory that creates <code>IBuffer</code>s for CFiles.
* <p>
* This interface may be implemented by clients.
* </p>
*
* This interface is similar to the JDT IBufferFactory interface.
*/
public interface IBufferFactory {
/**
* Creates a buffer for the given owner.
* The new buffer will be initialized with the contents of the owner
* if and only if it was not already initialized by the factory (a buffer is uninitialized if
* its content is <code>null</code>).
*
* @param owner the owner of the buffer
* @see IBuffer
*/
IBuffer createBuffer(ICOpenable owner);
}

View file

@ -0,0 +1,129 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* <p> A working copy of a C element acts just like a regular element (handle),
* except it is not attached to an underlying resource. A working copy is not
* visible to the rest of the C model. Changes in a working copy's buffer are
* not realized in a resource. To bring the C model up-to-date with a working
* copy's contents, an explicit commit must be performed on the working copy.
* Other operations performed on a working copy update the contents of the
* working copy's buffer but do not commit the contents of the working copy.
* </p>
* <p>
* Note: The contents of a working copy is determined when a working
* copy is created, based on the current content of the element the working
* copy is created from. If a working copy is an <code>ICFile</code> and is
* explicitly closed, the working copy's buffer will be thrown away. However,
* clients should not explicitly open and close working copies.
* </p>
* <p>
* The client that creates a working copy is responsible for
* destroying the working copy. The C model will never automatically destroy or
* close a working copy. (Note that destroying a working copy does not commit it
* to the model, it only frees up the memory occupied by the element). After a
* working copy is destroyed, the working copy cannot be accessed again. Non-
* handle methods will throw a <code>CModelException</code> indicating the
* C element does not exist.
* </p>
* <p>
* A working copy cannot be created from another working copy.
* Calling <code>getWorkingCopy</code> on a working copy returns the receiver.
* </p>
*/
public interface IWorkingCopy extends ITranslationUnit{
/**
* Commits the contents of this working copy to its original element
* and underlying resource, bringing the C model up-to-date with the current
* contents of the working copy.
*
* <p>It is possible that the contents of the original resource have changed
* since this working copy was created, in which case there is an update conflict.
* The value of the <code>force</code> parameter effects the resolution of
* such a conflict:<ul>
* <li> <code>true</code> - in this case the contents of this working copy are applied to
* the underlying resource even though this working copy was created before
* a subsequent change in the resource</li>
* <li> <code>false</code> - in this case a <code>CModelException</code> is
* thrown</li>
* </ul>
*/
void commit(boolean force, IProgressMonitor monitor) throws CModelException;
/**
* Destroys this working copy, closing its buffer and discarding
* its structure. Subsequent attempts to access non-handle information
* for this working copy will result in <code>CModelException</code>s. Has
* no effect if this element is not a working copy.
* <p>
* If this working copy is shared, it is destroyed only when the number of calls to
* <code>destroy()</code> is the same as the number of calls to <code>
* getSharedWorkingCopy(IProgressMonitor, IBufferFactory)</code>.
* A REMOVED CElementDelta is then reported on this working copy.
*/
void destroy();
/**
* Returns the original element this working copy was created from,
* or <code>null</code> if this is not a working copy.
*/
ITranslationUnit getOriginalElement();
/**
* Returns whether this working copy's original element's content
* has not changed since the inception of this working copy.
*
* @return true if this working copy's original element's content
* has not changed since the inception of this working copy, false otherwise
*/
boolean isBasedOn(IResource resource);
/**
* Reconciles the contents of this working copy.
* It performs the reconciliation by locally caching the contents of
* the working copy, updating the contents, then creating a delta
* over the cached contents and the new contents, and finally firing
* this delta.
* <p>
* If the working copy hasn't changed, then no problem will be detected,
* this is equivalent to <code>IWorkingCopy#reconcile(false, null)</code>.
* <p>
*/
IMarker[] reconcile() throws CModelException;
/**
* Reconciles the contents of this working copy.
* It performs the reconciliation by locally caching the contents of
* the working copy, updating the contents, then creating a delta
* over the cached contents and the new contents, and finally firing
* this delta.
* <p>
* The boolean argument allows to force problem detection even if the
* working copy is already consistent.
*/
void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws CModelException;
/**
* Restores the contents of this working copy to the current contents of
* this working copy's original element. Has no effect if this element
* is not a working copy.
*/
void restore() throws CModelException;
}

View file

@ -5,15 +5,15 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import java.util.ArrayList;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IParent;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IParent;
import org.eclipse.cdt.core.model.CModelException;
public abstract class Parent extends CElement implements IParent {
protected IResource resource;
@ -64,6 +64,24 @@ public abstract class Parent extends CElement implements IParent {
return getElementInfo().getChildren();
}
/**
* Gets the children of a certain type
* @param type
* @return ArrayList
*/
public ArrayList getChildrenOfType(int type){
ICElement[] children = getChildren();
int size = children.length;
ArrayList list = new ArrayList(size);
for (int i = 0; i < size; ++i) {
CElement elt = (CElement)children[i];
if (elt.getElementType() == type) {
list.add(elt);
}
}
return list;
}
public boolean hasChildren () {
return getElementInfo().hasChildren();
}

View file

@ -5,16 +5,16 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICOpenable;
import org.eclipse.cdt.core.model.ISourceManipulation;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.ISourceManipulation;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.CModelException;
/**
* Abstract class for C elements which implement ISourceReference.
*/
@ -105,6 +105,21 @@ public class SourceManipulation extends Parent implements ISourceManipulation, I
return null;
}
/**
* Returns the first parent of the element that is an instance of
* ICOpenable.
*/
public ICOpenable getOpenableParent() {
ICElement current = getParent();
while (current != null){
if (current instanceof ICOpenable){
return (ICOpenable) current;
}
current = current.getParent();
}
return null;
}
/**
* @see ISourceReference
*/

View file

@ -7,21 +7,25 @@ package org.eclipse.cdt.internal.core.model;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IInclude;
import org.eclipse.cdt.core.model.IParent;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IUsing;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IInclude;
import org.eclipse.cdt.core.model.IUsing;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.CModelException;
/**
* @see ITranslationUnit
*/
public class TranslationUnit extends CFile implements ITranslationUnit {
@ -180,4 +184,259 @@ public class TranslationUnit extends CFile implements ITranslationUnit {
protected CElementInfo createElementInfo () {
return new TranslationUnitInfo(this);
}
/**
* @see org.eclipse.cdt.internal.core.model.CFile#buildStructure(CFileInfo, IProgressMonitor)
*/
protected void buildStructure(CFileInfo info, IProgressMonitor monitor) throws CModelException {
if (monitor != null && monitor.isCanceled()) return;
// remove existing (old) infos
removeInfo();
HashMap newElements = new HashMap(11);
info.setIsStructureKnown(generateInfos(info, monitor, newElements, getResource()));
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().remove(this);
for (Iterator iter = newElements.keySet().iterator(); iter.hasNext();) {
ICElement key = (ICElement) iter.next();
Object value = newElements.get(key);
CModelManager.getDefault().putInfo(key, value);
}
// problem detection
if (monitor != null && monitor.isCanceled()) return;
//IProblemRequestor problemRequestor = this.getProblemRequestor();
//if (problemRequestor != null && problemRequestor.isActive()){
// problemRequestor.beginReporting();
// CompilationUnitProblemFinder.process(this, problemRequestor, monitor);
// problemRequestor.endReporting();
//}
// add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
// to be flushed. Might lead to performance issues.
CModelManager.getDefault().putInfo(this, info);
}
/**
* Returns true if this handle represents the same Java element
* as the given handle.
*
* <p>Compilation units must also check working copy state;
*
* @see Object#equals(java.lang.Object)
*/
public boolean equals(Object o) {
return super.equals(o) && !((ITranslationUnit)o).isWorkingCopy();
}
/**
* @see IWorkingCopy#findSharedWorkingCopy(IBufferFactory)
*/
public IWorkingCopy findSharedWorkingCopy(IBufferFactory factory) {
// if factory is null, default factory must be used
if (factory == null) factory = BufferManager.getDefaultBufferManager();
// In order to be shared, working copies have to denote the same translation unit
// AND use the same buffer factory.
// Assuming there is a little set of buffer factories, then use a 2 level Map cache.
Map sharedWorkingCopies = CModelManager.getDefault().sharedWorkingCopies;
Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(factory);
if (perFactoryWorkingCopies == null) return null;
return (WorkingCopy)perFactoryWorkingCopies.get(this);
}
/**
* To be removed with the new model builder in place
* @param newElements
* @param element
*/
private void getNewElements(Map newElements, CElement element){
Object info = element.getElementInfo();
if(info != null){
if(element instanceof IParent){
ICElement[] children = ((CElementInfo)info).getChildren();
int size = children.length;
for (int i = 0; i < size; ++i) {
CElement child = (CElement) children[i];
getNewElements(newElements, child);
}
}
}
newElements.put(element, info);
}
/**
* @see org.eclipse.cdt.internal.core.model.CResource#generateInfos(CResourceInfo, IProgressMonitor, Map, IResource)
*/
protected boolean generateInfos(CResourceInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws CModelException {
// put the info now, because getting the contents requires it
CModelManager.getDefault().putInfo(this, info);
TranslationUnitInfo unitInfo = (TranslationUnitInfo) info;
// generate structure
this.parse();
// this is temporary until the New Model Builder is implemented
getNewElements(newElements, this);
///////////////////////////////////////////////////////////////
if (isWorkingCopy()) {
ITranslationUnit original = (ITranslationUnit) ((IWorkingCopy)this).getOriginalElement();
// might be IResource.NULL_STAMP if original does not exist
unitInfo.fTimestamp = ((IFile) original.getResource()).getModificationStamp();
}
return unitInfo.isStructureKnown();
}
/**
* @see org.eclipse.cdt.core.model.ITranslationUnit#getContents()
*/
public char[] getContents() {
try {
IBuffer buffer = this.getBuffer();
return buffer == null ? null : buffer.getCharacters();
} catch (CModelException e) {
return new char[0];
}
}
/**
* @see org.eclipse.cdt.core.model.ITranslationUnit#getSharedWorkingCopy(IProgressMonitor, IBufferFactory)
*/
public IWorkingCopy getSharedWorkingCopy(IProgressMonitor monitor,IBufferFactory factory)
throws CModelException {
// if factory is null, default factory must be used
if (factory == null) factory = BufferManager.getDefaultBufferManager();
CModelManager manager = CModelManager.getDefault();
// In order to be shared, working copies have to denote the same translation unit
// AND use the same buffer factory.
// Assuming there is a little set of buffer factories, then use a 2 level Map cache.
Map sharedWorkingCopies = manager.sharedWorkingCopies;
Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(factory);
if (perFactoryWorkingCopies == null){
perFactoryWorkingCopies = new HashMap();
sharedWorkingCopies.put(factory, perFactoryWorkingCopies);
}
WorkingCopy workingCopy = (WorkingCopy)perFactoryWorkingCopies.get(this);
if (workingCopy != null) {
workingCopy.useCount++;
return workingCopy;
} else {
workingCopy = (WorkingCopy)this.getWorkingCopy(monitor, factory);
perFactoryWorkingCopies.put(this, workingCopy);
// report added java delta
// CElementDelta delta = new CElementDelta(this.getCModel());
// delta.added(workingCopy);
// manager.fire(delta, CModelManager.DEFAULT_CHANGE_EVENT);
return workingCopy;
}
}
/**
*
* @see org.eclipse.cdt.core.model.ITranslationUnit#getWorkingCopy()
*/
public IWorkingCopy getWorkingCopy()throws CModelException{
return this.getWorkingCopy(null, null);
}
/**
*
* @see org.eclipse.cdt.core.model.ITranslationUnit#getWorkingCopy()
*/
public IWorkingCopy getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory)throws CModelException{
WorkingCopy workingCopy = new WorkingCopy(getParent(), getFile(), factory);
// open the working copy now to ensure contents are that of the current state of this element
workingCopy.open(monitor);
return workingCopy;
}
/**
* Returns true if this element may have an associated source buffer.
*/
protected boolean hasBuffer() {
return true;
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#isConsistent()
*/
public boolean isConsistent() throws CModelException {
return CModelManager.getDefault().getElementsOutOfSynchWithBuffers().get(this) == null;
}
/**
* @see org.eclipse.cdt.internal.core.model.CResource#isSourceElement()
*/
protected boolean isSourceElement() {
return true;
}
/**
* @see org.eclipse.cdt.core.model.ITranslationUnit#isWorkingCopy()
*/
public boolean isWorkingCopy() {
return false;
}
/**
* @see org.eclipse.cdt.core.model.ICOpenable#makeConsistent(IProgressMonitor)
*/
public void makeConsistent(IProgressMonitor pm) throws CModelException {
if (!isConsistent()) {
// create a new info and make it the current info
CFileInfo info = (CFileInfo) createElementInfo();
buildStructure(info, pm);
}
}
/**
* @see org.eclipse.cdt.internal.core.model.CResource#openBuffer(IProgressMonitor)
*/
protected IBuffer openBuffer(IProgressMonitor pm) throws CModelException {
// create buffer - translation units only use default buffer factory
BufferManager bufManager = getBufferManager();
IBuffer buffer = getBufferFactory().createBuffer(this);
if (buffer == null)
return null;
// set the buffer source
if (buffer.getCharacters() == null){
IResource file = this.getResource();
if (file != null && file.getType() == IResource.FILE) {
buffer.setContents(Util.getResourceContentsAsCharArray((IFile)file));
}
}
// add buffer to buffer cache
bufManager.addBuffer(buffer);
// listen to buffer changes
buffer.addBufferChangedListener(this);
return buffer;
}
/**
* Parse the buffer contents of this element.
*/
public void parse(){
try{
getTranslationUnitInfo().parse(this.getBuffer().getContents());
} catch (CModelException e){
// error getting the buffer
}
}
}

View file

@ -5,21 +5,27 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.StringBufferInputStream;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.internal.core.parser.Parser;
import org.eclipse.cdt.internal.parser.CStructurizer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
/**
* The Element Info of a Translation Unit.
*/
class TranslationUnitInfo extends CFileInfo {
/**
* Timestamp of original resource at the time this element
* was opened or last updated.
*/
protected long fTimestamp;
protected TranslationUnitInfo (CElement element) {
super(element);
}
@ -29,27 +35,8 @@ class TranslationUnitInfo extends CFileInfo {
}
protected ICElement [] getChildren() {
if (hasChanged()) {
InputStream in = null;
try {
IResource res = getElement().getUnderlyingResource();
if (res != null && res.getType() == IResource.FILE) {
in = ((IFile)res).getContents();
parse(in);
}
} catch (CoreException e) {
//e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
return super.getChildren();
// CHECKPOINT: replacing the parsing done here before
return fChildren;
}
protected void parse(InputStream in) {
@ -70,6 +57,15 @@ class TranslationUnitInfo extends CFileInfo {
}
}
protected void parse(String buf) {
// CHECKPOINT: Parsing a string using the StringBufferInputStream
// FIXME: quick fix for the IBinary which uses fake translationUnit
if (buf != null) {
StringBufferInputStream in = new StringBufferInputStream (buf);
parse (in);
}
}
/* Overide the SourceManipulation for the range. */
protected ISourceRange getSourceRange() {
IPath location = ((TranslationUnit)getElement()).getLocation();

View file

@ -5,14 +5,19 @@ package org.eclipse.cdt.internal.core.model;
* All Rights Reserved.
*/
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
public class Util {
@ -114,4 +119,51 @@ public class Util {
boolean force = true;
file.setContents(stream, force, true, null); // record history
}
/**
* Returns the given file's contents as a character array.
*/
public static char[] getResourceContentsAsCharArray(IFile file) throws CModelException {
return getResourceContentsAsCharArray(file, null);
}
public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws CModelException {
InputStream stream= null;
try {
stream = new BufferedInputStream(file.getContents(true));
} catch (CoreException e) {
throw new CModelException(e, ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
}
try {
return Util.getInputStreamAsCharArray(stream, -1, encoding);
} catch (IOException e) {
throw new CModelException(e, ICModelStatusConstants.IO_EXCEPTION);
} finally {
try {
stream.close();
} catch (IOException e) {
}
}
}
/*
* Add a log entry
*/
public static void log(Throwable e, String message) {
IStatus status= new Status(
IStatus.ERROR,
CCorePlugin.getDefault().getDescriptor().getUniqueIdentifier(),
IStatus.ERROR,
message,
e);
CCorePlugin.getDefault().getLog().log(status);
}
/**
* Combines two hash codes to make a new one.
*/
public static int combineHashCodes(int hashCode1, int hashCode2) {
return hashCode1 * 17 + hashCode2;
}
}

View file

@ -0,0 +1,379 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
import java.io.ByteArrayInputStream;
import java.util.Map;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* Implementation of a working copy translation unit. A working copy maintains
* the timestamp of the resource it was created from.
*/
public class WorkingCopy extends TranslationUnit implements IWorkingCopy {
/**
* If set, this is the factory that will be used to create the buffer.
*/
protected IBufferFactory bufferFactory;
/**
* A counter of the number of time clients have asked for this
* working copy. It is set to 1, if the working
* copy is not managed. When destroyed, this counter is
* set to 0. Once destroyed, this working copy cannot be opened
* and non-handle info can not be accessed. This is
* never true if this translation unit is not a working copy.
*/
protected int useCount = 1;
/**
* Creates a working copy of this element
*/
public WorkingCopy(ICElement parent, IFile file, IBufferFactory bufferFactory) {
super(parent, file);
this.bufferFactory =
bufferFactory == null ?
getBufferManager() :
bufferFactory;
}
public WorkingCopy(ICElement parent, IPath path, IBufferFactory bufferFactory) {
super(parent, path);
this.bufferFactory =
bufferFactory == null ?
getBufferManager() :
bufferFactory;
}
/**
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#commit(boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public void commit(boolean force, IProgressMonitor monitor)
throws CModelException {
ITranslationUnit original = (ITranslationUnit)this.getOriginalElement();
if (original.exists()) {
CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
runOperation(op, monitor);
} else {
String contents = this.getSource();
if (contents == null) return;
try {
byte[] bytes = contents.getBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
IFile originalRes = (IFile)original.getResource();
if (originalRes.exists()) {
originalRes.setContents(
stream,
force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
null);
} else {
originalRes.create(
stream,
force,
monitor);
}
} catch (CoreException e) {
throw new CModelException(e);
}
}
}
/**
* Returns a new element info for this element.
*/
protected CElementInfo createElementInfo() {
return new WorkingCopyInfo(this);
}
/**
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#destroy()
*/
public void destroy() {
if (--this.useCount > 0) {
return;
}
try {
close();
// if original element is not on classpath flush it from the cache
ICElement originalElement = this.getOriginalElement();
if (!this.getParent().exists()) {
((TranslationUnit)originalElement).close();
}
// remove working copy from the cache
CModelManager manager = CModelManager.getDefault();
// In order to be shared, working copies have to denote the same compilation unit
// AND use the same buffer factory.
// Assuming there is a little set of buffer factories, then use a 2 level Map cache.
Map sharedWorkingCopies = manager.sharedWorkingCopies;
Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(this.bufferFactory);
if (perFactoryWorkingCopies != null){
if (perFactoryWorkingCopies.remove(originalElement) != null) {
// report removed java delta
//CElementDelta delta = new CElementDelta(this.getCoreModel());
//delta.removed(this);
//manager.fire(delta, CModelManager.DEFAULT_CHANGE_EVENT);
}
}
} catch (CModelException e) {
// do nothing
}
}
/**
* @see org.eclipse.cdt.core.model.ICElement#exists()
*/
public boolean exists() {
// working copy always exists in the model until it is detroyed
return this.useCount != 0;
}
/**
* Answers custom buffer factory
*/
public IBufferFactory getBufferFactory(){
return this.bufferFactory;
}
/**
* Working copies must be identical to be equal.
*
* @see Object#equals
*/
public boolean equals(Object o) {
return this == o;
}
/**
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#getOriginalElement()
*/
public ITranslationUnit getOriginalElement() {
return new TranslationUnit(getParent(), getFile());
}
/**
* @see org.eclipse.cdt.core.model.ITranslationUnit#getSharedWorkingCopy(IProgressMonitor, IBufferFactory)
*/
public IWorkingCopy getSharedWorkingCopy(IProgressMonitor monitor,IBufferFactory factory)
throws CModelException{
return this;
}
/**
* @see org.eclipse.cdt.core.model.ITranslationUnit#getWorkingCopy()
*/
public IWorkingCopy getWorkingCopy() {
return this;
}
/**
* @see IWorkingCopy
*/
public IWorkingCopy getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory){
return this;
}
/**
* @see IWorkingCopy
*/
public boolean isBasedOn(IResource resource) {
if (resource.getType() != IResource.FILE) {
return false;
}
if (this.useCount == 0) {
return false;
}
// if resource got deleted, then #getModificationStamp() will answer IResource.NULL_STAMP, which is always different from the cached
// timestamp
return ((TranslationUnitInfo) getElementInfo()).fTimestamp == ((IFile) resource).getModificationStamp();
}
/**
* @see org.eclipse.cdt.core.model.ITranslationUnit#isWorkingCopy()
*/
public boolean isWorkingCopy() {
return true;
}
/**
* @see ICFile
* @see IWorkingCopy
*
* @exception CModelException attempting to open a read only element for
* something other than navigation or if this is a working copy being
* opened after it has been destroyed.
*/
public void open(IProgressMonitor pm) throws CModelException {
if (this.useCount == 0) { // was destroyed
throw newNotPresentException();
} else {
super.open(pm);
}
}
/**
* @see org.eclipse.cdt.internal.core.model.CFile#openBuffer(IProgressMonitor)
*/
protected IBuffer openBuffer(IProgressMonitor pm) throws CModelException {
if (this.useCount == 0) throw newNotPresentException();
// create buffer - working copies may use custom buffer factory
IBuffer buffer = getBufferFactory().createBuffer(this);
if (buffer == null)
return null;
// set the buffer source if needed
if (buffer.getCharacters() == null){
ITranslationUnit original= (ITranslationUnit)this.getOriginalElement();
IBuffer originalBuffer = null;
try {
originalBuffer = original.getBuffer();
} catch (CModelException e) {
// original element does not exist: create an empty working copy
if (!e.getCModelStatus().doesNotExist()) {
throw e;
}
}
if (originalBuffer != null) {
char[] originalContents = originalBuffer.getCharacters();
if (originalContents != null) {
buffer.setContents((char[])originalContents.clone());
}
} else {
// initialize buffer
buffer.setContents(new char[0]);
}
}
// add buffer to buffer cache
this.getBufferManager().addBuffer(buffer);
// listen to buffer changes
buffer.addBufferChangedListener(this);
return buffer;
}
/**
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#reconcile()
*/
public IMarker[] reconcile() throws CModelException {
reconcile(false, null);
return null;
}
/**
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#reconcile(boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor)
throws CModelException {
if (this.useCount == 0) throw newNotPresentException(); //was destroyed
if (monitor != null){
if (monitor.isCanceled()) return;
monitor.beginTask("element.reconciling", 10); //$NON-NLS-1$
}
boolean wasConsistent = isConsistent();
CElementDeltaBuilder deltaBuilder = null;
try {
// create the delta builder (this remembers the current content of the cu)
if (!wasConsistent){
deltaBuilder = new CElementDeltaBuilder(this);
// update the element infos with the content of the working copy
this.makeConsistent(monitor);
deltaBuilder.buildDeltas();
}
if (monitor != null) monitor.worked(2);
// force problem detection? - if structure was consistent
if (forceProblemDetection && wasConsistent){
if (monitor != null && monitor.isCanceled()) return;
//IProblemRequestor problemRequestor = this.getProblemRequestor();
//if (problemRequestor != null && problemRequestor.isActive()){
// problemRequestor.beginReporting();
// CompilationUnitProblemFinder.process(this, problemRequestor, monitor);
// problemRequestor.endReporting();
//}
}
// fire the deltas
//if (deltaBuilder != null){
// if ((deltaBuilder.delta != null) && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
// CModelManager.getDefault().fire(deltaBuilder.delta, ElementChangedEvent.POST_RECONCILE);
// }
//}
} finally {
if (monitor != null) monitor.done();
}
}
/**
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#restore()
*/
public void restore() throws CModelException{
if (this.useCount == 0) throw newNotPresentException(); //was destroyed
TranslationUnit original = (TranslationUnit) getOriginalElement();
IBuffer buffer = this.getBuffer();
if (buffer == null) return;
buffer.setContents(original.getContents());
updateTimeStamp(original);
makeConsistent(null);
}
/**
* @see org.eclipse.cdt.core.model.ICFile#save(IProgressMonitor, boolean)
*/
public void save(IProgressMonitor pm, boolean force) throws CModelException {
if (isReadOnly()) {
throw new CModelException(new CModelStatus(ICModelStatusConstants.READ_ONLY, this));
}
// computes fine-grain deltas in case the working copy is being reconciled already (if not it would miss one iteration of deltas).
this.reconcile();
}
/**
* @param original
* @throws CModelException
*/
protected void updateTimeStamp(TranslationUnit original) throws CModelException {
long timeStamp =
((IFile) original.getResource()).getModificationStamp();
if (timeStamp == IResource.NULL_STAMP) {
throw new CModelException(
new CModelStatus(ICModelStatusConstants.INVALID_RESOURCE));
}
((TranslationUnitInfo) getElementInfo()).fTimestamp = timeStamp;
}
}

View file

@ -0,0 +1,22 @@
package org.eclipse.cdt.internal.core.model;
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
/**
* The Element Info of a Working Copy.
*/
public class WorkingCopyInfo extends TranslationUnitInfo {
public WorkingCopyInfo (CElement element) {
super(element);
}
}