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:
parent
fc68c36469
commit
28af61ba10
8 changed files with 325 additions and 7 deletions
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue