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(FailedDeclaratorsTest.suite());
|
||||||
suite.addTest(CPathEntryTest.suite());
|
suite.addTest(CPathEntryTest.suite());
|
||||||
suite.addTest(CConfigurationDescriptionReferenceTests.suite());
|
suite.addTest(CConfigurationDescriptionReferenceTests.suite());
|
||||||
|
suite.addTest(ASTCacheTests.suite());
|
||||||
return suite;
|
return suite;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,3 +35,6 @@ org.eclipse.cdt.core/debug/indexer/problems=false
|
||||||
|
|
||||||
# Code formatter debugging
|
# Code formatter debugging
|
||||||
org.eclipse.cdt.core/debug/formatter=false
|
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),
|
createPosition(118, 4, 15),
|
||||||
};
|
};
|
||||||
Position[] actual= getSemanticHighlightingPositions();
|
Position[] actual= getSemanticHighlightingPositions();
|
||||||
System.out.println(toString(actual));
|
if (PRINT_POSITIONS) System.out.println(toString(actual));
|
||||||
assertEqualPositions(expected, actual);
|
assertEqualPositions(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,8 @@
|
||||||
package org.eclipse.cdt.internal.ui.editor;
|
package org.eclipse.cdt.internal.ui.editor;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.Assert;
|
import org.eclipse.core.runtime.Assert;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
import org.eclipse.core.runtime.ISafeRunnable;
|
|
||||||
import org.eclipse.core.runtime.IStatus;
|
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.IPartListener2;
|
||||||
import org.eclipse.ui.IWindowListener;
|
import org.eclipse.ui.IWindowListener;
|
||||||
import org.eclipse.ui.IWorkbenchPart;
|
import org.eclipse.ui.IWorkbenchPart;
|
||||||
|
@ -29,21 +23,19 @@ import org.eclipse.ui.IWorkbenchPartReference;
|
||||||
import org.eclipse.ui.IWorkbenchWindow;
|
import org.eclipse.ui.IWorkbenchWindow;
|
||||||
import org.eclipse.ui.PlatformUI;
|
import org.eclipse.ui.PlatformUI;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
|
||||||
import org.eclipse.cdt.core.IPositionConverter;
|
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.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.index.IIndex;
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
import org.eclipse.cdt.core.model.ICElement;
|
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.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.model.ASTCache;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a shared AST for clients. The shared AST is
|
* Provides a shared AST for clients. The shared AST is
|
||||||
* the AST of the active CEditor's input element.
|
* the AST of the active CEditor's input element.
|
||||||
* Cloned from JDT.
|
|
||||||
*
|
*
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
|
@ -105,11 +97,6 @@ public final class ASTProvider {
|
||||||
/** Fast parse mode (use PDOM) */
|
/** Fast parse mode (use PDOM) */
|
||||||
public static int PARSE_MODE_FAST= ITranslationUnit.AST_SKIP_INDEXED_HEADERS;
|
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.
|
* Internal activation listener.
|
||||||
*/
|
*/
|
||||||
|
@ -136,9 +123,6 @@ public final class ASTProvider {
|
||||||
*/
|
*/
|
||||||
public void partClosed(IWorkbenchPartReference ref) {
|
public void partClosed(IWorkbenchPartReference ref) {
|
||||||
if (isActiveEditor(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);
|
activeEditorChanged(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,9 +183,6 @@ public final class ASTProvider {
|
||||||
*/
|
*/
|
||||||
public void windowClosed(IWorkbenchWindow window) {
|
public void windowClosed(IWorkbenchWindow window) {
|
||||||
if (fActiveEditor != null && fActiveEditor.getSite() != null && window == fActiveEditor.getSite().getWorkbenchWindow()) {
|
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);
|
activeEditorChanged(null);
|
||||||
}
|
}
|
||||||
window.getPartService().removePartListener(this);
|
window.getPartService().removePartListener(this);
|
||||||
|
@ -232,23 +213,10 @@ public final class ASTProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String DEBUG_PREFIX= "ASTProvider > "; //$NON-NLS-1$
|
private ASTCache fCache= new ASTCache();
|
||||||
|
|
||||||
|
|
||||||
private ICElement fReconcilingCElement;
|
|
||||||
private ICElement fActiveCElement;
|
|
||||||
private IPositionConverter fActivePositionConverter;
|
|
||||||
private IASTTranslationUnit fAST;
|
|
||||||
private ActivationListener fActivationListener;
|
private ActivationListener fActivationListener;
|
||||||
private Object fReconcileLock= new Object();
|
|
||||||
private Object fWaitLock= new Object();
|
|
||||||
private boolean fIsReconciling;
|
|
||||||
private IWorkbenchPart fActiveEditor;
|
private IWorkbenchPart fActiveEditor;
|
||||||
|
|
||||||
protected int fParseMode= PARSE_MODE_FAST;
|
|
||||||
|
|
||||||
private long fLastWriteOnIndex= -1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the C plug-in's AST provider.
|
* Returns the C plug-in's AST provider.
|
||||||
*
|
*
|
||||||
|
@ -282,41 +250,14 @@ public final class ASTProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activeEditorChanged(IWorkbenchPart editor) {
|
private void activeEditorChanged(IWorkbenchPart editor) {
|
||||||
|
|
||||||
ICElement cElement= null;
|
ICElement cElement= null;
|
||||||
if (editor instanceof CEditor) {
|
if (editor instanceof CEditor) {
|
||||||
cElement= ((CEditor)editor).getInputCElement();
|
cElement= ((CEditor)editor).getInputCElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
fActiveEditor= editor;
|
fActiveEditor= editor;
|
||||||
fActiveCElement= cElement;
|
fCache.setActiveElement((ITranslationUnit)cElement);
|
||||||
cache(null, null, 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
|
* @return <code>true</code> if the given translation unit is the active one
|
||||||
*/
|
*/
|
||||||
public boolean isActive(ITranslationUnit tu) {
|
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()
|
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
|
||||||
*/
|
*/
|
||||||
void aboutToBeReconciled(ICElement cElement) {
|
void aboutToBeReconciled(ICElement cElement) {
|
||||||
|
|
||||||
if (cElement == null)
|
if (cElement == null)
|
||||||
return;
|
return;
|
||||||
|
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||||
if (DEBUG)
|
fCache.aboutToBeReconciled((ITranslationUnit)cElement);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -445,248 +301,48 @@ public final class ASTProvider {
|
||||||
public IASTTranslationUnit getAST(ICElement cElement, IIndex index, WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) {
|
public IASTTranslationUnit getAST(ICElement cElement, IIndex index, WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) {
|
||||||
if (cElement == null)
|
if (cElement == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||||
|
return fCache.getAST((ITranslationUnit)cElement, index, waitFlag != WAIT_NO, progressMonitor);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes this AST provider.
|
* Disposes this AST provider.
|
||||||
*/
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
|
||||||
if (fActivationListener != null) {
|
if (fActivationListener != null) {
|
||||||
// Dispose activation listener
|
// Dispose activation listener
|
||||||
PlatformUI.getWorkbench().removeWindowListener(fActivationListener);
|
PlatformUI.getWorkbench().removeWindowListener(fActivationListener);
|
||||||
fActivationListener= null;
|
fActivationListener= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
disposeAST();
|
fCache.disposeAST();
|
||||||
|
|
||||||
synchronized (fWaitLock) {
|
|
||||||
fWaitLock.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled()
|
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled()
|
||||||
*/
|
*/
|
||||||
void reconciled(IASTTranslationUnit ast, IPositionConverter converter, ICElement cElement, IProgressMonitor progressMonitor) {
|
void reconciled(IASTTranslationUnit ast, IPositionConverter converter, ICElement cElement, IProgressMonitor progressMonitor) {
|
||||||
|
if (cElement == null)
|
||||||
if (DEBUG)
|
return;
|
||||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "reconciled: " + toString(cElement) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||||
|
fCache.reconciled(ast, (ITranslationUnit)cElement);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStatus runOnAST(ICElement cElement, WAIT_FLAG waitFlag, IProgressMonitor monitor,
|
public IStatus runOnAST(ICElement cElement, WAIT_FLAG waitFlag, IProgressMonitor monitor,
|
||||||
ASTRunnable astRunnable) {
|
ASTCache.ASTRunnable astRunnable) {
|
||||||
IIndex index;
|
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||||
try {
|
return fCache.runOnAST((ITranslationUnit)cElement, waitFlag != WAIT_NO, monitor, astRunnable);
|
||||||
index = CCorePlugin.getIndexManager().getIndex(cElement.getCProject());
|
}
|
||||||
index.acquireReadLock();
|
|
||||||
} catch (CoreException e) {
|
/**
|
||||||
return e.getStatus();
|
* @param cElement
|
||||||
} catch (InterruptedException e) {
|
* @param index
|
||||||
return Status.CANCEL_STATUS;
|
* @param monitor
|
||||||
}
|
* @return an AST or <code>null</code>, if no AST could be computed
|
||||||
|
*/
|
||||||
try {
|
public IASTTranslationUnit createAST(ICElement cElement, IIndex index, IProgressMonitor monitor) {
|
||||||
IASTTranslationUnit ast= getAST(cElement, index, waitFlag, monitor);
|
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||||
return astRunnable.runOnAST(ast);
|
return fCache.createAST((ITranslationUnit)cElement, index, monitor);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
index.releaseReadLock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,9 @@ import org.eclipse.cdt.core.model.ICElement;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
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.LineBackgroundPainter;
|
||||||
import org.eclipse.cdt.internal.ui.editor.ASTProvider.ASTRunnable;
|
|
||||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,7 +102,7 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
|
||||||
IStatus result = Status.OK_STATUS;
|
IStatus result = Status.OK_STATUS;
|
||||||
if (fTranslationUnit != null) {
|
if (fTranslationUnit != null) {
|
||||||
final ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
|
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) {
|
public IStatus runOnAST(IASTTranslationUnit ast) {
|
||||||
reconciled(ast, null, monitor);
|
reconciled(ast, null, monitor);
|
||||||
return Status.OK_STATUS;
|
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.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.model.CModelException;
|
import org.eclipse.cdt.core.model.CModelException;
|
||||||
import org.eclipse.cdt.core.model.ICElement;
|
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.ExtendedScannerInfo;
|
||||||
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
|
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
|
||||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||||
|
@ -96,17 +97,22 @@ public class OpenIncludeAction extends Action {
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
info = provider.getScannerInformation(proj);
|
info = provider.getScannerInformation(proj);
|
||||||
}
|
}
|
||||||
if (info != null) {
|
|
||||||
// search in system includes
|
boolean isSystemInclude = include instanceof IInclude
|
||||||
String[] includePaths = info.getIncludePaths();
|
&& ((IInclude) include).isStandard();
|
||||||
findFile(includePaths, includeName, filesFound);
|
|
||||||
|
// 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 (filesFound.size() == 0) {
|
||||||
// search in local includes
|
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
IExtendedScannerInfo scanInfo = new ExtendedScannerInfo(info);
|
// search in system includes
|
||||||
String[] localIncludePaths = scanInfo.getLocalIncludePath();
|
String[] includePaths = info.getIncludePaths();
|
||||||
findFile(localIncludePaths, includeName, filesFound);
|
findFile(includePaths, includeName, filesFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filesFound.size() == 0) {
|
if (filesFound.size() == 0) {
|
||||||
|
|
|
@ -45,7 +45,8 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.model.ICElement;
|
import org.eclipse.cdt.core.model.ICElement;
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
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.HighlightedPosition;
|
||||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle;
|
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle;
|
||||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||||
|
@ -513,7 +514,7 @@ public class SemanticHighlightingReconciler implements ICReconcilingListener {
|
||||||
|
|
||||||
final Job me= this;
|
final Job me= this;
|
||||||
ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
|
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) {
|
public IStatus runOnAST(IASTTranslationUnit ast) {
|
||||||
reconciled(ast, null, monitor);
|
reconciled(ast, null, monitor);
|
||||||
synchronized (fJobLock) {
|
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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -140,6 +140,7 @@ public class CReconcilingStrategy implements IReconcilingStrategy, IReconcilingS
|
||||||
index.acquireReadLock();
|
index.acquireReadLock();
|
||||||
} catch (InterruptedException exc) {
|
} catch (InterruptedException exc) {
|
||||||
ast= null;
|
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.ICPartitions;
|
||||||
import org.eclipse.cdt.ui.text.folding.ICFoldingStructureProvider;
|
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.ASTProvider;
|
||||||
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
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.DocumentCharacterIterator;
|
||||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||||
|
|
||||||
|
@ -1093,11 +1094,11 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
|
||||||
IASTTranslationUnit ast= ctx.getAST();
|
IASTTranslationUnit ast= ctx.getAST();
|
||||||
if (ast == null) {
|
if (ast == null) {
|
||||||
final ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
|
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) {
|
public IStatus runOnAST(IASTTranslationUnit ast) {
|
||||||
if (ast != null) {
|
if (ast != null) {
|
||||||
ctx.fAST= ast;
|
ctx.fAST= ast;
|
||||||
ctx.fASTPositionConverter= astProvider.getActivePositionConverter(getInputElement());
|
ctx.fASTPositionConverter= null;
|
||||||
fInitialASTReconcile= false;
|
fInitialASTReconcile= false;
|
||||||
computeFoldingStructure(ast, ctx);
|
computeFoldingStructure(ast, ctx);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue