1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 113518 - Patch to improve performance of CModel at reconcile time.

This commit is contained in:
Doug Schaefer 2006-01-04 20:09:35 +00:00
parent fc68c36469
commit 28af61ba10
8 changed files with 325 additions and 7 deletions

View file

@ -77,6 +77,20 @@ public class ElementChangedEvent extends EventObject {
* @since 2.0
*/
public static final int POST_RECONCILE = 4;
/**
* Event type constant indicating the following:
* Source text is changed somewhere in function body
* No global data affected for any C element
* but element offsets should be recalculated now.
*
* Note: usually, CShifData object is sent with
* this event as ICElementDelta
*
* @see CShiftData
*/
public static final int POST_SHIFT = 5;
/*
* Event type indicating the nature of this event.
* It can be a combination either:

View file

@ -797,6 +797,11 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe
fire(null, eventType);
}
public void fireShift(int offset, int size, int lines) {
ICElementDelta delta = new CShiftData(offset, size, lines);
fire(delta, ElementChangedEvent.POST_SHIFT);
}
/**
* Fire C Model deltas, flushing them after the fact.
* If the firing mode has been turned off, this has no effect.
@ -837,6 +842,9 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe
case ElementChangedEvent.POST_RECONCILE :
fireReconcileDelta(listeners, listenerMask, listenerCount);
break;
case ElementChangedEvent.POST_SHIFT:
fireShiftEvent(deltaToNotify, listeners, listenerMask, listenerCount);
return;
}
}
}
@ -880,6 +888,19 @@ public class CModelManager implements IResourceChangeListener, ICDescriptorListe
}
}
private void fireShiftEvent(ICElementDelta deltaToNotify, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) {
// post change deltas
if (VERBOSE) {
System.out.println("FIRING POST_SHIFT event [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
}
if (deltaToNotify != null) {
this.flush();
notifyListeners(deltaToNotify, ElementChangedEvent.POST_SHIFT, listeners, listenerMask, listenerCount);
}
}
public void notifyListeners(ICElementDelta deltaToNotify, int eventType,
IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) {

View file

@ -0,0 +1,99 @@
/**
*
*/
package org.eclipse.cdt.internal.core.model;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICElementDelta;
import org.eclipse.core.resources.IResourceDelta;
/**
* In this case, no delta for specific element passed
* Instead we'll notify Outline about offsets change.
*/
public class CShiftData implements ICElementDelta {
public int fOffset;
public int fSize;
public int fLines;
public CShiftData(int offset, int size, int lines) {
fOffset = offset;
fSize = size;
fLines = lines;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getAddedChildren()
*/
public ICElementDelta[] getAddedChildren() {
return new ICElementDelta[0];
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getAffectedChildren()
*/
public ICElementDelta[] getAffectedChildren() {
return new ICElementDelta[0];
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getChangedChildren()
*/
public ICElementDelta[] getChangedChildren() {
return new ICElementDelta[0];
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getElement()
*/
public ICElement getElement() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getFlags()
*/
public int getFlags() {
return 0;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getKind()
*/
public int getKind() {
return 0;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getMovedFromElement()
*/
public ICElement getMovedFromElement() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getMovedToElement()
*/
public ICElement getMovedToElement() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getRemovedChildren()
*/
public ICElementDelta[] getRemovedChildren() {
return new ICElementDelta[0];
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.model.ICElementDelta#getResourceDeltas()
*/
public IResourceDelta[] getResourceDeltas() {
return null;
}
public String toString() {
return ("CShiftData: offset=" + fOffset + ", size=" + fSize + ", lines=" + fLines);
}
}

View file

@ -14,12 +14,16 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ElementChangedEvent;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICElementDelta;
import org.eclipse.cdt.core.model.IElementChangedListener;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.model.CShiftData;
import org.eclipse.cdt.internal.core.model.SourceManipulation;
import org.eclipse.cdt.internal.ui.BaseCElementContentProvider;
import org.eclipse.cdt.internal.ui.util.StringMatcher;
import org.eclipse.cdt.ui.PreferenceConstants;
@ -30,6 +34,7 @@ import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.progress.DeferredTreeContentManager;
@ -118,6 +123,43 @@ public class CContentOutlinerProvider extends BaseCElementContentProvider {
}
}
/**
* Called after CEditor contents is changed.
* Existing elements can change their offset and length.
*
* @param offset
* position where source was changed
* @param size
* length of ins
* ertion (negaive for deletion)
*/
public void contentShift(CShiftData sdata) {
try {
ICElement[] el = root.getChildren();
for (int i=0; i< el.length; i++) {
if (!(el[i] instanceof SourceManipulation)) continue;
SourceManipulation sm = (SourceManipulation) el[i];
ISourceRange src = sm.getSourceRange();
int endOffset = src.getStartPos() + src.getLength();
// code BELOW this element changed - do nothing !
if (sdata.fOffset > endOffset) { continue; }
if (sdata.fOffset < src.getStartPos()) {
// code ABOVE this element changed - modify offset
sm.setIdPos(src.getIdStartPos() + sdata.fSize,src.getIdLength());
sm.setPos(src.getStartPos() + sdata.fSize, src.getLength());
sm.setLines(src.getStartLine() + sdata.fLines, src.getEndLine() + sdata.fLines);
} else {
// code INSIDE of this element changed - modify length
sm.setPos(src.getStartPos(), src.getLength() + sdata.fSize);
sm.setLines(src.getStartLine(), src.getEndLine() + sdata.fLines);
}
}
} catch (CModelException e) {}
}
/**
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
@ -239,6 +281,11 @@ public class CContentOutlinerProvider extends BaseCElementContentProvider {
* @see org.eclipse.cdt.core.model.IElementChangedListener#elementChanged(org.eclipse.cdt.core.model.ElementChangedEvent)
*/
public void elementChanged(final ElementChangedEvent e) {
if (e.getType() == ElementChangedEvent.POST_SHIFT && e.getDelta() instanceof CShiftData) {
contentShift((CShiftData)(e.getDelta()));
return;
}
final ICElementDelta delta = findElement(root, e.getDelta());
if (delta != null) {
contentUpdated();

View file

@ -0,0 +1,15 @@
package org.eclipse.cdt.internal.ui.text;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.Reconciler;
public class CReconciler extends Reconciler {
protected void process(DirtyRegion dirtyRegion) {
if(dirtyRegion != null) {
getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE).reconcile(dirtyRegion, null);
}
}
}

View file

@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.ui.text;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IWorkingCopy;
import org.eclipse.cdt.internal.core.model.CModelManager;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.IReconcilingParticipant;
import org.eclipse.cdt.ui.CUIPlugin;
@ -28,12 +29,11 @@ import org.eclipse.ui.texteditor.ITextEditor;
public class CReconcilingStrategy implements IReconcilingStrategy {
private ITextEditor fEditor;
private IWorkingCopyManager fManager;
private IProgressMonitor fProgressMonitor;
private String txt = null;
public CReconcilingStrategy(CEditor editor) {
fEditor= editor;
fManager= CUIPlugin.getDefault().getWorkingCopyManager();
@ -62,10 +62,45 @@ public class CReconcilingStrategy implements IReconcilingStrategy {
/**
* @see IReconcilingStrategy#reconcile(dirtyRegion, region)
* @see IReconcilingStrategy#reconcile(dirtyRegion, reion)
*/
public void reconcile(DirtyRegion dirtyRegion, IRegion region) {
reconcile();
// consistent data needs not further checks !
ITranslationUnit tu = fManager.getWorkingCopy(fEditor.getEditorInput());
if (tu != null && tu.isWorkingCopy()) {
try {
if (tu.isConsistent()) return;
} catch (CModelException e) {}
}
// bug 113518
// local data needs not to be re-parsed
boolean needReconcile = true;
int dOff = dirtyRegion.getOffset();
int dLen = dirtyRegion.getLength();
IDocument doc = fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
if ((doc != null) && (!CWordFinder.isGlobal(doc, dOff))) {
String s = "";
if (dirtyRegion.getType().charAt(2) == 'i') { // insert operation
s = dirtyRegion.getText();
if (!CWordFinder.hasCBraces(s)) {
CModelManager.getDefault().fireShift(dOff, dLen, CWordFinder.countLFs(s));
needReconcile = false;
}
} else { // remove operation
// check whether old document copy is relevant
if (txt != null && (txt.length() == doc.getLength() + dLen)) {
s = txt.substring(dOff, dOff + dLen);
if (!CWordFinder.hasCBraces(s)) {
CModelManager.getDefault().fireShift(dOff, -dLen, -CWordFinder.countLFs(s));
needReconcile = false;
}
}
}
}
if (needReconcile) reconcile();
txt = doc.get(); // save doc copy for further use
}
private void reconcile() {

View file

@ -221,7 +221,7 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration {
*/
public IReconciler getReconciler(ISourceViewer sourceViewer) {
if (fEditor != null && fEditor.isEditable()) {
Reconciler reconciler= new Reconciler() {
Reconciler reconciler= new CReconciler() {
protected void initialProcess() {
// prevent case where getDocument() returns null
// and causes exception in initialProcess()
@ -231,7 +231,7 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration {
}
};
reconciler.setDelay(1000);
reconciler.setIsIncrementalReconciler(false);
// reconciler.setIsIncrementalReconciler(false);
reconciler.setReconcilingStrategy(new CReconcilingStrategy(fEditor), IDocument.DEFAULT_CONTENT_TYPE);
return reconciler;
}

View file

@ -15,12 +15,18 @@ import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
/**
* This is a helper class for the text editor to be able to determine, given a
* particular offset in a document, various candidates segments for things like
* context help, proposals and hovering.
*/
public class CWordFinder {
private static final char CBRACE_L = '{';
private static final char CBRACE_R = '}';
private static final char BRACE_R = ')';
/**
* This method determines for a given offset into a given document what the
* region is which defines the current word. A word is defined as the set of
@ -198,5 +204,86 @@ public class CWordFinder {
return null;
}
/**
* This method will determine whether current offset is contained
* in any function's body or it's outside it.
*
* @param document
* The document to be examined
* @param offset
* The offset into the document
* @return
* <code>true</code> if there is no function body around offset
* <code>false</code> otherwise
*
* @param document
* @param offset
* @return
*/
public static boolean isGlobal(IDocument document, int offset) {
try {
int pos = offset;
int bracketcount = 0;
char c;
//Find left curled bracket from our position
while (pos > 0) {
c = document.getChar(pos--);
if (c == CBRACE_R) {
bracketcount++; // take into account nested blocks
} else if (c == CBRACE_L) {
if (bracketcount-- == 0) {
do {
c = document.getChar(pos--);
if (c == BRACE_R) return false;
} while (Character.isSpace(c));
// container block seems to be not a function or statement body
pos++; // step back one symbol
bracketcount = 0; // let's search for upper block
}
}
}
} catch (BadLocationException x) { /* Ignore */ }
// return true in case of unknown result or exception
return true;
}
/**
* Searches for line feed symbols in string.
* First met '\r' or '\n' is treated as LF symbol
*
* @param s
* string to search in.
* @return number of LFs met.
*/
public static int countLFs (String s) {
int counter = 0;
char lf = 0;
char c;
for (int i=0; i<s.length(); i++) {
c = s.charAt(i);
if (lf == 0) {
if (c == '\n' || c == '\r') {
lf = c;
counter++;
}
} else if (lf == c) counter++;
}
return counter;
}
/**
* Checks whether the string contains any C-block delimiters ( { } )
*
* @param s
* text to check
* @return true if curled brace found.
*/
public static boolean hasCBraces (String s) {
if (s.indexOf(CBRACE_L) > -1 || s.indexOf(CBRACE_R) > -1) return true;
else return false;
}
}