From 2dfdde8c568ca1050bf58854de3553b8d1b6721b Mon Sep 17 00:00:00 2001 From: Anton Leherbauer Date: Wed, 21 Mar 2007 14:45:58 +0000 Subject: [PATCH] Fix for 173872: ASTProvider locked up waiting on a notify() --- .../cdt/core/model/tests/ASTCacheTests.java | 200 ++++++++ .../cdt/core/model/tests/AllCoreTests.java | 2 +- core/org.eclipse.cdt.core/.options | 3 + .../cdt/internal/core/model/ASTCache.java | 427 ++++++++++++++++++ .../tests/text/SemanticHighlightingTest.java | 2 +- .../cdt/internal/ui/editor/ASTProvider.java | 398 ++-------------- .../ui/editor/InactiveCodeHighlighting.java | 5 +- .../internal/ui/editor/OpenIncludeAction.java | 22 +- .../SemanticHighlightingReconciler.java | 5 +- .../ui/text/CReconcilingStrategy.java | 3 +- .../DefaultCFoldingStructureProvider.java | 7 +- 11 files changed, 685 insertions(+), 389 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java new file mode 100644 index 00000000000..8fce841b803 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java @@ -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); + } + } + } + +} diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java index 423b189510c..223d165b9c7 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java @@ -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; } diff --git a/core/org.eclipse.cdt.core/.options b/core/org.eclipse.cdt.core/.options index 61c44b47d45..4b2af371095 100644 --- a/core/org.eclipse.cdt.core/.options +++ b/core/org.eclipse.cdt.core/.options @@ -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 diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java new file mode 100644 index 00000000000..9dce129d997 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java @@ -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 null + * @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. + *

+ * 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. + *

+ * + * @param tUnit the translation unit + * @param index the index used to create the AST, needs to be read-locked + * @param wait if true, wait for AST to be computed (might compute a new AST) + * @param progressMonitor the progress monitor or null + * @return the AST or null 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 + * true if the AST should be computed or waited + * upon in case it is not yet available + * @param monitor a progress monitor, may be null + * @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 true, 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 true 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$ + } + +} diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SemanticHighlightingTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SemanticHighlightingTest.java index 352bf12e60f..4243c7b9256 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SemanticHighlightingTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SemanticHighlightingTest.java @@ -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); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java index b6abe57ff4d..110538f0fc5 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java @@ -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 true 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 true 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; + return fCache.getAST((ITranslationUnit)cElement, index, waitFlag != WAIT_NO, progressMonitor); } - /** - * Tells whether the given C element is the one - * reported as currently being reconciled. - * - * @param cElement the C element - * @return true 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 true 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. */ 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(); - } - - 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 null - */ - public IPositionConverter getActivePositionConverter(ICElement element) { - if (fActiveCElement == element) { - return fActivePositionConverter; - } - return null; + if (cElement == null) + return; + 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; - } - - try { - IASTTranslationUnit ast= getAST(cElement, index, waitFlag, monitor); - return astRunnable.runOnAST(ast); - } - finally { - index.releaseReadLock(); - } + ASTCache.ASTRunnable astRunnable) { + Assert.isTrue(cElement instanceof ITranslationUnit); + return fCache.runOnAST((ITranslationUnit)cElement, waitFlag != WAIT_NO, monitor, astRunnable); + } + + /** + * @param cElement + * @param index + * @param monitor + * @return an AST or null, 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); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java index 71034e3e518..520750da3a7 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java @@ -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; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OpenIncludeAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OpenIncludeAction.java index 6c29a551764..33b1967d1dc 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OpenIncludeAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OpenIncludeAction.java @@ -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,17 +97,22 @@ public class OpenIncludeAction extends Action { if (info == null) { info = provider.getScannerInformation(proj); } - if (info != null) { - // search in system includes - String[] includePaths = info.getIncludePaths(); - findFile(includePaths, includeName, filesFound); + + 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) { - // search in local includes if (info != null) { - IExtendedScannerInfo scanInfo = new ExtendedScannerInfo(info); - String[] localIncludePaths = scanInfo.getLocalIncludePath(); - findFile(localIncludePaths, includeName, filesFound); + // search in system includes + String[] includePaths = info.getIncludePaths(); + findFile(includePaths, includeName, filesFound); } if (filesFound.size() == 0) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightingReconciler.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightingReconciler.java index b70432670c3..b0a49f0a6ea 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightingReconciler.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightingReconciler.java @@ -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) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CReconcilingStrategy.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CReconcilingStrategy.java index 1b35886b2be..a870e69860e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CReconcilingStrategy.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CReconcilingStrategy.java @@ -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; } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java index 26ad851637d..76cf0388b7d 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java @@ -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); }