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
This commit is contained in:
peter
2013-11-09 12:24:35 +01:00
parent fcfef16a56
commit 0af49e609b
3 changed files with 21 additions and 5 deletions
@@ -66,7 +66,9 @@ class StubAstSwitchTest extends LightCodeInsightFixtureTestCase {
int count = 100
List<PsiClass> classList = (0..<count).collect {
myFixture.addClass("class Foo$it { " +
(0..<100).collect { "void foo$it(int i, boolean b, Object o) {}" }.join("\n") +
"void foo$it(" +
(0..250).collect { "int i$it"}.join(", ") +
") {}" +
" }")
}
CountDownLatch latch = new CountDownLatch(count)
@@ -202,7 +202,14 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
}
treeElement.setPsi(this);
List<Pair<StubBasedPsiElementBase, CompositeElement>> bindings = calcStubAstBindings(treeElement, cachedDocument);
List<Pair<StubBasedPsiElementBase, CompositeElement>> bindings;
LazyParseableElement.setSuppressEagerPsiCreation(true);
try {
bindings = calcStubAstBindings(treeElement, cachedDocument);
}
finally {
LazyParseableElement.setSuppressEagerPsiCreation(false);
}
synchronized (PsiLock.LOCK) {
FileElement existing = derefTreeElement();
@@ -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<Boolean> ourSuppressEagerPsiCreation = new ThreadLocal<Boolean>();
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);
}
}