From 0af49e609b7c67e0ef7ac7346dbd2187a8fdfcce Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 8 Nov 2013 21:01:57 +0100 Subject: [PATCH] fix two psi elements per one ast element in stub-ast switch: psi1 is taken from stub psi2 is eagerly created during chameleon parsing another thread gets the ast when some psi1 parent is already switched and psi1 is not, it walks down the ast and gets psi2 --- .../com/intellij/psi/StubAstSwitchTest.groovy | 4 +++- .../com/intellij/psi/impl/source/PsiFileImpl.java | 9 ++++++++- .../psi/impl/source/tree/LazyParseableElement.java | 13 ++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy b/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy index b7b39fb7a017..936bb1c84203 100644 --- a/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy @@ -66,7 +66,9 @@ class StubAstSwitchTest extends LightCodeInsightFixtureTestCase { int count = 100 List classList = (0..> bindings = calcStubAstBindings(treeElement, cachedDocument); + List> bindings; + LazyParseableElement.setSuppressEagerPsiCreation(true); + try { + bindings = calcStubAstBindings(treeElement, cachedDocument); + } + finally { + LazyParseableElement.setSuppressEagerPsiCreation(false); + } synchronized (PsiLock.LOCK) { FileElement existing = derefTreeElement(); diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java index 15b605ccdba5..a09ab199b95a 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java @@ -48,6 +48,7 @@ public class LazyParseableElement extends CompositeElement { // Under no circumstances should you grab the PSI_LOCK while holding this lock. private final ChameleonLock lock = new ChameleonLock(); private CharSequence myText; /** guarded by {@link #lock} */ + private static final ThreadLocal ourSuppressEagerPsiCreation = new ThreadLocal(); public LazyParseableElement(@NotNull IElementType type, CharSequence text) { super(type); @@ -181,9 +182,11 @@ public class LazyParseableElement extends CompositeElement { super.rawAddChildrenWithoutNotifications((TreeElement)parsedNode); } - // create PSI all at once, to reduce contention of PsiLock in CompositeElement.getPsi() - // create PSI outside the 'lock' since this method grabs PSI_LOCK and deadlock is possible when someone else locks in the other order. - createAllChildrenPsiIfNecessary(); + if (!Boolean.TRUE.equals(ourSuppressEagerPsiCreation.get())) { + // create PSI all at once, to reduce contention of PsiLock in CompositeElement.getPsi() + // create PSI outside the 'lock' since this method grabs PSI_LOCK and deadlock is possible when someone else locks in the other order. + createAllChildrenPsiIfNecessary(); + } } @Override @@ -222,4 +225,8 @@ public class LazyParseableElement extends CompositeElement { public static void setParsingAllowed(boolean allowed) { ourParsingAllowed = allowed; } + + public static void setSuppressEagerPsiCreation(boolean suppress) { + ourSuppressEagerPsiCreation.set(suppress); + } }