more diagnostics on stub-ast mismatch

This commit is contained in:
peter
2013-06-07 22:44:09 +02:00
parent 4bf8878dd0
commit b82f6dd943
6 changed files with 60 additions and 36 deletions
@@ -176,6 +176,7 @@ public class StubBasedPsiElementBase<T extends StubElement> extends ASTDelegateP
if (psi != null) {
return psi;
}
ApplicationManager.getApplication().assertReadAccessAllowed();
synchronized (PsiLock.LOCK) {
if (myStub != null) {
throw new PsiInvalidElementAccessException(this, "no psi for file stub " + stub, null);
@@ -472,7 +472,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
@Override
public String toString() {
return getClass().getSimpleName() + "{myVirtualFile=" + myVirtualFile + '}';
return getClass().getSimpleName() + "{myVirtualFile=" + myVirtualFile + ", content=" + getContent() + '}';
}
private interface Content {
@@ -35,7 +35,6 @@ import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.*;
@@ -260,23 +259,15 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
}
private List<Pair<StubBasedPsiElementBase, CompositeElement>> calcStubAstBindings(final ASTNode root) {
StubTree stubTree = derefStub();
final StubTree stubTree = derefStub();
if (stubTree == null) {
return Collections.emptyList();
}
final Iterator<StubElement<?>> stubs = stubTree.getPlainList().iterator();
stubs.next(); // Skip file stub;
final IElementType contentElementType = getContentElementType();
if (!(contentElementType instanceof IStubFileElementType)) {
final VirtualFile vFile = getVirtualFile();
throw new AssertionError("A stub in a non-stub file '" + vFile + "'; isValid()=" + (vFile != null ? vFile.isValid() : "null") +
" type: " + contentElementType + "; content:<<<\n" +
StringUtil.first(getViewProvider().getContents(), 200, true) +
"\n>>>; stubs=" + ContainerUtil.collect(stubs));
}
final List<Pair<StubBasedPsiElementBase, CompositeElement>> result = ContainerUtil.newArrayList();
final StubBuilder builder = ((IStubFileElementType)contentElementType).getBuilder();
final StubBuilder builder = ((IStubFileElementType)getContentElementType()).getBuilder();
((TreeElement)root).acceptTree(new RecursiveTreeElementWalkingVisitor() {
@Override
@@ -290,16 +281,13 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
IElementType type = node.getElementType();
if (type instanceof IStubElementType && ((IStubElementType)type).shouldCreateStub(node)) {
if (!stubs.hasNext()) {
rebuildStub();
throw new AssertionError("Stub list in " + getName() + " has fewer elements than PSI. Last AST element: " +
node.getElementType() + " " + node);
reportStubAstMismatch("Stub list is less than AST, last AST element: " + node.getElementType() + " " + node, stubTree);
}
final StubElement stub = stubs.next();
if (stub.getStubType() != node.getElementType()) {
rebuildStub();
throw new AssertionError("Stub and PSI element type mismatch in " + getName() + ": stub " + stub + ", AST " +
node.getElementType() + "; " + node);
reportStubAstMismatch("Stub and PSI element type mismatch in " + getName() + ": stub " + stub + ", AST " +
node.getElementType() + "; " + node, stubTree);
}
PsiElement psi = stub.getPsi();
@@ -310,9 +298,37 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
super.visitNode(node);
}
});
if (stubs.hasNext()) {
reportStubAstMismatch("Stub list in " + getName() + " has more elements than PSI", stubTree);
}
return result;
}
private void reportStubAstMismatch(String message, StubTree stubTree) {
rebuildStub();
String msg = message;
msg += "\n file=" + this;
msg += "\n name=" + getName();
msg += "\n stub debugInfo=" + stubTree.getDebugInfo();
FileViewProvider viewProvider = getViewProvider();
msg += "\n viewProvider=" + viewProvider;
msg += "\n viewProvider stamp: " + viewProvider.getModificationStamp();
VirtualFile file = viewProvider.getVirtualFile();
msg += "; file stamp: " + file.getModificationStamp();
msg += "; file modCount: " + file.getModificationCount();
Document document = FileDocumentManager.getInstance().getCachedDocument(file);
if (document != null) {
msg += "\n doc saved: " + !FileDocumentManager.getInstance().isDocumentUnsaved(document);
msg += "; doc stamp: " + document.getModificationStamp();
msg += "; committed: " + PsiDocumentManager.getInstance(getProject()).isCommitted(document);
}
throw new AssertionError(msg);
}
protected FileElement createFileElement(final CharSequence docText) {
final FileElement treeElement;
final TreeElement contentLeaf = createContentLeafElement(docText);
@@ -649,6 +665,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
if (derefd != null) return derefd;
if (getTreeElement() != null) return null;
if (!(getContentElementType() instanceof IStubFileElementType)) return null;
final VirtualFile vFile = getVirtualFile();
if (!(vFile instanceof VirtualFileWithId)) return null;
@@ -656,19 +674,6 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
if (!(tree instanceof StubTree)) return null;
StubTree stubHolder = (StubTree)tree;
final IElementType contentElementType = getContentElementType();
if (!(contentElementType instanceof IStubFileElementType)) {
final FileViewProvider viewProvider = getViewProvider();
throw new AssertionError("A stub in a non-stub file '" + vFile +"'; isValid()=" + vFile.isValid() +
"; IndexStamp="+ StubTreeLoader.getInstance().getStubTreeTimestamp(vFile) +
"; Type: " + contentElementType + "; " +
"Psi roots: " + viewProvider.getAllFiles() + "; " +
" StubUpdatingIndex.canHaveStub(vFile)=" + StubTreeLoader.getInstance().canHaveStub(vFile) +
" content:<<<\n"+
StringUtil.first(viewProvider.getContents(),200,true)+
"\n>>>; stubs=" + stubHolder.getPlainList());
}
synchronized (PsiLock.LOCK) {
if (getTreeElement() != null) return null;
@@ -965,6 +970,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
StubElement currentStubTree = ((IStubFileElementType)contentElementType).getBuilder().buildStubTree(this);
tree = new StubTree((PsiFileStub)currentStubTree);
tree.setDebugInfo("created in calcStubTree");
try {
TreeUtil.bindStubsToTree(this, tree);
}
@@ -30,9 +30,9 @@ import java.util.Map;
* Date: 8/3/12
*/
public class ObjectStubTree<T extends Stub> {
protected static final Key<ObjectStubTree> STUB_TO_TREE_REFERENCE = Key.create("stub to tree reference");
private static final Key<ObjectStubTree> STUB_TO_TREE_REFERENCE = Key.create("stub to tree reference");
protected final ObjectStubBase myRoot;
private String myDebugInfo;
protected final List<T> myPlainList = new ArrayList<T>();
public ObjectStubTree(@NotNull final ObjectStubBase root, final boolean withBackReference) {
@@ -73,6 +73,19 @@ public class ObjectStubTree<T extends Stub> {
}
}
public void setDebugInfo(String info) {
ObjectStubTree ref = myRoot.getUserData(STUB_TO_TREE_REFERENCE);
if (ref != null) {
assert ref == this;
info += "; with backReference";
}
myDebugInfo = info;
}
public String getDebugInfo() {
return myDebugInfo;
}
private static class StubIndexSink implements IndexSink, TObjectProcedure<Map<Object, int[]>>,TObjectObjectProcedure<Object,int[]> {
private final THashMap<StubIndexKey, Map<Object, int[]>> myResult = new THashMap<StubIndexKey, Map<Object, int[]>>();
private int myStubIdx;
@@ -437,7 +437,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
msg += "; file stamp: " + file.getModificationStamp();
msg += "; file modCount: " + file.getModificationCount();
Document document = FileDocumentManager.getInstance().getDocument(file);
Document document = FileDocumentManager.getInstance().getCachedDocument(file);
if (document != null) {
msg += "\nsaved: " + !FileDocumentManager.getInstance().isDocumentUnsaved(document);
msg += "; doc stamp: " + document.getModificationStamp();
@@ -70,7 +70,9 @@ public class StubTreeLoaderImpl extends StubTreeLoader {
}
}
if (element instanceof PsiFileStub) {
return new StubTree((PsiFileStub)element);
StubTree tree = new StubTree((PsiFileStub)element);
tree.setDebugInfo("created from file content, timestamp=" + vFile.getTimeStamp());
return tree;
}
}
catch (IOException e) {
@@ -104,7 +106,9 @@ public class StubTreeLoaderImpl extends StubTreeLoader {
catch (SerializerNotFoundException e) {
return processError(vFile, "No stub serializer: " + vFile.getPresentableUrl() + ": " + e.getMessage(), e);
}
return stub instanceof PsiFileStub ? new StubTree((PsiFileStub)stub) : new ObjectStubTree((ObjectStubBase)stub, true);
ObjectStubTree tree = stub instanceof PsiFileStub ? new StubTree((PsiFileStub)stub) : new ObjectStubTree((ObjectStubBase)stub, true);
tree.setDebugInfo("created from index, index creation stamp=" + IndexInfrastructure.getIndexCreationStamp(StubUpdatingIndex.INDEX_ID) + "; index stamp=" + IndexingStamp.getIndexStamp(vFile, StubUpdatingIndex.INDEX_ID));
return tree;
}
else if (size != 0) {
return processError(vFile, "Twin stubs: " + vFile.getPresentableUrl() + " has " + size + " stub versions. Should only have one. id=" + id,