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.
Properties
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.
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.
Kept for the process, as the compiler keeps its own: the constructor is where the parser's members are looked up.
Functions
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.
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).
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.
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.
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.