AnalysisSession

The Analysis API over the running game: a standalone session whose one library module is the same widened classpath ReplHost compiles snippets against. Ask it what a name means; ReplHost is what runs it.

The two must see the identical classpath or an answer here can contradict what an eval does — hence the widened list, not a freshly enumerated one: private / protected / internal members are callable in a snippet only because the access-widen overlay opened them, and analysis has to be told the same story.

Everything is lazy. Building the session indexes the whole classpath, so the first call is expensive and every later one is free; drive it off-tick.

Types

Link copied to clipboard
class Built(val session: StandaloneAnalysisAPISession, val context: KaSourceModule)

Handed out together: a KtFile's context module must belong to the session that will analyze it, so neither half is meaningful without the other.

Link copied to clipboard
class Cursor(val file: KtFile, val element: KtElement, val prefix: String)

Where a query is being asked. element is what to hand analyze; filter candidates by prefix, since the element's own name carries the placeholder rather than what was typed.

Link copied to clipboard
class Editor(val file: KtFile)

One editing context — a connection, a pane, whatever owns a caret.

Properties

Link copied to clipboard
val context: KaSourceModule

What a snippet is analyzed against: an empty source module whose dependencies are the game's widened classpath and the running JDK.

Link copied to clipboard

The session, built on first access and then kept — the game's classpath is fixed by the time one exists, so there is nothing that could invalidate it. lazy retries rather than caching a failed build.

Link copied to clipboard

This class's own loader, exactly as ReplHost finds it — repl.impl.* is masking-owned. Null outside a masking launch (unit tests), where there is no parent kotlin to pin against either.

Link copied to clipboard
private val parser: SnippetParser

Kept for the process, as the compiler keeps its own: the constructor is where the parser's members are looked up.

Link copied to clipboard
val project: Project

Functions

Link copied to clipboard
Link copied to clipboard

A fresh editing context over code. Hold one per caret, and close it when that caret is gone.

Link copied to clipboard
private fun newFile(code: String): KtFile

An in-memory snippet, holding the same function-body parse an eval's source gets (see rewrite). Named SCRIPT_EXT for the same reason an eval's source is: it is the extension the script configurator that McpScriptRegistrar installs accepts.

Link copied to clipboard
private fun registerScriptExtensions(project: Project, owner: Disposable)

Teach the session the snippet's script shape, so its implicit ScriptScope receiver and its bare Patches / Probe imports resolve here too. The compiler's own McpScriptRegistrar — the relocated Analysis API and the embedded compiler share one FirExtensionRegistrar class — but not lowered: the body stays the initializer it parses to, since LL FIR rebuilds every body from PSI (see McpScriptConfigurator).

Link copied to clipboard
private fun rewrite(file: KtFile, text: String)

Swaps file's whole tree for SnippetParser.parsePsi's parse of text. The file object survives, so its module — and with it the analysis cache key — stays the one it already had. The modification stamp moves, which is what tells the session on that key to be rebuilt instead of reused stale.

Link copied to clipboard
private fun rootScope(project: Project, roots: List<Path>, opened: List<VirtualFile>, environment: CoreApplicationEnvironment): GlobalSearchScope

The library module's content scope, built here rather than left to the module builder: its default routes through VirtualFileUtil.toNioPathOrNull, and intellij-core ships a same-named facade without that method — it survives only in the @Metadata proto, so the call finds nothing and throws NoSuchMethodError the first time a module carries binary virtual files.

Link copied to clipboard
private fun splitRoots(widened: List<File>, jarFs: VirtualFileSystem): Pair<List<Path>, List<VirtualFile>>

Archives opened here, everything else left as a plain root. A binary root is read back by dispatching on endsWith("jar"), so an archive named otherwise — nested-jar extraction leaves *.jar.tmp and friends — would resolve as one opaque file with none of its classes visible. An eval is unaffected: the compiler indexes the same list its own way.