problems creating stub tree

I'm trying to integrate StubTrees for fast access to some data of my psi-elements. I implemented everything according to the documentation here: .
My problem is that my PSI-elements are never backed by stubs.
In my implementation of IStubElementType the createStub- the serialize-, and deserialize-Methods are called. But the createPsi-Method is never called and the getStub-Method always returns null.

Here is the source of my very simple test language plugin:

public interface ItemStub extends StubElement<Item>{     List<String> getTokens(); }

public class ItemStubImpl extends StubBase<Item> implements ItemStub {     private List<String> tokens;     public ItemStubImpl(StubElement parent, List<String> tokens) {         super(parent, SimpleTypes.ITEM);         this.tokens = tokens;     }     @Override     public List<String> getTokens() {         return tokens;     }     public void setTokens(List<String> tokens) {         this.tokens = tokens;     } }

public class ItemStubElementImpl <T extends StubElement> extends StubBasedPsiElementBase<T> {     public ItemStubElementImpl(@NotNull T stub, @NotNull IStubElementType nodeType) {         super(stub, nodeType);     }     public ItemStubElementImpl(@NotNull ASTNode node) {         super(node);     } }

public interface Item extends StubBasedPsiElement<ItemStub> {     List<String> getTokens(); }

public class ItemImpl extends ItemStubElementImpl<ItemStub> implements Item{     public ItemImpl(final @NotNull ItemStub stub, final @NotNull IStubElementType nodeType) {         super(stub, nodeType);     }     public ItemImpl(@NotNull ASTNode node) {         super(node);     }     public List<String> getTokens(){         ItemStub stub = getStub();         if(stub != null) {
            // unfortunately I never reach this point. My stub is always null             System.out.println("loaded from stub yeah");             List<String> tokens = stub.getTokens();             return tokens;         }         ASTNode[] children = getNode().getChildren(TokenSet.create(SimpleTypes.TOKEN));         List<String> tokens = new ArrayList<String>();         for (ASTNode child : children) {             String text = child.getText();             tokens.add(text);         }         return tokens;     } }

public class SimpleElementType extends IStubElementType<ItemStub, Item> {     public SimpleElementType(@NotNull @NonNls String debugName) {         super(debugName, SimpleLanguage.INSTANCE);     }     @Override     public Item createPsi(@NotNull ItemStub stub) {         return new ItemImpl(stub, this);     }     @Override     public ItemStub createStub(@NotNull Item psi, StubElement parentStub) {
        // this is called for every Item           List<String> tokens = psi.getTokens();         ItemStubImpl itemStub = new ItemStubImpl(parentStub, tokens);         return itemStub;     }     @Override     public String getExternalId() {         return null;     }     @Override     public void serialize(ItemStub stub, StubOutputStream dataStream) throws IOException {
        // this is called         List<String> tokens = stub.getTokens();         String join = StringUtils.join(tokens, ",");         dataStream.writeName(join);     }     @Override     public ItemStub deserialize(StubInputStream dataStream, StubElement parentStub) throws IOException {
        // this is called         StringRef stringRef = dataStream.readName();         if(stringRef == null) {             return null;         }         String string = stringRef.getString();         String[] split = string.split(",");         List<String> tokens = new ArrayList<String>();         for (String s : split) {             tokens.add(s);         }         ItemStubImpl itemStub = new ItemStubImpl(parentStub, tokens);         return itemStub;     }     @Override     public void indexStub(ItemStub stub, IndexSink sink) {         // TODO later     } }

Sorry to just offer the source and hoping that someone finds the error, but I'm not able to find any hints in the web, so I would be very thankful if someone could put me in the right direction,

Comment actions Permalink

One thing to bear in mind is that stubs are generally used to create a lightweight partial PSI tree which is used for global symbol resolution. It looks like your stub code is working correctly based on the methods you're seeing being called, what I suspect is that in your testing you're never performing operations which will require stubs to be used. If you're testing with files that are open in an editor, for example, stubs will be created (as you're seeing) but never actually used since the editor always has the full PSI after parsing the file. Do you have some code that accesses the PSI in a way that would need stubs to be used?

Comment actions Permalink

Hallo Colin, thank you for that hint. In fact I always used two test-files that were opened in the editor. Nevertheless changing that didn't have the effect that the stubs were used.
Maybe the problem is that my test-action forces Intellij to parse all the files and so no need for stub access is given.
That is the action I used:

public class TestAction extends AnAction {     public void actionPerformed(AnActionEvent e) {         List<SimpleFile> results = new ArrayList<SimpleFile>();         Collection<VirtualFile> virtualFiles = FileBasedIndex.getInstance().getContainingFiles(FileTypeIndex.NAME,                 SimpleFileType.INSTANCE, GlobalSearchScope.allScope(e.getProject()));         for (VirtualFile virtualFile : virtualFiles) {                 PsiFile file = PsiManager.getInstance(e.getProject()).findFile(virtualFile);                 results.add((SimpleFile)file);         }         for (SimpleFile result : results) {             Item[] childrenByClass = result.findChildrenByClass(Item.class);             for (Item childrenByClas : childrenByClass) {                 List<String> tokens = childrenByClas.getTokens();                 for (String token : tokens) {                     System.out.println(token);                 }             }         }     } }

I guess I still have a problem understanding the stubs. This is the workflow how I understood it:
1. When some functionality tries to access some psi-data, intellij checks if the psi-element  was parsed?
2. If it was parsed, no reason to use stubs so no stub is deserialized from disk?
3. If it was not parsed, Intellij loads the stub from disk. If the stub can offer the needed data nothing will be parsed? If the stub can't offer the needed data the file gets parsed?

Bit confused and thankful for any help,


Please sign in to leave a comment.