2016-01-14 19:38:06 -08:00

164 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>Stub Indexes / IntelliJ Platform SDK DevGuide</title>
<link rel="stylesheet" href="/intellij/sdk/docs/app/css/styles.min.css">
<!-- non-retina iPad pre iOS 7 -->
<link rel="apple-touch-icon" href="/intellij/sdk/docs/apple-touch-icon-72x72.png" sizes="72x72">
<!-- retina iPhone pre iOS 7 -->
<link rel="apple-touch-icon" href="/intellij/sdk/docs/apple-touch-icon-114x114.png" sizes="114x114">
<!-- retina iPad pre iOS 7 -->
<link rel="apple-touch-icon" href="/intellij/sdk/docs/apple-touch-icon-144x144.png" sizes="144x144">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/intellij/sdk/docs/apple-touch-icon-precomposed.png">
<!-- normal favicon -->
<link rel="shortcut icon" type="image/x-icon" href="/intellij/sdk/docs/favicon.ico">
<link rel="icon" type="image/png" href="/intellij/sdk/docs/favicon.png">
<link rel="stylesheet" href="/intellij/sdk/docs/styles/styles.css"></head>
<body data-id="basics/indexing_and_psi_stubs/stub_indexes">
<div class="wrapper">
<section class="panel _nav">
<header class="panel__header">
<div class="container">
<form class="search-box">
<label for="search-box__input" class="search-box__label">
<input type="text" class="search-box__input" id="search-box__input" placeholder="Search IntelliJ Platform SDK DevGuide">
</label>
<div class="search-box__clear" title="Clear"></div>
</form>
</div>
</header>
<nav class="panel__content">
<div class="container _nav">
<menu class="nav-tree"></menu>
</div>
<div class="container _footer panel__footer">
<p><a href="https://youtrack.jetbrains.com/issues/IJSDK">Send feedback</a></p>
<p>&copy; 2000&ndash;2016 <a href="//www.jetbrains.com">JetBrains</a> s.r.o.<br>
All rights reserved.</p>
</div>
</nav>
</section>
<main class="panel _main" role="main">
<header class="panel__header">
<div class="container">
<h3>IntelliJ Platform SDK DevGuide</h3>
<div class="shortcuts-switcher"><label for="switch-shortcuts">Keymap:</label><select id="switch-shortcuts" class="select _shortcuts" height="1">
<option data-group="primary" value="default" selected>Default</option>
<option data-group="primary" value="default_for_gnome">GNOME</option>
<option data-group="primary" value="default_for_kde">KDE</option>
<option data-group="primary" value="default_for_xwin">XWindow</option>
<option data-group="primary" value="emacs">Emacs</option>
<option data-group="primary" value="jbuilder">JBuilder</option>
<option data-group="primary" value="visual_studio">Visual Studio</option>
<option data-group="primary" value="netbeans_6.5">NetBeans 6.5</option>
<option data-group="primary" value="eclipse">Eclipse</option>
<option data-group="secondary" value="mac_os_x_10.5_">OS X 10.5+</option>
<option data-group="secondary" value="mac_os_x">OS X</option>
<option data-group="secondary" value="eclipse_mac_os_x">OS X Eclipse</option></select>
</div>
<div class="panel-trigger"></div>
</div>
</header>
<section class="panel__content">
<div class="container">
<article class="article" data-shortcut-switcher="false">
<h1>Stub Indexes</h1>
<a name="stub-trees" class="elem-anchor"></a>
<h2>Stub Trees<a href="#stub-trees" class="anchor-link"><span></span></a></h2>
<p>A stub tree is a subset of the PSI tree for a file; it is stored in a compact serialized binary format. The PSI tree for a file can be backed either by the AST (built by parsing the text of the file) or by the stub tree deserialized from disk. Switching between the two is transparent.</p>
<p>The stub tree contains only a subset of the nodes. Typically it contains only the nodes that are needed to resolve the declarations contained in this file from external files. Trying to access any node which is not part of the stub tree, or to perform any operation which cannot be satisfied by the stub tree, e.g. accessing the text of a PSI element, causes file parsing and switches the PSI to AST backing.</p>
<p>Each stub in the stub tree is simply a bean class with no behavior. A stub stores a subset of the state of the corresponding PSI element, like elements name, modifier flags like public or final, etc. The stub also holds a pointer to its parent in the tree and a list of its children stubs.</p>
<p>To support stubs for your custom language, you first need to decide which of the elements of your PSI tree should be stored as stubs. Typically you need to have stubs for things like methods or fields, which are visible from other files. You usually dont need to have stubs for things like statements or local variables, which are not visible externally.</p>
<p>For each element type that you want to store in the stub tree, you need to perform the following steps:</p>
<ul>
<li>Define an interface for the stub, derived from the <code class="code highlight language-text">StubElement</code> interface (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyStub.java" data-bypass="yes" target="_blank"><span>example</span></a>).</li>
<li>Provide an implementation for the interface (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyStubImpl.java" data-bypass="yes" target="_blank"><span>example</span></a>).</li>
<li>Make sure that the interface for the PSI element extends <code class="code highlight language-text">StubBasedPsiElement</code> parameterized by the type of the stub interface (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/Property.java" data-bypass="yes" target="_blank"><span>example</span></a>).</li>
<li>Make sure that the implementation class for the PSI element extends <code class="code highlight language-text">StubBasedPsiElementBase</code> parameterized by the type of the stub interface (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java" data-bypass="yes" target="_blank"><span>example</span></a><!--#L45-->). Provide both a constructor that accepts an <code class="code highlight language-text">ASTNode</code> and a constructor which accepts a stub.</li>
<li>Create a class which implements <code class="code highlight language-text">IStubElementType</code> and is parameterized with the stub interface and the actual PSI element interface (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertyStubElementType.java" data-bypass="yes" target="_blank"><span>example</span></a>). Implement the <code class="code highlight language-text">createPsi()</code> and <code class="code highlight language-text">createStub()</code> methods for creating PSI from a stub and vice versa. Implement the <code class="code highlight language-text">serialize()</code> and <code class="code highlight language-text">deserialize()</code> methods for storing the data in a binary stream.</li>
<li>Use the class implementing <code class="code highlight language-text">IStubElementType</code> as the element type constant when parsing (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertiesElementTypes.java" data-bypass="yes" target="_blank"><span>example</span></a>).</li>
<li>Make sure that all methods in the PSI element interface access the stub data rather than the PSI tree when appropriate (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java" data-bypass="yes" target="_blank"><span>example: Property.getKey() implementation</span></a><!--#L95-->).</li>
</ul>
<p>The following steps need to be performed only once for each language that supports stubs:</p>
<ul>
<li>Change the file element type for your language (the element type that you return from <code class="code highlight language-text">ParserDefinition.getFileNodeType()</code>) to a class that extends <code class="code highlight language-text">IStubFileElementType</code>.</li>
<li>In your <code class="code highlight language-text">plugin.xml</code>, define the <code class="code highlight language-text">&lt;stubElementTypeHolder&gt;</code> extension and specify the interface which contains the <code class="code highlight language-text">IElementType</code> constants used by your languages parser (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/plugins/properties/src/META-INF/plugin.xml" data-bypass="yes" target="_blank"><span>example</span></a><!--#L55-->).</li>
</ul>
<p>For serializing string data, e.g. element names, in stubs, we recommend to use <code class="code highlight language-text">StubOutputStream.writeName()</code> and <code class="code highlight language-text">StubInputStream.readName()</code> methods. These methods ensure that each unique identifier is stored only once in the data stream. This reduces the size of the serialized stub tree data.</p>
<p>If you need to change the stored binary format for the stubs (for example, if you want to store some additional data or some new elements), make sure that you advance the stub version returned from <code class="code highlight language-text">IStubFileElementType.getStubVersion()</code> for your language. This will cause the stubs and stub indices to be rebuilt, and will avoid mismatches between the stored data format and the code trying to load it.</p>
<p>By default, if a PSI element extends <code class="code highlight language-text">StubBasedPsiElement</code>, all elements of that type will be stored in the stub tree. If you need more precise control over which elements are stored, override <code class="code highlight language-text">IStubElementType.shouldCreateStub()</code> and return <code class="code highlight language-text">false</code> for elements which should not be included in the stub tree.</p>
<aside class="note">
<p> The exclusion is not recursive: if some elements of the element for which you returned false are also stub-based PSI elements, they will be included in the stub tree.</p>
</aside>
<p>Its essential to make sure that all information stored in the stub tree depends only on the contents of the file for which stubs are being built, and does not depend on any external files. Otherwise the stub tree will not be rebuilt when an external dependency changes, and you will have stale and incorrect data in the stub tree.</p>
<a name="stub-indexes" class="elem-anchor"></a>
<h2>Stub indexes<a href="#stub-indexes" class="anchor-link"><span></span></a></h2>
<p>When building the stub tree, you can at the same time put some data about the stub elements into a number of indexes, which then can be used to find the PSI elements by the corresponding key. Unlike file-based indexes, stub indexes do not support storing custom data as values; the value is always a PSI element. Keys in stub indexes are normally strings (such as class names); other data types are also supported if desired.</p>
<p>A stub index is a class which extends <a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/platform/indexing-api/src/com/intellij/psi/stubs/AbstractStubIndex.java" data-bypass="yes" target="_blank"><span><code class="code highlight language-text">AbstractStubIndex</code></span></a>. In the most common case, when the key type is <code class="code highlight language-text">String</code>, you use a more specific base class, namely <a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/platform/indexing-api/src/com/intellij/psi/stubs/StringStubIndexExtension.java" data-bypass="yes" target="_blank"><span>StringStubIndexExtension</span></a>. Stub index implementation classes are registered in the <code class="code highlight language-text">&lt;stubIndex&gt;</code> extension point.</p>
<p>To put data into an index, you implement the method <code class="code highlight language-text">IStubElementType.indexStub()</code> (<a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-1731d054af4ca27aa827c03929e27eeb0e6a8366/psi/impl/java/stubs/JavaClassElementType.java" data-bypass="yes" target="_blank"><span>example: JavaClassElementType.indexStub()</span></a><!--#L189-->). This method accepts an <code class="code highlight language-text">IndexSink</code> as a parameter, and puts in the index ID and the key for each index in which the element should be stored.</p>
<p>To access the data from an index, the following two methods are used:</p>
<ul>
<li><code class="code highlight language-text">AbstractStubIndex.getAllKeys()</code> returns the list of all keys in the specified index for the specified project (for example, the list of all class names found in the project).</li>
<li><code class="code highlight language-text">AbstractStubIndex.get()</code> returns the collection of PSI elements corresponding to a certain key (for example, classes with the specified short name) in the specified scope.</li>
</ul>
<a name="related-forum-discussions" class="elem-anchor"></a>
<h2>Related Forum Discussions<a href="#related-forum-discussions" class="anchor-link"><span></span></a></h2>
<ul>
<li><a href="https://devnet.jetbrains.com/message/5485343" data-bypass="yes" target="_blank"><span>Lifecycle of stub creation</span></a></li>
</ul>
<div class="last-modified">
Last modified: 21 December 2015
</div>
</article>
<section class="disqus">
<div id="disqus_thread"></div>
</section>
</div>
</section>
</main>
</div>
<script data-main="/intellij/sdk/docs/app/js/main.build" data-baseurl="/intellij/sdk/docs/" src="/intellij/sdk/docs/app/js/vendor/requirejs/require.js"></script>
</body>
</html>