mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 14:42:11 +02:00
Fix for 173872: ASTProvider locked up waiting on a notify()
This commit is contained in:
parent
bea41263df
commit
2dfdde8c56
11 changed files with 685 additions and 389 deletions
|
@ -0,0 +1,200 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Anton Leherbauer (Wind River Systems) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.model.tests;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.IPDOMManager;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||
import org.eclipse.cdt.core.testplugin.CTestPlugin;
|
||||
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
||||
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache;
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
/**
|
||||
* Tests for the {@link ASTCache}.
|
||||
*/
|
||||
public class ASTCacheTests extends BaseTestCase {
|
||||
private static int fgReconcilerCount;
|
||||
|
||||
public class MockReconciler extends Thread {
|
||||
private ITranslationUnit fTU;
|
||||
private ASTCache fCache;
|
||||
public volatile boolean fStopped;
|
||||
private IASTTranslationUnit fAST;
|
||||
|
||||
public MockReconciler(ITranslationUnit tu, ASTCache cache) {
|
||||
super("MockReconciler-"+fgReconcilerCount++);
|
||||
fTU= tu;
|
||||
fCache= cache;
|
||||
}
|
||||
public void run() {
|
||||
while (!fStopped) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
fCache.aboutToBeReconciled(fTU);
|
||||
IASTTranslationUnit ast;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
fAST= fCache.createAST(fTU, fIndex, null);
|
||||
fCache.reconciled(fAST, fTU);
|
||||
} catch (InterruptedException exc) {
|
||||
fStopped= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ICProject fProject;
|
||||
private ITranslationUnit fTU1;
|
||||
private ITranslationUnit fTU2;
|
||||
private IIndex fIndex;
|
||||
|
||||
public ASTCacheTests(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
// {source1.cpp}
|
||||
// void foo1() {}
|
||||
// void bar1() {}
|
||||
|
||||
// {source2.cpp}
|
||||
// void foo2() {}
|
||||
// void bar2() {}
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite= new TestSuite(ASTCacheTests.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
fProject= createProject("ASTCacheTest");
|
||||
assertNotNull(fProject);
|
||||
IFile file1= createFile(fProject.getProject(), "source1.cpp", readTaggedComment("source1.cpp"));
|
||||
assertNotNull(file1);
|
||||
fTU1= CProjectHelper.findTranslationUnit(fProject, file1.getName());
|
||||
assertNotNull(fTU1);
|
||||
IFile file2= createFile(fProject.getProject(), "source2.cpp", readTaggedComment("source2.cpp"));
|
||||
assertNotNull(file2);
|
||||
fTU2= CProjectHelper.findTranslationUnit(fProject, file2.getName());
|
||||
assertNotNull(fTU2);
|
||||
CCorePlugin.getIndexManager().joinIndexer(5000, new NullProgressMonitor());
|
||||
fIndex= CCorePlugin.getIndexManager().getIndex(fProject);
|
||||
fIndex.acquireReadLock();
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
if (fIndex != null) {
|
||||
fIndex.releaseReadLock();
|
||||
}
|
||||
if (fProject != null) {
|
||||
CProjectHelper.delete(fProject);
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected ICProject createProject(final String name) throws CoreException {
|
||||
return CProjectHelper.createCProject(name, null, IPDOMManager.ID_FAST_INDEXER);
|
||||
}
|
||||
|
||||
protected String readTaggedComment(String tag) throws Exception {
|
||||
return TestSourceReader.readTaggedComment(CTestPlugin.getDefault().getBundle(), "model", getClass(), tag);
|
||||
}
|
||||
|
||||
protected IFile createFile(IContainer container, String fileName, String contents) throws Exception {
|
||||
return TestSourceReader.createFile(container, new Path(fileName), contents);
|
||||
}
|
||||
|
||||
public void testASTCache() throws Exception {
|
||||
checkActiveElement();
|
||||
checkSingleThreadAccess();
|
||||
checkAccessWithBackgroundReconciler();
|
||||
}
|
||||
|
||||
private void checkActiveElement() throws Exception {
|
||||
ASTCache cache= new ASTCache();
|
||||
assertFalse(cache.isActiveElement(fTU1));
|
||||
assertFalse(cache.isActiveElement(fTU2));
|
||||
cache.setActiveElement(fTU1);
|
||||
assertTrue(cache.isActiveElement(fTU1));
|
||||
assertFalse(cache.isActiveElement(fTU2));
|
||||
cache.setActiveElement(fTU2);
|
||||
assertFalse(cache.isActiveElement(fTU1));
|
||||
assertTrue(cache.isActiveElement(fTU2));
|
||||
}
|
||||
|
||||
private void checkSingleThreadAccess() throws Exception {
|
||||
ASTCache cache= new ASTCache();
|
||||
cache.setActiveElement(fTU1);
|
||||
IASTTranslationUnit ast;
|
||||
ast= cache.getAST(fTU1, fIndex, false, null);
|
||||
assertNull(ast);
|
||||
IProgressMonitor npm= new NullProgressMonitor();
|
||||
npm.setCanceled(true);
|
||||
ast= cache.getAST(fTU1, fIndex, true, npm);
|
||||
assertNull(ast);
|
||||
npm.setCanceled(false);
|
||||
ast= cache.getAST(fTU1, fIndex, true, npm);
|
||||
assertNotNull(ast);
|
||||
}
|
||||
|
||||
private void checkAccessWithBackgroundReconciler() throws Exception {
|
||||
ASTCache cache= new ASTCache();
|
||||
cache.setActiveElement(fTU1);
|
||||
MockReconciler reconciler1= new MockReconciler(fTU1, cache);
|
||||
MockReconciler reconciler2= null;
|
||||
try {
|
||||
assertFalse(cache.isReconciling(fTU1));
|
||||
reconciler1.start();
|
||||
synchronized (reconciler1) {
|
||||
reconciler1.wait();
|
||||
}
|
||||
IASTTranslationUnit ast;
|
||||
ast= cache.getAST(fTU1, fIndex, true, null);
|
||||
assertNotNull(ast);
|
||||
assertSame(ast, reconciler1.fAST);
|
||||
|
||||
// change active element
|
||||
cache.setActiveElement(fTU2);
|
||||
reconciler2= new MockReconciler(fTU2, cache);
|
||||
reconciler2.start();
|
||||
synchronized (reconciler2) {
|
||||
reconciler2.wait();
|
||||
}
|
||||
ast= cache.getAST(fTU2, fIndex, true, null);
|
||||
assertNotNull(ast);
|
||||
assertSame(ast, reconciler2.fAST);
|
||||
} finally {
|
||||
reconciler1.fStopped= true;
|
||||
reconciler1.join(1000);
|
||||
if (reconciler2 != null) {
|
||||
reconciler2.fStopped= true;
|
||||
reconciler2.join(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -47,7 +47,7 @@ public class AllCoreTests {
|
|||
suite.addTest(FailedDeclaratorsTest.suite());
|
||||
suite.addTest(CPathEntryTest.suite());
|
||||
suite.addTest(CConfigurationDescriptionReferenceTests.suite());
|
||||
|
||||
suite.addTest(ASTCacheTests.suite());
|
||||
return suite;
|
||||
|
||||
}
|
||||
|
|
|
@ -35,3 +35,6 @@ org.eclipse.cdt.core/debug/indexer/problems=false
|
|||
|
||||
# Code formatter debugging
|
||||
org.eclipse.cdt.core/debug/formatter=false
|
||||
|
||||
# ASTCache debugging
|
||||
org.eclipse.cdt.core/debug/ASTCache=false
|
||||
|
|
|
@ -0,0 +1,427 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others. All rights reserved.
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
|
||||
* and is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors: Anton Leherbauer (Wind River Systems) - initial API and
|
||||
* implementation
|
||||
******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.ISafeRunnable;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.SafeRunner;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
||||
/**
|
||||
* Provides a shared AST of a single translation unit at a time.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ASTCache {
|
||||
/**
|
||||
* Tells whether this class is in debug mode.
|
||||
*/
|
||||
private static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.cdt.core/debug/ASTCache")); //$NON-NLS-1$//$NON-NLS-2$
|
||||
private static final String DEBUG_PREFIX= "[ASTCache] "; //$NON-NLS-1$
|
||||
|
||||
/** Full parse mode (no PDOM) */
|
||||
public static int PARSE_MODE_FULL= 0;
|
||||
/** Fast parse mode (use PDOM) */
|
||||
public static int PARSE_MODE_FAST= ITranslationUnit.AST_SKIP_INDEXED_HEADERS;
|
||||
|
||||
/**
|
||||
* Do something with an AST.
|
||||
*
|
||||
* @see #runOnAST(IASTTranslationUnit)
|
||||
*/
|
||||
public static interface ASTRunnable {
|
||||
/**
|
||||
* Do something with the given AST.
|
||||
*
|
||||
* @param ast the translation unit AST, may be <code>null</code>
|
||||
* @return a status object
|
||||
*/
|
||||
IStatus runOnAST(IASTTranslationUnit ast);
|
||||
}
|
||||
|
||||
private final int fParseMode;
|
||||
private final Object fCacheMutex= new Object();
|
||||
|
||||
/** The active translation unit for which to cache the AST */
|
||||
private ITranslationUnit fActiveTU;
|
||||
/** The cached AST if any */
|
||||
private IASTTranslationUnit fAST;
|
||||
/**
|
||||
* The timestamp of the last index write access at the time
|
||||
* the AST got cached. A cached AST becomes invalid on any index
|
||||
* write access afterwards.
|
||||
*/
|
||||
private long fLastWriteOnIndex;
|
||||
/** Inidicates whether the AST is currenty being computed */
|
||||
private volatile boolean fIsReconciling;
|
||||
|
||||
/**
|
||||
* Create a new AST cache.
|
||||
*/
|
||||
public ASTCache() {
|
||||
fParseMode= PARSE_MODE_FAST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared translation unit AST for the given
|
||||
* translation unit.
|
||||
* <p>
|
||||
* Clients are not allowed to modify the AST and must
|
||||
* hold a read lock prior to calling this method and continue
|
||||
* to hold the lock as long as the AST is being used.
|
||||
* </p>
|
||||
*
|
||||
* @param tUnit the translation unit
|
||||
* @param index the index used to create the AST, needs to be read-locked
|
||||
* @param wait if <code>true</code>, wait for AST to be computed (might compute a new AST)
|
||||
* @param progressMonitor the progress monitor or <code>null</code>
|
||||
* @return the AST or <code>null</code> if the AST is not available
|
||||
*/
|
||||
public IASTTranslationUnit getAST(ITranslationUnit tUnit, IIndex index, boolean wait, IProgressMonitor progressMonitor) {
|
||||
if (tUnit == null)
|
||||
return null;
|
||||
|
||||
while (true) {
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
return null;
|
||||
|
||||
final boolean isActiveElement;
|
||||
synchronized (fCacheMutex) {
|
||||
isActiveElement= tUnit.equals(fActiveTU);
|
||||
if (isActiveElement) {
|
||||
if (fAST != null) {
|
||||
// AST is cached
|
||||
if (fLastWriteOnIndex < index.getLastWriteAccess()) {
|
||||
// AST has been invalidated by index write access
|
||||
disposeAST();
|
||||
} else {
|
||||
// cached AST is valid
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "returning cached AST:" + toString(fAST) + " for: " + tUnit.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return fAST;
|
||||
}
|
||||
}
|
||||
// no cached AST
|
||||
if (!wait) {
|
||||
// no AST, no wait - we are done
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "returning null (WAIT_NO) for: " + tUnit.getElementName()); //$NON-NLS-1$
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// no cached AST, but wait
|
||||
if (isActiveElement && isReconciling(tUnit)) {
|
||||
try {
|
||||
final ICElement activeElement= fActiveTU;
|
||||
// Wait for AST
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "waiting for AST for: " + tUnit.getElementName()); //$NON-NLS-1$
|
||||
fCacheMutex.wait();
|
||||
// Check whether active element is still valid (
|
||||
synchronized (this) {
|
||||
if (activeElement == fActiveTU && fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "...got AST for: " + tUnit.getElementName()); //$NON-NLS-1$
|
||||
return fAST;
|
||||
}
|
||||
}
|
||||
// try again
|
||||
continue;
|
||||
} catch (InterruptedException e) {
|
||||
return null; // thread has been interrupted don't compute AST
|
||||
}
|
||||
} else if (!wait) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isActiveElement)
|
||||
aboutToBeReconciled(tUnit);
|
||||
|
||||
if (DEBUG)
|
||||
System.err.println(DEBUG_PREFIX + getThreadName() + "creating AST for " + tUnit.getElementName()); //$NON-NLS-1$
|
||||
|
||||
IASTTranslationUnit ast= null;
|
||||
try {
|
||||
ast= createAST(tUnit, index, progressMonitor);
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
ast= null;
|
||||
else if (DEBUG && ast != null)
|
||||
System.err.println(DEBUG_PREFIX + getThreadName() + "created AST for: " + tUnit.getElementName()); //$NON-NLS-1$
|
||||
} finally {
|
||||
if (isActiveElement) {
|
||||
if (fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "Ignore created AST for " + tUnit.getElementName() + "- AST from reconciler is newer"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// other reconciler was faster, still need to trigger notify
|
||||
reconciled(fAST, tUnit);
|
||||
} else
|
||||
reconciled(ast, tUnit);
|
||||
}
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes {@link ASTRunnable#runOnAST(IASTTranslationUnit)} with the AST
|
||||
* provided by this cache for the given translation unit. Handles acquiring
|
||||
* and releasing the index read-lock for the client.
|
||||
*
|
||||
* @param tUnit
|
||||
* the translation unit
|
||||
* @param wait
|
||||
* <code>true</code> if the AST should be computed or waited
|
||||
* upon in case it is not yet available
|
||||
* @param monitor a progress monitor, may be <code>null</code>
|
||||
* @param astRunnable the runnable taking the AST
|
||||
* @return the status returned by the ASTRunnable
|
||||
*/
|
||||
public IStatus runOnAST(ITranslationUnit tUnit, boolean wait, IProgressMonitor monitor,
|
||||
ASTRunnable astRunnable) {
|
||||
IIndex index;
|
||||
try {
|
||||
index = CCorePlugin.getIndexManager().getIndex(tUnit.getCProject());
|
||||
index.acquireReadLock();
|
||||
} catch (CoreException e) {
|
||||
return e.getStatus();
|
||||
} catch (InterruptedException e) {
|
||||
return Status.CANCEL_STATUS;
|
||||
}
|
||||
|
||||
try {
|
||||
IASTTranslationUnit ast= getAST(tUnit, index, wait, monitor);
|
||||
return astRunnable.runOnAST(ast);
|
||||
}
|
||||
finally {
|
||||
index.releaseReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the given AST for the given translation unit.
|
||||
*
|
||||
* @param ast the AST
|
||||
* @param tUnit the translation unit
|
||||
*/
|
||||
private void cache(IASTTranslationUnit ast, ITranslationUnit tUnit) {
|
||||
synchronized (fCacheMutex) {
|
||||
if (fActiveTU != null && !fActiveTU.equals(tUnit)) {
|
||||
if (DEBUG && tUnit != null) // don't report call from disposeAST()
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "don't cache AST for inactive: " + toString(tUnit)); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG && (tUnit != null || ast != null)) // don't report call from disposeAST()
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "caching AST: " + toString(ast) + " for: " + toString(tUnit)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
if (fAST != null)
|
||||
disposeAST();
|
||||
|
||||
fAST= ast;
|
||||
fLastWriteOnIndex= fAST == null ? 0 : fAST.getIndex().getLastWriteAccess();
|
||||
|
||||
// Signal AST change
|
||||
fCacheMutex.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the cached AST.
|
||||
*/
|
||||
public void disposeAST() {
|
||||
synchronized (fCacheMutex) {
|
||||
if (fAST == null)
|
||||
return;
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "disposing AST: " + toString(fAST) + " for: " + toString(fActiveTU)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
fAST= null;
|
||||
cache(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new translation unit AST.
|
||||
*
|
||||
* @param tUnit the C element for which to create the AST
|
||||
* @param index for AST generation, needs to be read-locked.
|
||||
* @param progressMonitor the progress monitor
|
||||
* @return AST
|
||||
*/
|
||||
public IASTTranslationUnit createAST(final ITranslationUnit tUnit, final IIndex index, final IProgressMonitor progressMonitor) {
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
return null;
|
||||
|
||||
final IASTTranslationUnit root[]= new IASTTranslationUnit[1];
|
||||
|
||||
SafeRunner.run(new ISafeRunnable() {
|
||||
public void run() throws CoreException {
|
||||
try {
|
||||
if (progressMonitor != null && progressMonitor.isCanceled()) {
|
||||
root[0]= null;
|
||||
} else {
|
||||
root[0]= tUnit.getAST(index, fParseMode);
|
||||
}
|
||||
} catch (OperationCanceledException ex) {
|
||||
root[0]= null;
|
||||
}
|
||||
}
|
||||
public void handleException(Throwable ex) {
|
||||
IStatus status= new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, IStatus.OK, "Error in CDT Core during AST creation", ex); //$NON-NLS-1$
|
||||
CCorePlugin.getDefault().getLog().log(status);
|
||||
}
|
||||
});
|
||||
|
||||
return root[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given translation unit as active element to cache an AST for.
|
||||
*
|
||||
* @param tUnit
|
||||
*/
|
||||
public void setActiveElement(ITranslationUnit tUnit) {
|
||||
if (tUnit == fActiveTU) {
|
||||
return;
|
||||
}
|
||||
fIsReconciling= false;
|
||||
synchronized (fCacheMutex) {
|
||||
fActiveTU= tUnit;
|
||||
cache(null, tUnit);
|
||||
}
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "active element is: " + toString(tUnit)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given translation unit is the active element of this cache.
|
||||
*
|
||||
* @param tUnit
|
||||
* @return <code>true</code>, if this cache manages the given translation unit
|
||||
*/
|
||||
public boolean isActiveElement(ITranslationUnit tUnit) {
|
||||
synchronized (fCacheMutex) {
|
||||
return fActiveTU != null && fActiveTU.equals(tUnit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs that reconciling (computation of the AST) for the given element
|
||||
* is about to be started.
|
||||
*
|
||||
* @param tUnit the C element
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
|
||||
*/
|
||||
public void aboutToBeReconciled(ITranslationUnit tUnit) {
|
||||
if (tUnit == null)
|
||||
return;
|
||||
if (fActiveTU == null || !fActiveTU.equals(tUnit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "about to reconcile: " + toString(tUnit)); //$NON-NLS-1$
|
||||
|
||||
fIsReconciling= true;
|
||||
cache(null, tUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs that reconciling of the AST of the given translation unit has finished.
|
||||
*
|
||||
* @param ast
|
||||
* @param tUnit
|
||||
*/
|
||||
public void reconciled(IASTTranslationUnit ast, ITranslationUnit tUnit) {
|
||||
synchronized (fCacheMutex) {
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + "reconciled: " + toString(tUnit) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
fIsReconciling= false;
|
||||
if (tUnit == null || !tUnit.equals(fActiveTU)) {
|
||||
if (DEBUG)
|
||||
System.out.println(DEBUG_PREFIX + getThreadName() + " ignoring AST of out-dated element"); //$NON-NLS-1$
|
||||
|
||||
// Signal - threads might wait for wrong element
|
||||
fCacheMutex.notifyAll();
|
||||
return;
|
||||
}
|
||||
cache(ast, tUnit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given C element is the one
|
||||
* reported as currently being reconciled.
|
||||
*
|
||||
* @param tUnit the C element
|
||||
* @return <code>true</code> if reported as currently being reconciled
|
||||
*/
|
||||
public boolean isReconciling(ITranslationUnit tUnit) {
|
||||
synchronized (fCacheMutex) {
|
||||
if (fActiveTU == null || tUnit == null) {
|
||||
return false;
|
||||
}
|
||||
return fIsReconciling && (fActiveTU.equals(tUnit));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getThreadName() {
|
||||
String name= Thread.currentThread().getName();
|
||||
if (name != null)
|
||||
return name + ": "; //$NON-NLS-1$
|
||||
else
|
||||
return Thread.currentThread().toString() + ": "; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for the given C element used for debugging.
|
||||
*
|
||||
* @param cElement the translation unit AST
|
||||
* @return a string used for debugging
|
||||
*/
|
||||
private static String toString(ICElement cElement) {
|
||||
if (cElement == null)
|
||||
return "null"; //$NON-NLS-1$
|
||||
else
|
||||
return cElement.getElementName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for the given AST used for debugging.
|
||||
*
|
||||
* @param ast the translation unit AST
|
||||
* @return a string used for debugging
|
||||
*/
|
||||
private static String toString(IASTTranslationUnit ast) {
|
||||
if (ast == null)
|
||||
return "null"; //$NON-NLS-1$
|
||||
|
||||
IASTNode[] nodes= ast.getDeclarations();
|
||||
if (nodes != null && nodes.length > 0)
|
||||
return nodes[0].getRawSignature();
|
||||
else
|
||||
return "AST without any declaration"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
|
@ -131,7 +131,7 @@ public class SemanticHighlightingTest extends AbstractSemanticHighlightingTest {
|
|||
createPosition(118, 4, 15),
|
||||
};
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
System.out.println(toString(actual));
|
||||
if (PRINT_POSITIONS) System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,14 +14,8 @@
|
|||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.ISafeRunnable;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.SafeRunner;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.ui.IPartListener2;
|
||||
import org.eclipse.ui.IWindowListener;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
|
@ -29,21 +23,19 @@ import org.eclipse.ui.IWorkbenchPartReference;
|
|||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ISourceReference;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a shared AST for clients. The shared AST is
|
||||
* the AST of the active CEditor's input element.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
|
@ -105,11 +97,6 @@ public final class ASTProvider {
|
|||
/** Fast parse mode (use PDOM) */
|
||||
public static int PARSE_MODE_FAST= ITranslationUnit.AST_SKIP_INDEXED_HEADERS;
|
||||
|
||||
/**
|
||||
* Tells whether this class is in debug mode.
|
||||
*/
|
||||
private static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.cdt.ui/debug/ASTProvider")); //$NON-NLS-1$//$NON-NLS-2$
|
||||
|
||||
/**
|
||||
* Internal activation listener.
|
||||
*/
|
||||
|
@ -136,9 +123,6 @@ public final class ASTProvider {
|
|||
*/
|
||||
public void partClosed(IWorkbenchPartReference ref) {
|
||||
if (isActiveEditor(ref)) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "closed active editor: " + ref.getTitle()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
activeEditorChanged(null);
|
||||
}
|
||||
}
|
||||
|
@ -199,9 +183,6 @@ public final class ASTProvider {
|
|||
*/
|
||||
public void windowClosed(IWorkbenchWindow window) {
|
||||
if (fActiveEditor != null && fActiveEditor.getSite() != null && window == fActiveEditor.getSite().getWorkbenchWindow()) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "closed active editor: " + fActiveEditor.getTitle()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
activeEditorChanged(null);
|
||||
}
|
||||
window.getPartService().removePartListener(this);
|
||||
|
@ -232,23 +213,10 @@ public final class ASTProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private static final String DEBUG_PREFIX= "ASTProvider > "; //$NON-NLS-1$
|
||||
|
||||
|
||||
private ICElement fReconcilingCElement;
|
||||
private ICElement fActiveCElement;
|
||||
private IPositionConverter fActivePositionConverter;
|
||||
private IASTTranslationUnit fAST;
|
||||
private ASTCache fCache= new ASTCache();
|
||||
private ActivationListener fActivationListener;
|
||||
private Object fReconcileLock= new Object();
|
||||
private Object fWaitLock= new Object();
|
||||
private boolean fIsReconciling;
|
||||
private IWorkbenchPart fActiveEditor;
|
||||
|
||||
protected int fParseMode= PARSE_MODE_FAST;
|
||||
|
||||
private long fLastWriteOnIndex= -1;
|
||||
|
||||
/**
|
||||
* Returns the C plug-in's AST provider.
|
||||
*
|
||||
|
@ -282,41 +250,14 @@ public final class ASTProvider {
|
|||
}
|
||||
|
||||
private void activeEditorChanged(IWorkbenchPart editor) {
|
||||
|
||||
ICElement cElement= null;
|
||||
if (editor instanceof CEditor) {
|
||||
cElement= ((CEditor)editor).getInputCElement();
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
fActiveEditor= editor;
|
||||
fActiveCElement= cElement;
|
||||
cache(null, null, cElement);
|
||||
fCache.setActiveElement((ITranslationUnit)cElement);
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "active editor is: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
synchronized (fReconcileLock) {
|
||||
if (fIsReconciling && (fReconcilingCElement == null || !fReconcilingCElement.equals(cElement))) {
|
||||
fIsReconciling= false;
|
||||
fReconcilingCElement= null;
|
||||
} else if (cElement == null) {
|
||||
fIsReconciling= false;
|
||||
fReconcilingCElement= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given translation unit AST is
|
||||
* cached by this AST provided.
|
||||
*
|
||||
* @param ast the translation unit AST
|
||||
* @return <code>true</code> if the given AST is the cached one
|
||||
*/
|
||||
public boolean isCached(IASTTranslationUnit ast) {
|
||||
return ast != null && fAST == ast;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,7 +268,7 @@ public final class ASTProvider {
|
|||
* @return <code>true</code> if the given translation unit is the active one
|
||||
*/
|
||||
public boolean isActive(ITranslationUnit tu) {
|
||||
return tu != null && tu.equals(fActiveCElement);
|
||||
return fCache.isActiveElement(tu);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,95 +278,10 @@ public final class ASTProvider {
|
|||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
|
||||
*/
|
||||
void aboutToBeReconciled(ICElement cElement) {
|
||||
|
||||
if (cElement == null)
|
||||
return;
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "about to reconcile: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
synchronized (fReconcileLock) {
|
||||
fIsReconciling= true;
|
||||
fReconcilingCElement= cElement;
|
||||
}
|
||||
cache(null, null, cElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the cached AST.
|
||||
*/
|
||||
private synchronized void disposeAST() {
|
||||
|
||||
if (fAST == null)
|
||||
return;
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "disposing AST: " + toString(fAST) + " for: " + toString(fActiveCElement)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
fAST= null;
|
||||
|
||||
cache(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for the given C element used for debugging.
|
||||
*
|
||||
* @param cElement the translation unit AST
|
||||
* @return a string used for debugging
|
||||
*/
|
||||
private String toString(ICElement cElement) {
|
||||
if (cElement == null)
|
||||
return "null"; //$NON-NLS-1$
|
||||
else
|
||||
return cElement.getElementName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for the given AST used for debugging.
|
||||
*
|
||||
* @param ast the translation unit AST
|
||||
* @return a string used for debugging
|
||||
*/
|
||||
private String toString(IASTTranslationUnit ast) {
|
||||
if (ast == null)
|
||||
return "null"; //$NON-NLS-1$
|
||||
|
||||
IASTNode[] nodes= ast.getDeclarations();
|
||||
if (nodes != null && nodes.length > 0)
|
||||
return nodes[0].getRawSignature();
|
||||
else
|
||||
return "AST without any declaration"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the given translation unit AST for the given C element.
|
||||
*
|
||||
* @param ast
|
||||
* @param cElement
|
||||
*/
|
||||
private synchronized void cache(IASTTranslationUnit ast, IPositionConverter converter, ICElement cElement) {
|
||||
|
||||
if (fActiveCElement != null && !fActiveCElement.equals(cElement)) {
|
||||
if (DEBUG && cElement != null) // don't report call from disposeAST()
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "don't cache AST for inactive: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG && (cElement != null || ast != null)) // don't report call from disposeAST()
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "caching AST: " + toString(ast) + " for: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
if (fAST != null)
|
||||
disposeAST();
|
||||
|
||||
fAST= ast;
|
||||
fLastWriteOnIndex= fAST == null ? 0 : fAST.getIndex().getLastWriteAccess();
|
||||
fActivePositionConverter= converter;
|
||||
|
||||
// Signal AST change
|
||||
synchronized (fWaitLock) {
|
||||
fWaitLock.notifyAll();
|
||||
}
|
||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||
fCache.aboutToBeReconciled((ITranslationUnit)cElement);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -445,248 +301,48 @@ public final class ASTProvider {
|
|||
public IASTTranslationUnit getAST(ICElement cElement, IIndex index, WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) {
|
||||
if (cElement == null)
|
||||
return null;
|
||||
|
||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
return null;
|
||||
|
||||
boolean isActiveElement;
|
||||
synchronized (this) {
|
||||
isActiveElement= cElement.equals(fActiveCElement);
|
||||
if (isActiveElement) {
|
||||
if (fAST != null) {
|
||||
if (fLastWriteOnIndex < index.getLastWriteAccess()) {
|
||||
disposeAST();
|
||||
}
|
||||
else {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning cached AST:" + toString(fAST) + " for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
return fAST;
|
||||
}
|
||||
}
|
||||
if (waitFlag == WAIT_NO) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning null (WAIT_NO) for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isActiveElement && isReconciling(cElement)) {
|
||||
try {
|
||||
final ICElement activeElement= fReconcilingCElement;
|
||||
|
||||
// Wait for AST
|
||||
synchronized (fWaitLock) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "waiting for AST for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// don't wait forever, notify might have happened already
|
||||
fWaitLock.wait(1000);
|
||||
}
|
||||
|
||||
// Check whether active element is still valid
|
||||
synchronized (this) {
|
||||
if (activeElement == fActiveCElement && fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "...got AST for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
return fAST;
|
||||
}
|
||||
}
|
||||
return getAST(cElement, index, waitFlag, progressMonitor);
|
||||
} catch (InterruptedException e) {
|
||||
return null; // thread has been interrupted don't compute AST
|
||||
}
|
||||
} else if (waitFlag == WAIT_NO || (waitFlag == WAIT_ACTIVE_ONLY && !(isActiveElement && fAST == null)))
|
||||
return null;
|
||||
|
||||
if (isActiveElement)
|
||||
aboutToBeReconciled(cElement);
|
||||
|
||||
if (DEBUG)
|
||||
System.err.println(getThreadName() + " - " + DEBUG_PREFIX + "creating AST for " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
IASTTranslationUnit ast= null;
|
||||
try {
|
||||
ast= createAST(cElement, index, progressMonitor);
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
ast= null;
|
||||
else if (DEBUG && ast != null)
|
||||
System.err.println(getThreadName() + " - " + DEBUG_PREFIX + "created AST for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} finally {
|
||||
if (isActiveElement) {
|
||||
if (fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "Ignore created AST for " + cElement.getElementName() + "- AST from reconciler is newer"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
reconciled(fAST, fActivePositionConverter, cElement, null);
|
||||
} else
|
||||
reconciled(ast, null, cElement, null);
|
||||
}
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given C element is the one
|
||||
* reported as currently being reconciled.
|
||||
*
|
||||
* @param cElement the C element
|
||||
* @return <code>true</code> if reported as currently being reconciled
|
||||
*/
|
||||
private boolean isReconciling(ICElement cElement) {
|
||||
synchronized (fReconcileLock) {
|
||||
return cElement != null && cElement.equals(fReconcilingCElement) && fIsReconciling;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new translation unit AST.
|
||||
*
|
||||
* @param cElement the C element for which to create the AST
|
||||
* @param index for AST generation, needs to be read-locked.
|
||||
* @param progressMonitor the progress monitor
|
||||
* @return AST
|
||||
*/
|
||||
IASTTranslationUnit createAST(ICElement cElement, final IIndex index, final IProgressMonitor progressMonitor) {
|
||||
if (!hasSource(cElement))
|
||||
return null;
|
||||
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
return null;
|
||||
|
||||
if (!(cElement instanceof ITranslationUnit))
|
||||
return null;
|
||||
|
||||
final ITranslationUnit tu= (ITranslationUnit)cElement;
|
||||
final IASTTranslationUnit root[]= new IASTTranslationUnit[1];
|
||||
|
||||
SafeRunner.run(new ISafeRunnable() {
|
||||
public void run() throws CoreException {
|
||||
try {
|
||||
if (progressMonitor != null && progressMonitor.isCanceled()) {
|
||||
root[0]= null;
|
||||
} else {
|
||||
root[0]= tu.getAST(index, fParseMode);
|
||||
}
|
||||
} catch (OperationCanceledException ex) {
|
||||
root[0]= null;
|
||||
}
|
||||
}
|
||||
public void handleException(Throwable ex) {
|
||||
IStatus status= new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, IStatus.OK, "Error in CDT Core during AST creation", ex); //$NON-NLS-1$
|
||||
CUIPlugin.getDefault().getLog().log(status);
|
||||
}
|
||||
});
|
||||
|
||||
return root[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given C element has accessible source.
|
||||
*
|
||||
* @param cElement the C element to test
|
||||
* @return <code>true</code> if the element has source
|
||||
*/
|
||||
private boolean hasSource(ICElement cElement) {
|
||||
if (cElement == null || !cElement.exists())
|
||||
return false;
|
||||
|
||||
try {
|
||||
return cElement instanceof ISourceReference /* && ((ISourceReference)cElement).getSource() != null */;
|
||||
} catch (Exception ex) {
|
||||
IStatus status= new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, IStatus.OK, "Error in CDT Core during AST creation", ex); //$NON-NLS-1$
|
||||
CUIPlugin.getDefault().getLog().log(status);
|
||||
}
|
||||
return false;
|
||||
return fCache.getAST((ITranslationUnit)cElement, index, waitFlag != WAIT_NO, progressMonitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes this AST provider.
|
||||
*/
|
||||
public void dispose() {
|
||||
|
||||
if (fActivationListener != null) {
|
||||
// Dispose activation listener
|
||||
PlatformUI.getWorkbench().removeWindowListener(fActivationListener);
|
||||
fActivationListener= null;
|
||||
}
|
||||
|
||||
disposeAST();
|
||||
|
||||
synchronized (fWaitLock) {
|
||||
fWaitLock.notifyAll();
|
||||
}
|
||||
fCache.disposeAST();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled()
|
||||
*/
|
||||
void reconciled(IASTTranslationUnit ast, IPositionConverter converter, ICElement cElement, IProgressMonitor progressMonitor) {
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "reconciled: " + toString(cElement) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
synchronized (fReconcileLock) {
|
||||
|
||||
fIsReconciling= progressMonitor != null && progressMonitor.isCanceled();
|
||||
if (cElement == null || !cElement.equals(fReconcilingCElement)) {
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + " ignoring AST of out-dated editor"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// Signal - threads might wait for wrong element
|
||||
synchronized (fWaitLock) {
|
||||
fWaitLock.notifyAll();
|
||||
}
|
||||
|
||||
if (cElement == null)
|
||||
return;
|
||||
}
|
||||
|
||||
cache(ast, converter, cElement);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getThreadName() {
|
||||
String name= Thread.currentThread().getName();
|
||||
if (name != null)
|
||||
return name;
|
||||
else
|
||||
return Thread.currentThread().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param element
|
||||
* @return the position converter for the AST of the active element or <code>null</code>
|
||||
*/
|
||||
public IPositionConverter getActivePositionConverter(ICElement element) {
|
||||
if (fActiveCElement == element) {
|
||||
return fActivePositionConverter;
|
||||
}
|
||||
return null;
|
||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||
fCache.reconciled(ast, (ITranslationUnit)cElement);
|
||||
}
|
||||
|
||||
public IStatus runOnAST(ICElement cElement, WAIT_FLAG waitFlag, IProgressMonitor monitor,
|
||||
ASTRunnable astRunnable) {
|
||||
IIndex index;
|
||||
try {
|
||||
index = CCorePlugin.getIndexManager().getIndex(cElement.getCProject());
|
||||
index.acquireReadLock();
|
||||
} catch (CoreException e) {
|
||||
return e.getStatus();
|
||||
} catch (InterruptedException e) {
|
||||
return Status.CANCEL_STATUS;
|
||||
ASTCache.ASTRunnable astRunnable) {
|
||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||
return fCache.runOnAST((ITranslationUnit)cElement, waitFlag != WAIT_NO, monitor, astRunnable);
|
||||
}
|
||||
|
||||
try {
|
||||
IASTTranslationUnit ast= getAST(cElement, index, waitFlag, monitor);
|
||||
return astRunnable.runOnAST(ast);
|
||||
}
|
||||
finally {
|
||||
index.releaseReadLock();
|
||||
}
|
||||
/**
|
||||
* @param cElement
|
||||
* @param index
|
||||
* @param monitor
|
||||
* @return an AST or <code>null</code>, if no AST could be computed
|
||||
*/
|
||||
public IASTTranslationUnit createAST(ICElement cElement, IIndex index, IProgressMonitor monitor) {
|
||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||
return fCache.createAST((ITranslationUnit)cElement, index, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,9 @@ import org.eclipse.cdt.core.model.ICElement;
|
|||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.LineBackgroundPainter;
|
||||
import org.eclipse.cdt.internal.ui.editor.ASTProvider.ASTRunnable;
|
||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
|
||||
/**
|
||||
|
@ -101,7 +102,7 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
|
|||
IStatus result = Status.OK_STATUS;
|
||||
if (fTranslationUnit != null) {
|
||||
final ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
|
||||
result= astProvider.runOnAST(fTranslationUnit, ASTProvider.WAIT_YES, monitor, new ASTRunnable() {
|
||||
result= astProvider.runOnAST(fTranslationUnit, ASTProvider.WAIT_YES, monitor, new ASTCache.ASTRunnable() {
|
||||
public IStatus runOnAST(IASTTranslationUnit ast) {
|
||||
reconciled(ast, null, monitor);
|
||||
return Status.OK_STATUS;
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.eclipse.swt.widgets.MessageBox;
|
|||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
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.parser.ExtendedScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||
|
@ -96,18 +97,23 @@ public class OpenIncludeAction extends Action {
|
|||
if (info == null) {
|
||||
info = provider.getScannerInformation(proj);
|
||||
}
|
||||
|
||||
boolean isSystemInclude = include instanceof IInclude
|
||||
&& ((IInclude) include).isStandard();
|
||||
|
||||
// search in user includes
|
||||
if (!isSystemInclude && info != null) {
|
||||
IExtendedScannerInfo scanInfo = new ExtendedScannerInfo(info);
|
||||
String[] localIncludePaths = scanInfo.getLocalIncludePath();
|
||||
findFile(localIncludePaths, includeName, filesFound);
|
||||
}
|
||||
|
||||
if (filesFound.size() == 0) {
|
||||
if (info != null) {
|
||||
// search in system includes
|
||||
String[] includePaths = info.getIncludePaths();
|
||||
findFile(includePaths, includeName, filesFound);
|
||||
}
|
||||
if (filesFound.size() == 0) {
|
||||
// search in local includes
|
||||
if (info != null) {
|
||||
IExtendedScannerInfo scanInfo = new ExtendedScannerInfo(info);
|
||||
String[] localIncludePaths = scanInfo.getLocalIncludePath();
|
||||
findFile(localIncludePaths, includeName, filesFound);
|
||||
}
|
||||
|
||||
if (filesFound.size() == 0) {
|
||||
// Fall back and search the project
|
||||
|
|
|
@ -45,7 +45,8 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
|||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.ASTProvider.ASTRunnable;
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightedPosition;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle;
|
||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
|
@ -513,7 +514,7 @@ public class SemanticHighlightingReconciler implements ICReconcilingListener {
|
|||
|
||||
final Job me= this;
|
||||
ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
|
||||
IStatus status= astProvider.runOnAST(element, ASTProvider.WAIT_YES, monitor, new ASTRunnable() {
|
||||
IStatus status= astProvider.runOnAST(element, ASTProvider.WAIT_YES, monitor, new ASTCache.ASTRunnable() {
|
||||
public IStatus runOnAST(IASTTranslationUnit ast) {
|
||||
reconciled(ast, null, monitor);
|
||||
synchronized (fJobLock) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2005, 2006 IBM Corporation and others.
|
||||
* Copyright (c) 2005, 2007 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -140,6 +140,7 @@ public class CReconcilingStrategy implements IReconcilingStrategy, IReconcilingS
|
|||
index.acquireReadLock();
|
||||
} catch (InterruptedException exc) {
|
||||
ast= null;
|
||||
index= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,9 +72,10 @@ import org.eclipse.cdt.ui.PreferenceConstants;
|
|||
import org.eclipse.cdt.ui.text.ICPartitions;
|
||||
import org.eclipse.cdt.ui.text.folding.ICFoldingStructureProvider;
|
||||
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.ASTProvider;
|
||||
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
||||
import org.eclipse.cdt.internal.ui.editor.ASTProvider.ASTRunnable;
|
||||
import org.eclipse.cdt.internal.ui.text.DocumentCharacterIterator;
|
||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
|
||||
|
@ -1093,11 +1094,11 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
|
|||
IASTTranslationUnit ast= ctx.getAST();
|
||||
if (ast == null) {
|
||||
final ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
|
||||
IStatus status= astProvider.runOnAST(getInputElement(), ASTProvider.WAIT_ACTIVE_ONLY, null, new ASTRunnable() {
|
||||
IStatus status= astProvider.runOnAST(getInputElement(), ASTProvider.WAIT_ACTIVE_ONLY, null, new ASTCache.ASTRunnable() {
|
||||
public IStatus runOnAST(IASTTranslationUnit ast) {
|
||||
if (ast != null) {
|
||||
ctx.fAST= ast;
|
||||
ctx.fASTPositionConverter= astProvider.getActivePositionConverter(getInputElement());
|
||||
ctx.fASTPositionConverter= null;
|
||||
fInitialASTReconcile= false;
|
||||
computeFoldingStructure(ast, ctx);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue