oracle

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 11, 2026 License: MIT Imports: 38 Imported by: 0

Documentation

Index

Constants

View Source
const CacheVersion = 2

CacheVersion is bumped whenever the on-disk entry layout changes in a way that invalidates previously-written entries. A version mismatch on read is treated as a miss and the offending entry is deleted.

Variables

View Source
var ErrDaemonFileNotInSession = errors.New("daemon: file not in source module")

ErrDaemonFileNotInSession is returned by Daemon.AnalyzeWithDeps when the daemon's response errors map contains any "File not found in source module" entries. Callers use errors.Is to recognize the condition and trigger a daemon Rebuild + retry before falling through to one-shot.

Functions

func CacheDir

func CacheDir(repoDir string) (string, error)

CacheDir returns the cache root for a repo. The directory is created if it doesn't exist.

func CachePath

func CachePath(scanPaths []string) string

CachePath returns the path for the cached oracle JSON.

func CacheStats

func CacheStats(cacheDir string) (count int, bytes int64, err error)

CacheStats walks the entries directory for reporting (count, byte size). Used by the CLI -verbose path and by the end-to-end benchmark script.

func CollectKtFiles

func CollectKtFiles(sourceDirs []string) ([]string, error)

CollectKtFiles walks the given source directories and returns absolute paths of all .kt files. Mirrors the directory pruning FindSourceDirs does (build/.gradle/.git/node_modules) so the Go-side enumeration matches what the JVM side will actually see. Also applies the krit-types default exclude patterns so excluded files don't leak into the cache miss list.

func ContentHash

func ContentHash(path string) (string, error)

ContentHash returns the content hash of the file at path in lowercase hex. Used both as the cache key and as the building block for closure fingerprints. Routed through the process-scoped hashutil.Memo so the same file hashed by multiple cache subsystems within one run only pays the hash cost once.

func FindJar

func FindJar(scanPaths []string) string

FindJar locates the krit-types shadow JAR by checking: 1. Next to the krit binary (tools/krit-types/build/libs/krit-types.jar) 2. In the project being scanned (.krit/krit-types.jar) 3. Relative to the krit binary's directory

func FindRepoDir

func FindRepoDir(scanPaths []string) string

FindRepoDir picks the repo root for repo-local Krit state.

func FindSourceDirs

func FindSourceDirs(scanPaths []string) []string

FindSourceDirs discovers Kotlin source directories under the given paths.

func IndexCacheHashes

func IndexCacheHashes(cacheDir string) map[string]bool

IndexCacheHashes walks the legacy cache entries directory once and returns a set of content hashes that have a legacy JSON entry on disk. Packed entries are indexed per shard when the shard is loaded.

Returned map is nil on directory walk error; callers treat nil the same as "don't trust the index, fall back to per-file LoadEntry".

func Invoke

func Invoke(jarPath string, sourceDirs []string, outputPath string, verbose bool) (string, error)

Invoke runs krit-types.jar to produce a type oracle JSON file. It enforces a hard timeout (KRIT_TYPES_TIMEOUT, default 5m) and a soft grace period (KRIT_TYPES_GRACE_EXIT, default 15s) that starts once the output file appears on disk. The grace period exists because krit-types.jar has been observed to hang after writing its output when Analysis API background threads keep the JVM alive — once the output is complete we can force-kill the subprocess without losing work.

On failure, the returned error includes the first few lines of the subprocess's captured stderr (up to 8 KB tail) so the caller can surface a diagnostic instead of a bare exit code. On success the output path is returned even when the grace period fired — the caller is responsible for validating the JSON via oracle.Load / oracle.LoadFromData.

func InvokeCached

func InvokeCached(
	jarPath string,
	sourceDirs []string,
	repoDir string,
	outputPath string,
	filterListPath string,
	verbose bool,
	s *store.FileStore,
) (string, error)

InvokeCached is the cache-aware variant of Invoke. It walks sourceDirs, classifies .kt files into hits and misses via the on-disk cache, runs krit-types only on misses (with --files + --cache-deps-out), writes new cache entries, and assembles the final oracle JSON at outputPath.

filterListPath (optional, "" = no filter) is a path to a newline-separated list of absolute .kt paths produced by the rule-classification pre-scan. When present, it narrows the universe of files the cache classifies — files not in the filter are neither looked up nor analyzed, since no enabled rule cares about them. Rule filtering and per-file caching thus compose: filter narrows first, cache dedupes what remains.

Returns the output path on success. If no files were discovered or the cache can't be created, the function falls back to a plain Invoke so the caller still gets a complete oracle. InvokeCached is the cache-aware variant of Invoke. s is the optional unified store; when non-nil, oracle cache entries are read from and written to s instead of the legacy cacheDir file layout.

func InvokeCachedWithOptions

func InvokeCachedWithOptions(
	jarPath string,
	sourceDirs []string,
	repoDir string,
	outputPath string,
	filterListPath string,
	verbose bool,
	s *store.FileStore,
	opts InvocationOptions,
) (string, error)

InvokeCachedWithOptions is InvokeCached plus optional deep perf instrumentation for the cache/filter/JVM path.

func InvokeWithFiles

func InvokeWithFiles(jarPath string, sourceDirs []string, outputPath, filesListPath string, verbose bool) (string, error)

InvokeWithFiles is identical to Invoke but additionally passes a --files LISTFILE flag to krit-types if filesListPath is non-empty. LISTFILE is expected to contain one absolute .kt path per line and is produced by the rule-classification oracle filter (oracle.CollectOracleFiles + oracle.WriteFilterListFile). krit-types still builds the FIR session from the full --sources tree so that cross-file resolution works; the flag only narrows which files contribute expressions/declarations to the output JSON.

func InvokeWithFilesWithOptions

func InvokeWithFilesWithOptions(jarPath string, sourceDirs []string, outputPath, filesListPath string, verbose bool, opts InvocationOptions) (string, error)

InvokeWithFilesWithOptions is InvokeWithFiles plus optional perf instrumentation. The krit-types output schema stays unchanged; Kotlin-side timings are captured through a temporary --timings-out sidecar when a tracker is enabled.

func PreloadPath added in v0.2.0

func PreloadPath(path string)

PreloadPath kicks off oracle JSON deserialization for path and keeps the result available for any later LazyLookup created for the same file.

func RenderSignatureStub

func RenderSignatureStub(jarPath, fqn string, cls *Class) string

RenderSignatureStub produces the placeholder Kotlin source for one FQN. Exposed for tests and for callers that want to render without going through the cache.

func SetReporter

func SetReporter(r *diag.Reporter)

SetReporter installs r as the package-level Reporter used for verbose and warning output. Passing nil restores a default warnings-only Reporter so library code never panics on a nil dereference.

func StableFingerprint

func StableFingerprint(paths []string, root string) string

StableFingerprint returns a fingerprint of paths that is invariant under repository checkout location: each path is rewritten relative to root (slash-normalised) before hashing. Paths outside root fall back to their basename. An empty input returns the fingerprint of the empty set (matches fingerprintPaths(nil)).

The CI oracle-fingerprint gate uses this instead of the absolute- path fingerprint emitted in perf output, since baseline files are checked in and must match across every contributor's checkout.

func VerifyClosure

func VerifyClosure(entry *CacheEntry, hashCache map[string]string) bool

VerifyClosure recomputes the dep-closure fingerprint from disk and compares against the entry's stored fingerprint. Returns true iff the two match. Any I/O error while reading deps is treated as a miss. Crashed entries bypass closure verification: they have no dep list by construction (the crash happened before any deps were collected), and their validity is content-hash-only — if the bytes that crashed before are unchanged, the same crash will deterministically recur.

hashCache can be nil (cold path) or a shared map (ClassifyFiles passes its own map so multiple VerifyClosure calls share content-hash results across the whole classify pass).

func WriteCallTargetFilterFile

func WriteCallTargetFilterFile(summary CallTargetFilterSummary, tmpDir string) (string, error)

WriteCallTargetFilterFile writes the callee filter JSON consumed by krit-types --call-filter. Disabled summaries return an empty path.

func WriteEntry

func WriteEntry(cacheDir string, entry *CacheEntry) error

WriteEntry atomically writes a cache entry: temp file in the same directory, then rename into place. This avoids torn writes if the process crashes mid-write.

func WriteEntryToStore

func WriteEntryToStore(s *store.FileStore, entry *CacheEntry) error

WriteEntryToStore persists a CacheEntry in s keyed by its content hash.

func WriteFilterListFile

func WriteFilterListFile(summary FilterSummary, tmpDir string) (string, error)

WriteFilterListFile writes the filter's matched paths to a temp file that krit-types can read via its --files flag. Returns the written path or an error. Callers should clean up the file after the oracle run. When AllFiles is true or the Paths list is nil, returns an empty string and no error — the caller is expected to skip the --files flag entirely in that case.

func WriteFreshEntries

func WriteFreshEntries(
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
) (int, error)

WriteFreshEntries writes cache entries for the files that krit-types just analyzed. For each fresh FileResult, it looks up the corresponding dep fragment in the CacheDepsFile, computes the closure fingerprint from the current disk state of the dep paths, and writes an atomic entry under cacheDir. Shares a content-hash memoization across all per-entry closure computations so shared dependency closures are read once.

func WriteFreshEntriesToStore

func WriteFreshEntriesToStore(
	s *store.FileStore,
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
) (int, error)

WriteFreshEntriesToStore is like WriteFreshEntries but writes to s instead of the legacy cacheDir layout. Falls back to WriteFreshEntries when s is nil.

func WriteFreshEntriesToStoreWithTracker

func WriteFreshEntriesToStoreWithTracker(
	s *store.FileStore,
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
	tracker perf.Tracker,
) (int, error)

func WriteFreshEntriesToStoreWithTrackerScoped

func WriteFreshEntriesToStoreWithTrackerScoped(
	s *store.FileStore,
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
	tracker perf.Tracker,
	callFilterFingerprint string,
) (int, error)

func WriteFreshEntriesToStoreWithTrackerScopedV2

func WriteFreshEntriesToStoreWithTrackerScopedV2(
	s *store.FileStore,
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
	tracker perf.Tracker,
	callFilterFingerprint, declarationProfileFingerprint string,
) (int, error)

func WriteFreshEntriesWithTracker

func WriteFreshEntriesWithTracker(
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
	tracker perf.Tracker,
) (int, error)

func WriteFreshEntriesWithTrackerScoped

func WriteFreshEntriesWithTrackerScoped(
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
	tracker perf.Tracker,
	callFilterFingerprint string,
) (int, error)

func WriteFreshEntriesWithTrackerScopedV2

func WriteFreshEntriesWithTrackerScopedV2(
	cacheDir string,
	fresh *Data,
	deps *CacheDepsFile,
	tracker perf.Tracker,
	callFilterFingerprint, declarationProfileFingerprint string,
) (int, error)

Types

type CacheClosure

type CacheClosure struct {
	DepPaths    []string `json:"dep_paths"`
	Fingerprint string   `json:"fingerprint"`
}

CacheClosure records this file's direct source-file dependencies and the fingerprint computed over their content at write time.

type CacheDepsEntry

type CacheDepsEntry struct {
	DepPaths    []string          `json:"depPaths"`
	PerFileDeps map[string]*Class `json:"perFileDeps"`
}

CacheDepsEntry is one file's dep-closure fragment.

type CacheDepsFile

type CacheDepsFile struct {
	Version       int                        `json:"version"`
	Approximation string                     `json:"approximation"`
	Files         map[string]*CacheDepsEntry `json:"files"`
	Crashed       map[string]string          `json:"crashed,omitempty"`
}

CacheDepsFile is the schema of the --cache-deps-out JSON emitted by krit-types. Keys in Files are source file paths. Crashed maps a file path to the short error string for files whose analyzeKtFile outer catch fired — those get poison-marker entries instead of regular ones.

func LoadCacheDeps

func LoadCacheDeps(path string) (*CacheDepsFile, error)

LoadCacheDeps reads the --cache-deps-out JSON produced by krit-types.

type CacheEntry

type CacheEntry struct {
	V           int               `json:"v"`
	ContentHash string            `json:"content_hash"`
	FilePath    string            `json:"file_path"`
	FileResult  *File             `json:"file_result"`
	PerFileDeps map[string]*Class `json:"per_file_deps,omitempty"`
	Closure     CacheClosure      `json:"closure"`
	// CallFilterFingerprint is empty for unfiltered/broad oracle entries.
	// Filtered entries only satisfy lookups for the same filter. Unfiltered
	// entries are a safe superset and can satisfy filtered runs.
	CallFilterFingerprint string `json:"call_filter_fingerprint,omitempty"`
	// DeclarationProfileFingerprint is empty for entries produced with the
	// full declaration export profile (pre-profile behavior). Narrow-profile
	// entries only satisfy lookups at the same fingerprint — the
	// broader-superset rule that applies to CallFilterFingerprint also
	// applies here: empty = contains every field = satisfies any lookup.
	DeclarationProfileFingerprint string `json:"declaration_profile_fingerprint,omitempty"`
	// Approximation tags the dep-closure tracking method used when the
	// entry was written. Any mismatch with the current runtime's
	// approximation is treated as a miss — lets us upgrade the tracker
	// without leaving stale entries from a weaker approximation lying
	// around.
	Approximation string `json:"approximation,omitempty"`
	// Crashed marks this entry as a poison marker: the file with this
	// exact content deterministically crashes krit-types during analysis.
	// FileResult and PerFileDeps are nil for crash entries; they contribute
	// nothing to the assembled oracle. ClassifyFiles still returns them as
	// hits so the caller skips JVM launch. Invalidated automatically on a
	// content-hash change (content edit) or a CacheVersion bump (Kotlin or
	// krit-types upgrade).
	Crashed    bool   `json:"crashed,omitempty"`
	CrashError string `json:"crash_error,omitempty"`
}

CacheEntry is one file's cached oracle analysis. The JSON field names are intentionally short because there can be tens of thousands of these in a single repo.

func ClassifyFiles

func ClassifyFiles(cacheDir string, paths []string) (hits []*CacheEntry, misses []string)

ClassifyFiles partitions paths into cache hits and cache misses. For each input path it computes the content hash, loads any matching entry, and verifies the closure fingerprint. Errors on individual files degrade to a miss for that file (with a best-effort cleanup of the corrupt entry) so a single bad entry can't poison the whole run.

Performance: ClassifyFiles keeps one pack store per pass, so each requested pack shard is loaded at most once, and builds an in-memory index for the legacy fallback directory. It also shares a single content-hash memoization map across all VerifyClosure calls in the pass.

The returned `hits` slice has one entry per hit with `FilePath` already set to the canonical path (synthesized if the stored entry was written for a content-identical but differently-named file). The `misses` slice contains the subset of `paths` that need to be sent to krit-types.

func ClassifyFilesScoped

func ClassifyFilesScoped(cacheDir string, paths []string, callFilterFingerprint string) (hits []*CacheEntry, misses []string)

func ClassifyFilesScopedV2

func ClassifyFilesScopedV2(cacheDir string, paths []string, callFilterFingerprint, declarationProfileFingerprint string) (hits []*CacheEntry, misses []string)

func ClassifyFilesWithStore

func ClassifyFilesWithStore(s *store.FileStore, cacheDir string, paths []string) (hits []*CacheEntry, misses []string)

ClassifyFilesWithStore is like ClassifyFiles but reads from s instead of the legacy cacheDir layout. Falls back to ClassifyFiles(cacheDir, paths) when s is nil.

func ClassifyFilesWithStoreScoped

func ClassifyFilesWithStoreScoped(s *store.FileStore, cacheDir string, paths []string, callFilterFingerprint string) (hits []*CacheEntry, misses []string)

func ClassifyFilesWithStoreScopedV2

func ClassifyFilesWithStoreScopedV2(s *store.FileStore, cacheDir string, paths []string, callFilterFingerprint, declarationProfileFingerprint string) (hits []*CacheEntry, misses []string)

ClassifyFilesWithStoreScopedV2 is ClassifyFilesWithStoreScoped extended with the declaration profile fingerprint. Entries are treated as hits only when both the call filter and declaration profile scopes are compatible; the usual "empty fingerprint = broad superset" rule applies to both axes.

func LoadEntry

func LoadEntry(cacheDir, hash string) (*CacheEntry, error)

LoadEntry reads and parses a cache entry from the packed backend, falling back to the legacy per-entry JSON file if the pack is missing or corrupt. Returns (nil, nil) if neither backend has the entry. Corrupt JSON returns an error so the caller can degrade to a miss.

func LoadEntryFromStore

func LoadEntryFromStore(s *store.FileStore, contentHash string) (*CacheEntry, error)

LoadEntryFromStore retrieves a CacheEntry from s by content hash. Returns (nil, nil) on a miss. Treats any malformed value as a miss.

type CacheWriter

type CacheWriter struct {
	// contains filtered or unexported fields
}

CacheWriter defers per-file oracle cache-entry writes out of the caller's critical path. It keeps entry-level counters on top of the generic async writer, whose stats are job-oriented.

func NewCacheWriter

func NewCacheWriter(workers int) *CacheWriter

NewCacheWriter starts a bounded writer for oracle cache entries. Worker counts below one are clamped and counts above four are capped to keep cold-cache persistence from competing too aggressively with analysis work.

func (*CacheWriter) AddPerfEntries

func (w *CacheWriter) AddPerfEntries(t perf.Tracker, storeBacked bool)

func (*CacheWriter) Close

func (w *CacheWriter) Close() error

func (*CacheWriter) Flush

func (w *CacheWriter) Flush(ctx context.Context) error

Flush waits for queued writes to finish. A canceled context returns early, but the underlying writer continues draining in its goroutine.

func (*CacheWriter) QueueFreshEntries

func (w *CacheWriter) QueueFreshEntries(cacheDir string, fresh *Data, deps *CacheDepsFile) (int, error)

QueueFreshEntries queues fresh oracle cache entries. If the writer is nil, the existing synchronous path is used.

func (*CacheWriter) QueueFreshEntriesToStore

func (w *CacheWriter) QueueFreshEntriesToStore(s *store.FileStore, cacheDir string, fresh *Data, deps *CacheDepsFile) (int, error)

QueueFreshEntriesToStore queues fresh oracle cache entries, writing to the unified store when s is non-nil. Queue saturation falls back to running that batch synchronously so cache persistence remains best-effort complete.

func (*CacheWriter) QueueFreshEntriesToStoreScoped

func (w *CacheWriter) QueueFreshEntriesToStoreScoped(s *store.FileStore, cacheDir string, fresh *Data, deps *CacheDepsFile, callFilterFingerprint string) (int, error)

QueueFreshEntriesToStoreScoped is QueueFreshEntriesToStore with cache compatibility metadata for filtered oracle call-target output.

func (*CacheWriter) QueueFreshEntriesToStoreScopedV2

func (w *CacheWriter) QueueFreshEntriesToStoreScopedV2(s *store.FileStore, cacheDir string, fresh *Data, deps *CacheDepsFile, callFilterFingerprint, declarationProfileFingerprint string) (int, error)

QueueFreshEntriesToStoreScopedV2 extends QueueFreshEntriesToStoreScoped with the declaration profile fingerprint. Entries written here carry both scope fingerprints so classify lookups can gate on either axis.

func (*CacheWriter) Stats

func (w *CacheWriter) Stats() CacheWriterStats

type CacheWriterStats

type CacheWriterStats struct {
	Queued                 int64
	Completed              int64
	Failed                 int64
	Bytes                  int64
	PoisonWrites           int64
	DepPaths               int64
	UniqueDepPaths         int64
	ContentHashDuration    time.Duration
	ClosureFingerprintTime time.Duration
	MarshalDuration        time.Duration
	StorePutDuration       time.Duration
	AtomicWriteDuration    time.Duration
	PackWrites             int64
}

CacheWriterStats is a point-in-time snapshot of deferred oracle cache writes. Durations are aggregate worker time, not wall-clock flush duration.

type CallTargetFilterSummary

type CallTargetFilterSummary struct {
	Enabled              bool
	DisabledBy           []string
	CalleeNames          []string
	TargetFQNs           []string
	LexicalHintsByCallee map[string][]string
	LexicalSkipByCallee  map[string][]string
	RuleProfiles         []CallTargetRuleProfile
	Fingerprint          string
}

CallTargetFilterSummary is the Go-side contract for narrowing JVM resolveToCall() work. Enabled=false means at least one active rule needs broad call targets, so krit-types must preserve the pre-filter behavior.

func FinalizeCallTargetFilter

func FinalizeCallTargetFilter(summary CallTargetFilterSummary) CallTargetFilterSummary

FinalizeCallTargetFilter sorts, deduplicates, derives simple callee names from FQNs, and computes a stable fingerprint. Callers that build summaries directly should run this before writing or passing the filter onward.

type CallTargetRuleProfile

type CallTargetRuleProfile struct {
	RuleID               string              `json:"ruleID"`
	AllCalls             bool                `json:"allCalls"`
	DiscardedOnly        bool                `json:"discardedOnly,omitempty"`
	CalleeNames          []string            `json:"calleeNames,omitempty"`
	TargetFQNs           []string            `json:"targetFQNs,omitempty"`
	LexicalHintsByCallee map[string][]string `json:"lexicalHintsByCallee,omitempty"`
	LexicalSkipByCallee  map[string][]string `json:"lexicalSkipByCallee,omitempty"`
	AnnotatedIdentifiers []string            `json:"annotatedIdentifiers,omitempty"`
	DerivedCalleeNames   []string            `json:"derivedCalleeNames,omitempty"`
	DisabledReason       string              `json:"disabledReason,omitempty"`
}

CallTargetRuleProfile carries per-rule filtering metadata. The JVM uses these profiles to decide whether a matching lexical call site should be resolved, so they are part of the effective filter fingerprint.

type Class

type Class struct {
	FQN            string    `json:"fqn"`
	Kind           string    `json:"kind"` // class, interface, object, enum, sealed class, sealed interface
	Supertypes     []string  `json:"supertypes"`
	IsSealed       bool      `json:"isSealed"`
	IsData         bool      `json:"isData"`
	IsOpen         bool      `json:"isOpen"`
	IsAbstract     bool      `json:"isAbstract"`
	Visibility     string    `json:"visibility"`
	TypeParameters []string  `json:"typeParameters,omitempty"`
	Members        []*Member `json:"members,omitempty"`
	Annotations    []string  `json:"annotations,omitempty"` // FQNs
	Line           int       `json:"line,omitempty"`        // 1-based source line when known
	Column         int       `json:"column,omitempty"`      // 1-based source column when known
	JARPath        string    `json:"jarPath,omitempty"`     // dependency JAR containing this class, when known
}

Class describes a class, interface, object, or enum.

type CompositeResolver

type CompositeResolver struct {
	// contains filtered or unexported fields
}

CompositeResolver wraps a Lookup oracle with a fallback TypeResolver. Oracle provides dependency types; fallback provides source-level inference.

func NewCompositeResolver

func NewCompositeResolver(oracle Lookup, fallback typeinfer.TypeResolver) *CompositeResolver

NewCompositeResolver creates a resolver that checks the oracle first for dependency types and falls back to the tree-sitter resolver for source types.

func (*CompositeResolver) AnnotationValueFlat

func (c *CompositeResolver) AnnotationValueFlat(idx uint32, file *scanner.File, annotationName, argName string) string

func (*CompositeResolver) ClassHierarchy

func (c *CompositeResolver) ClassHierarchy(typeName string) *typeinfer.ClassInfo

ClassHierarchy checks oracle first (has dependency types), then fallback.

func (*CompositeResolver) EnumEntries

func (c *CompositeResolver) EnumEntries(enumTypeName string) []string

EnumEntries checks oracle first, then fallback.

func (*CompositeResolver) Fallback

Fallback returns the source-level TypeResolver wrapped by this composite. The dispatcher hands this out as ctx.Resolver for rules that declare TypeInfo.PreferBackend = PreferResolver so they avoid the oracle IPC for every lookup.

func (*CompositeResolver) IndexFilesParallel

func (c *CompositeResolver) IndexFilesParallel(files []*scanner.File, workers int)

IndexFilesParallel delegates to the fallback resolver's indexing.

func (*CompositeResolver) IndexFilesParallelWithTracker

func (c *CompositeResolver) IndexFilesParallelWithTracker(files []*scanner.File, workers int, tracker perf.Tracker)

func (*CompositeResolver) IsExceptionSubtype

func (c *CompositeResolver) IsExceptionSubtype(a, b string) bool

IsExceptionSubtype checks oracle first (full hierarchy), then fallback.

func (*CompositeResolver) IsNullableFlat

func (c *CompositeResolver) IsNullableFlat(idx uint32, file *scanner.File) *bool

func (*CompositeResolver) Oracle

func (c *CompositeResolver) Oracle() Lookup

Oracle returns the underlying oracle Lookup, allowing rules to call LookupAnnotations, LookupCallTarget, etc. directly.

func (*CompositeResolver) ResolveByNameFlat

func (c *CompositeResolver) ResolveByNameFlat(name string, idx uint32, file *scanner.File) *typeinfer.ResolvedType

func (*CompositeResolver) ResolveFlatNode

func (c *CompositeResolver) ResolveFlatNode(idx uint32, file *scanner.File) *typeinfer.ResolvedType

func (*CompositeResolver) ResolveImport

func (c *CompositeResolver) ResolveImport(simpleName string, file *scanner.File) string

ResolveImport checks fallback first, then oracle dependencies.

func (*CompositeResolver) SealedVariants

func (c *CompositeResolver) SealedVariants(sealedTypeName string) []string

SealedVariants checks oracle first, then fallback.

type Daemon

type Daemon struct {
	// contains filtered or unexported fields
}

Daemon manages a long-lived krit-types JVM process for on-demand type resolution.

func ConnectOrStartDaemon

func ConnectOrStartDaemon(jarPath string, sourceDirs []string, classpath []string, verbose bool) (*Daemon, error)

ConnectOrStartDaemon tries to reuse an existing persistent daemon for the given sourceDirs. Each repo has its own PID file under ~/.krit/cache/daemons/{hash}.{pid,port} so multiple daemons (one per repo) can coexist; krit invocations targeting different repos don't fight over a shared PID file. If no daemon is running (or the existing one is unresponsive), cleanStaleDaemon wipes just this repo's entry and StartDaemonWithPort starts a fresh one.

func InvokeDaemon

func InvokeDaemon(scanPaths []string, verbose bool) (*Daemon, error)

InvokeDaemon finds the JAR and source directories, then starts a long-lived krit-types daemon process. The caller is responsible for calling Close() on the returned Daemon.

func InvokePersistentDaemon

func InvokePersistentDaemon(scanPaths []string, verbose bool) (*Daemon, error)

InvokePersistentDaemon finds the JAR and source directories, then either connects to an existing persistent daemon or starts a new one. The daemon survives across krit invocations and is reused via PID file + TCP port. The caller is responsible for calling Close() on the returned Daemon.

func StartDaemon

func StartDaemon(jarPath string, sourceDirs []string, classpath []string, verbose bool) (*Daemon, error)

StartDaemon launches the krit-types JVM process in daemon mode.

func StartDaemonWithPort

func StartDaemonWithPort(jarPath string, sourceDirs []string, classpath []string, verbose bool) (*Daemon, error)

StartDaemonWithPort launches the krit-types JVM process in daemon mode with a TCP listener. The daemon auto-assigns a port and reports it on stdout.

func StartDaemonWithPortSlot

func StartDaemonWithPortSlot(jarPath string, sourceDirs []string, classpath []string, verbose bool, slot int) (*Daemon, error)

func (*Daemon) Analyze

func (d *Daemon) Analyze(files []string) (*Data, error)

Analyze sends an incremental analysis request for specific files.

func (*Daemon) AnalyzeAll

func (d *Daemon) AnalyzeAll() (*Data, error)

AnalyzeAll sends a full analysis request for all files.

func (*Daemon) AnalyzeAllWithCallFilter

func (d *Daemon) AnalyzeAllWithCallFilter(callFilter *CallTargetFilterSummary) (*Data, error)

AnalyzeAllWithCallFilter sends a full analysis request for all files, optionally narrowing call-target resolution in the JVM oracle.

func (*Daemon) AnalyzeWithDeps

func (d *Daemon) AnalyzeWithDeps(files []string) (*Data, *CacheDepsFile, error)

AnalyzeWithDeps is the cache-aware variant of Analyze. It asks the daemon to run analysis with a DepTracker instrumented per file and returns both the Data AND the per-file dep closure the Go-side cache layer needs to write fresh entries.

The response envelope has a flat shape with `result`, `errors`, and `cacheDeps` as siblings (unlike the legacy `analyze` which nests errors inside result). A missing `cacheDeps` field on a successful response is a protocol-version error — the caller should fall back to the one-shot path.

If the daemon's errors map contains any file-not-in-session entries, this method returns ErrDaemonFileNotInSession wrapping the count. The caller (typically runMissAnalysis) uses errors.Is to recognize the condition and trigger a daemon Rebuild + retry before falling through to one-shot.

func (*Daemon) AnalyzeWithDepsWithTimings

func (d *Daemon) AnalyzeWithDepsWithTimings(files []string, collectTimings bool, callFilter *CallTargetFilterSummary, declarationProfile *DeclarationProfileSummary) (*Data, *CacheDepsFile, []perf.TimingEntry, error)

AnalyzeWithDepsWithTimings is AnalyzeWithDeps plus optional Kotlin-side timing entries returned by newer daemon processes.

func (*Daemon) Checkpoint

func (d *Daemon) Checkpoint() error

Checkpoint asks the daemon to create a CRaC checkpoint. If the JDK does not support CRaC the daemon returns an error which we silently ignore.

func (*Daemon) Close

func (d *Daemon) Close() error

Close shuts down and cleans up. For shared (reused) daemons, only the TCP connection is closed — the daemon process keeps running for future clients. For owned daemons, the process is shut down and PID files are removed.

func (*Daemon) DecompileJar

func (d *Daemon) DecompileJar(jarPath, fqn string) (string, error)

DecompileJar asks krit-types to produce Kotlin source for a class resolved from the daemon's library module.

func (*Daemon) MatchesRepo

func (d *Daemon) MatchesRepo(sourceDirs []string) bool

MatchesRepo returns true if this Daemon was started for (or is currently connected to) a daemon whose sourceDirs fingerprint matches the given set. Used by runMissAnalysis to reject daemon reuse across krit invocations that target different repos — when the fingerprints disagree the caller falls back to one-shot for the current invocation rather than trusting a daemon whose sourceModule walks a different file set.

An empty sourcesHash (older daemon that predates Phase 3 sources tagging) always returns false so callers conservatively fall back. The old daemon keeps running for its original consumer.

func (*Daemon) Ping

func (d *Daemon) Ping() error

Ping sends a ping request to verify the daemon is responsive.

func (*Daemon) Rebuild

func (d *Daemon) Rebuild() error

Rebuild tells the daemon to rebuild its Analysis API session (after file changes).

func (*Daemon) Release

func (d *Daemon) Release() error

Release drops this Go-side handle to the daemon but leaves the daemon process alive. Closes the TCP connection (releasing the socket) and the log file handle. Does NOT call Shutdown, does NOT remove the PID file. The daemon stays discoverable by the next krit invocation via the per-repo PID files under ~/.krit/cache/daemons/, and eventually self-terminates on its 30-minute idle timeout (serverSocket.soTimeout in Main.kt:117-124).

This is the correct cleanup for short-lived CLI invocations that want to benefit from daemon reuse across sequential runs: Close() shuts the daemon down on exit (losing all the warmup benefit), Release() leaves it alive.

func (*Daemon) ResolveExpressionTypes

func (d *Daemon) ResolveExpressionTypes(positions map[string][]ExpressionPosition) (map[string]map[ExpressionPosition]*typeinfer.ResolvedType, error)

ResolveExpressionTypes sends a batched resolveExpressionTypes RPC to the daemon and returns the resolved facts keyed by (file path, position). Positions that did not resolve to a fact are silently omitted — the caller treats absence as "no fact at this position."

On RPC error (timeout, daemon dead, malformed response), returns (nil, err); the caller should fall through to source-only inference.

func (*Daemon) Shutdown

func (d *Daemon) Shutdown() error

Shutdown gracefully stops the daemon.

type DaemonDecompiler

type DaemonDecompiler struct {
	Daemon *Daemon
}

func (DaemonDecompiler) Decompile

func (d DaemonDecompiler) Decompile(jarPath, fqn string) (string, error)

type DaemonPool

type DaemonPool struct {
	Members   []*Daemon
	Requested int
	Connected int
	Started   int
}

DaemonPool is an opt-in set of persistent krit-types daemons for parallel warm miss analysis. Slot 0 intentionally uses the legacy single-daemon PID files; additional slots use {sourcesHash}.{slot}.{pid,port}.

func ConnectOrStartDaemonPool

func ConnectOrStartDaemonPool(jarPath string, sourceDirs []string, classpath []string, size int, verbose bool) (*DaemonPool, error)

ConnectOrStartDaemonPool connects or starts each requested pool slot. It is deliberately separate from ConnectOrStartDaemon so the default path keeps exactly one daemon and the old PID-file layout.

func (*DaemonPool) AnalyzeWithDepsSharded

func (p *DaemonPool) AnalyzeWithDepsSharded(files []string, collectTimings bool, callFilter *CallTargetFilterSummary, declarationProfile *DeclarationProfileSummary, tracker perf.Tracker) (*Data, *CacheDepsFile, error)

func (*DaemonPool) MatchesRepo

func (p *DaemonPool) MatchesRepo(sourceDirs []string) bool

func (*DaemonPool) Release

func (p *DaemonPool) Release() error

type Data

type Data struct {
	Version       int               `json:"version"`
	KotlinVersion string            `json:"kotlinVersion"`
	Files         map[string]*File  `json:"files"`        // source file path → declarations
	Dependencies  map[string]*Class `json:"dependencies"` // FQN → class info from JARs
}

Data is the top-level JSON structure produced by krit-types.

func AssembleOracle

func AssembleOracle(hits []*CacheEntry, fresh *Data) *Data

AssembleOracle builds an Data from a set of cache hits plus any freshly-analyzed files from a krit-types run. Dependencies are unioned across all sources, with cache hits losing to fresh data on conflict (fresh wins so a re-analysis with new classpath is reflected). Crashed (poison) entries contribute nothing — they're in `hits` only so the caller skips re-analysis, not because they have data to emit.

type DeclLocation

type DeclLocation struct {
	FQN       string
	Kind      string
	File      string
	JARPath   string
	Line      int
	Column    int
	Signature string
}

DeclLocation describes where a declaration was defined.

Line and Column are 1-based when known. The current oracle JSON does not emit per-declaration source positions, so Line and Column are zero until krit-types starts emitting them; File and Signature are always populated.

type DeclarationProfile

type DeclarationProfile struct {
	// ClassShell is the class FQN/kind/visibility/modality header. Always
	// on in practice (the class result cannot be synthesized without it),
	// but carried as a flag for symmetry with the Kotlin-side profile.
	ClassShell bool
	// Supertypes records direct supertype FQNs (excluding kotlin.Any).
	Supertypes bool
	// ClassAnnotations records class-level annotation FQNs.
	ClassAnnotations bool
	// Members gates traversal of symbol.memberScope. When false, the
	// member list is returned empty regardless of the other member flags.
	Members bool
	// MemberSignatures gates return-type rendering and parameter-type
	// extraction for each included member.
	MemberSignatures bool
	// MemberAnnotations records annotation FQNs on each included member.
	MemberAnnotations bool
	// SourceDependencyClosure keeps the library-supertype walk that feeds
	// the oracle cache closure. Disabling it breaks incremental cache
	// invalidation and should be reserved for experiments.
	SourceDependencyClosure bool
}

DeclarationProfile gates which KAA symbol fields krit-types extracts per class/member. Extracting a smaller profile saves JVM-side time by skipping member-scope traversal, type rendering, and annotation walks that no active rule consumes.

Default zero-value is treated as "empty" — callers should construct profiles through FullDeclarationProfile() or by setting fields explicitly.

func FullDeclarationProfile

func FullDeclarationProfile() DeclarationProfile

FullDeclarationProfile returns the profile that matches pre-profile extraction behavior — every field populated. A run with this profile writes cache entries with an empty DeclarationProfileFingerprint, so they satisfy any subsequent lookup (broader set satisfies narrower).

func MergeDeclarationProfiles

func MergeDeclarationProfiles(profiles ...DeclarationProfile) DeclarationProfile

MergeDeclarationProfiles returns the union of the given profiles. The resulting profile contains every feature that any input contains — this is the safe default when deriving a profile from a heterogeneous rule set, since the broadest-needing rule wins.

func ParseDeclarationProfile

func ParseDeclarationProfile(value string) DeclarationProfile

ParseDeclarationProfile parses the comma-separated feature string used on the CLI (and in tests). Unknown feature names are ignored. An empty input returns the zero profile, not the full profile — callers that want "no flag passed ⇒ full" must check upstream.

func (DeclarationProfile) CLIValue

func (p DeclarationProfile) CLIValue() string

CLIValue returns the comma-separated feature list passed to krit-types via --declaration-profile. Returns "" for the full profile so callers can omit the flag entirely (preserving the pre-profile CLI shape).

func (DeclarationProfile) IsFull

func (p DeclarationProfile) IsFull() bool

IsFull reports whether the profile is equivalent to FullDeclarationProfile. Full profiles write unfingerprinted cache entries.

type DeclarationProfileSummary

type DeclarationProfileSummary struct {
	Profile     DeclarationProfile
	Fingerprint string
}

DeclarationProfileSummary is the plumbing wrapper passed through InvocationOptions. The fingerprint is empty when the profile is full, matching the CallFilterFingerprint convention (empty = broad = satisfies any lookup).

func FinalizeDeclarationProfile

func FinalizeDeclarationProfile(profile DeclarationProfile) DeclarationProfileSummary

FinalizeDeclarationProfile computes the stable fingerprint for a profile. Full profiles get an empty fingerprint so their cache entries are treated as unfiltered/broad.

type DecompileCache

type DecompileCache struct {
	// contains filtered or unexported fields
}

DecompileCache wraps a Decompiler with a content-addressed disk cache. JAR contents are immutable per content hash, so cached decompiles never need invalidating: a cache entry under {jar-sha}/{fqn}.kt is correct forever for that JAR's bytes.

func NewDecompileCache

func NewDecompileCache(root string, source Decompiler) *DecompileCache

NewDecompileCache wires a cache rooted at root. root is created lazily on first write; callers typically point this at ".krit/jar-decompile" inside the project.

func (*DecompileCache) Get

func (c *DecompileCache) Get(jarPath, fqn string) (string, error)

Get returns the decompiled source for {jarPath, fqn}, reading from disk when available and otherwise calling the underlying Decompiler and persisting the result. When the JAR file itself is missing, Get falls back to the supplied source — this is the "signature-stub" path the proposal describes for unresolved classpath entries.

func (*DecompileCache) JARMissing

func (c *DecompileCache) JARMissing(jarPath string) bool

JARMissing reports whether Get has previously observed jarPath to be unreadable. The LSP server uses this to log unresolved classpath entries without spamming the log on every request.

type Decompiler

type Decompiler interface {
	Decompile(jarPath, fqn string) (string, error)
}

Decompiler turns a {jar, fqn} pair into Kotlin-shaped source text. The production implementation will RPC into krit-types and use the Kotlin Analysis API's KotlinDecompiledLightClassSupport. Until that lands the LSP path uses a signature-stub renderer driven entirely from data the oracle already collects in Data.Dependencies — enough for editors to render a recognisable virtual document.

type Diagnostic

type Diagnostic struct {
	FactoryName string `json:"factoryName"` // e.g. "UNREACHABLE_CODE", "USELESS_ELVIS"
	Severity    string `json:"severity"`    // "ERROR", "WARNING", "INFO"
	Message     string `json:"message"`
	Line        int    `json:"line"` // 1-based
	Col         int    `json:"col"`  // 1-based
	StartByte   int    `json:"startByte,omitempty"`
	EndByte     int    `json:"endByte,omitempty"`
}

Diagnostic holds a compiler diagnostic emitted by the Kotlin Analysis API.

type ExpressionPosition

type ExpressionPosition struct {
	Line int
	Col  int
}

ExpressionPosition identifies a single oracle expression-type query by 1-based line and column. Mirrors api.ExpressionPosition (the rule-side equivalent) so callers can convert by struct literal. Kept independent of v2 here to avoid an oracle → rules-package dependency direction.

type ExpressionType

type ExpressionType struct {
	Type               string   `json:"type"` // FQN like "kotlin.String"
	Nullable           bool     `json:"nullable"`
	StartByte          int      `json:"startByte,omitempty"`
	EndByte            int      `json:"endByte,omitempty"`
	CallTarget         string   `json:"callTarget,omitempty"`         // FQN of resolved function or lexical fallback
	CallTargetResolved bool     `json:"callTargetResolved,omitempty"` // true when callTarget came from KAA resolution
	CallTargetSuspend  bool     `json:"callTargetSuspend,omitempty"`  // true when the resolved callable symbol is suspend
	Annotations        []string `json:"annotations,omitempty"`        // FQNs of annotations on the resolved symbol
}

ExpressionType holds a compiler-resolved type for an expression at a source position.

type FakeOracle

type FakeOracle struct {
	Classes               map[string]*typeinfer.ClassInfo
	Sealed                map[string][]string
	Enums                 map[string][]string
	Subtypes              map[string][]string // type → supertypes (for IsSubtype)
	Functions             map[string]*typeinfer.ResolvedType
	Deps                  map[string]*Class
	Expressions           map[string]map[string]*typeinfer.ResolvedType // file → ("line:col" → type)
	Annotations           map[string][]string                           // "ClassName.memberName" → annotation FQNs
	CallTargets           map[string]map[string]string                  // file → ("line:col" → call target FQN)
	CallTargetSuspend     map[string]map[string]bool                    // file → ("line:col" → suspend status for resolved call target)
	CallTargetAnnotations map[string]map[string][]string                // file → ("line:col" → annotation FQNs on symbol)
	Diagnostics           map[string][]Diagnostic                       // file → diagnostics
}

FakeOracle is a configurable test double for the Lookup interface. Set up responses before using in tests.

func NewFakeOracle

func NewFakeOracle() *FakeOracle

NewFakeOracle creates a FakeOracle with all maps initialized.

func (*FakeOracle) Dependencies

func (f *FakeOracle) Dependencies() map[string]*Class

func (*FakeOracle) IsSubtype

func (f *FakeOracle) IsSubtype(a, b string) bool

func (*FakeOracle) LookupAnnotations

func (f *FakeOracle) LookupAnnotations(key string) []string

func (*FakeOracle) LookupCallTarget

func (f *FakeOracle) LookupCallTarget(filePath string, line, col int) string

func (*FakeOracle) LookupCallTargetAnnotations

func (f *FakeOracle) LookupCallTargetAnnotations(filePath string, line, col int) []string

func (*FakeOracle) LookupCallTargetAnnotationsFlat

func (f *FakeOracle) LookupCallTargetAnnotationsFlat(file *scanner.File, idx uint32) []string

func (*FakeOracle) LookupCallTargetFlat

func (f *FakeOracle) LookupCallTargetFlat(file *scanner.File, idx uint32) string

func (*FakeOracle) LookupCallTargetSuspend

func (f *FakeOracle) LookupCallTargetSuspend(filePath string, line, col int) (bool, bool)

func (*FakeOracle) LookupCallTargetSuspendFlat

func (f *FakeOracle) LookupCallTargetSuspendFlat(file *scanner.File, idx uint32) (bool, bool)

func (*FakeOracle) LookupClass

func (f *FakeOracle) LookupClass(name string) *typeinfer.ClassInfo

func (*FakeOracle) LookupDiagnostics

func (f *FakeOracle) LookupDiagnostics(filePath string) []Diagnostic

func (*FakeOracle) LookupDiagnosticsForFlatRange

func (f *FakeOracle) LookupDiagnosticsForFlatRange(file *scanner.File, _ uint32) []Diagnostic

func (*FakeOracle) LookupEnumEntries

func (f *FakeOracle) LookupEnumEntries(name string) []string

func (*FakeOracle) LookupExpression

func (f *FakeOracle) LookupExpression(filePath string, line, col int) *typeinfer.ResolvedType

func (*FakeOracle) LookupExpressionFlat

func (f *FakeOracle) LookupExpressionFlat(file *scanner.File, idx uint32) *typeinfer.ResolvedType

func (*FakeOracle) LookupFunction

func (f *FakeOracle) LookupFunction(key string) *typeinfer.ResolvedType

func (*FakeOracle) LookupSealedVariants

func (f *FakeOracle) LookupSealedVariants(name string) []string

type FallbackDecompiler

type FallbackDecompiler struct {
	Primary  Decompiler
	Fallback Decompiler
}

func (FallbackDecompiler) Decompile

func (d FallbackDecompiler) Decompile(jarPath, fqn string) (string, error)

type File

type File struct {
	Package      string                     `json:"package"`
	Declarations []*Class                   `json:"declarations"`
	Expressions  map[string]*ExpressionType `json:"expressions,omitempty"` // "line:col" → type
	Diagnostics  []*Diagnostic              `json:"diagnostics,omitempty"` // compiler diagnostics
}

File holds declarations extracted from a single source file.

type FilterRule

type FilterRule struct {
	// Name is the rule identifier, used only for verbose reporting.
	Name string
	// Filter is the rule's declared oracle filter. A nil Filter (or
	// AllFiles: true) means the rule wants every file — the caller
	// should set AllFiles: true explicitly when no narrowing applies.
	Filter *FilterSpec
}

FilterRule is a minimal view of a rule that declared NeedsOracle. The caller (internal/rules.BuildFilterRulesV2) pre-filters the registered v2 rules and passes only oracle-needing rules here — the filter inversion (roadmap: core-infra/oracle-filter-inversion.md) means rules without NeedsOracle never reach this package.

type FilterSpec

type FilterSpec struct {
	Identifiers []string
	AllFiles    bool
}

FilterSpec is an in-package mirror of api.OracleFilter. The value types are decoupled so internal/oracle does not import internal/rules. The fields match api.OracleFilter 1:1.

type FilterSummary

type FilterSummary struct {
	// TotalFiles is len(files).
	TotalFiles int
	// MarkedFiles is the number of files at least one rule wants oracle
	// access on. Always <= TotalFiles.
	MarkedFiles int
	// AllFiles is true when any enabled rule declared AllFiles: true
	// and the filter was short-circuited to the full set.
	AllFiles bool
	// Paths is the sorted list of absolute paths that any rule marked
	// for oracle access. When AllFiles is true, Paths is nil (the caller
	// should fall back to the unfiltered set).
	Paths []string
	// Fingerprint is a short hex-encoded SHA-256 prefix over the sorted
	// Paths. It is a stable identity for the oracle input set: narrowing
	// PRs can diff fingerprints to detect which files moved in or out
	// without a full finding diff. Empty when AllFiles is true (the
	// "full corpus" set is not fingerprinted — its identity is implicit).
	Fingerprint string
}

FilterSummary describes the outcome of a filter evaluation. Returned from CollectOracleFiles so the caller can decide whether to skip the filtering round trip (no reduction) and emit a verbose log.

func CollectOracleFiles

func CollectOracleFiles(rules []FilterRule, files []*scanner.File) FilterSummary

CollectOracleFiles returns the subset of files any enabled rule wants oracle access on. Rules are represented by FilterRule (the caller is expected to build this slice from api.Registry via rules.GetOracleFilter).

Matching semantics:

  1. If any rule has AllFiles: true, the short-circuit returns AllFiles: true and Paths: nil. Callers should treat this as "no reduction — feed the full file set to the oracle".
  2. Otherwise each file is marked when any rule's Identifiers list contains a substring of the file's raw bytes. bytes.Contains is conservative: false positives waste oracle work but never lose findings.
  3. Files that no rule marks are dropped from the returned Paths.

The returned Paths are absolute (via filepath.Abs) so that krit-types can match them against its own source tree regardless of how the caller passed them in.

type Index

type Index struct {
	// contains filtered or unexported fields
}

Index provides O(1) reverse lookups from FQN to declaration and references, plus O(1) expression-id to type lookups, over an assembled Data.

Index is safe for concurrent reads alongside ApplyFileUpdate / RemoveFile mutations from a single writer (typically the LSP didChange handler).

func BuildIndex

func BuildIndex(raw *Data) *Index

BuildIndex constructs the reverse lookup from an assembled Data. One linear pass over declarations and one pass over every file's expressions.

func (*Index) ApplyFileUpdate

func (idx *Index) ApplyFileUpdate(path string, file *File)

ApplyFileUpdate replaces every entry sourced from path with entries derived from file. Passing a nil file is equivalent to RemoveFile(path). Safe to call concurrently with reads.

func (*Index) FindDeclarationByFQN

func (idx *Index) FindDeclarationByFQN(fqn string) (*DeclLocation, bool)

FindDeclarationByFQN returns the declaration record for fqn.

func (*Index) FindDeclarationBySimpleName

func (idx *Index) FindDeclarationBySimpleName(name string) []*DeclLocation

FindDeclarationBySimpleName returns every declaration whose FQN ends in `.name` (or whose FQN equals name for top-level declarations without a package).

func (*Index) FindReferencesByFQN

func (idx *Index) FindReferencesByFQN(fqn string) []ReferenceLocation

FindReferencesByFQN returns every recorded use of fqn, including the declaration site itself. The returned slice is a copy; the caller may retain it across subsequent index mutations.

func (*Index) RemoveFile

func (idx *Index) RemoveFile(path string)

RemoveFile evicts every decl, ref, and expression entry that originated from path. Linear in the number of entries removed, not in total index size. Safe to call concurrently with reads.

func (*Index) TypeAtExpression

func (idx *Index) TypeAtExpression(exprID string) (TypeInfo, bool)

TypeAtExpression returns the resolved type for an expression. The exprId is "filePath:line:col" using the oracle's 1-based line and column.

type InvocationOptions

type InvocationOptions struct {
	Tracker      perf.Tracker
	CacheWriter  *CacheWriter
	CallFilter   *CallTargetFilterSummary
	ExtraJVMArgs []string
	// DisableDiagnostics skips krit-types collectDiagnostics(), which is
	// expensive on large projects and only needed by rules that consume
	// compiler diagnostic facts.
	DisableDiagnostics bool
	// DeclarationProfile narrows which fields krit-types populates per
	// class/member. Nil or a full profile preserves pre-profile extraction;
	// narrow profiles skip KAA traversal for unused sections.
	DeclarationProfile *DeclarationProfileSummary
}

InvocationOptions carries optional diagnostics for oracle invocations. A nil or disabled tracker keeps the existing low-overhead behavior.

type LazyLookup

type LazyLookup struct {
	// contains filtered or unexported fields
}

LazyLookup defers oracle JSON deserialization until the first semantic lookup. Warm runs with complete findings-cache hits can carry this through the resolver without paying jsonLoad at all.

func NewLazyLookup

func NewLazyLookup(path string, onError func(error)) *LazyLookup

NewLazyLookup returns a Lookup backed by path. onError is called once if the load fails; nil is accepted.

func (*LazyLookup) Dependencies

func (l *LazyLookup) Dependencies() map[string]*Class

func (*LazyLookup) Err

func (l *LazyLookup) Err() error

Err reports the load error after a lookup attempts to load the JSON.

func (*LazyLookup) IsSubtype

func (l *LazyLookup) IsSubtype(a, b string) bool

func (*LazyLookup) Loaded

func (l *LazyLookup) Loaded() bool

Loaded reports whether the JSON has been deserialized successfully.

func (*LazyLookup) LookupAnnotations

func (l *LazyLookup) LookupAnnotations(key string) []string

func (*LazyLookup) LookupCallTarget

func (l *LazyLookup) LookupCallTarget(filePath string, line, col int) string

func (*LazyLookup) LookupCallTargetAnnotations

func (l *LazyLookup) LookupCallTargetAnnotations(filePath string, line, col int) []string

func (*LazyLookup) LookupCallTargetAnnotationsFlat

func (l *LazyLookup) LookupCallTargetAnnotationsFlat(file *scanner.File, idx uint32) []string

func (*LazyLookup) LookupCallTargetFlat

func (l *LazyLookup) LookupCallTargetFlat(file *scanner.File, idx uint32) string

func (*LazyLookup) LookupCallTargetSuspend

func (l *LazyLookup) LookupCallTargetSuspend(filePath string, line, col int) (bool, bool)

func (*LazyLookup) LookupCallTargetSuspendFlat

func (l *LazyLookup) LookupCallTargetSuspendFlat(file *scanner.File, idx uint32) (bool, bool)

func (*LazyLookup) LookupClass

func (l *LazyLookup) LookupClass(name string) *typeinfer.ClassInfo

func (*LazyLookup) LookupDiagnostics

func (l *LazyLookup) LookupDiagnostics(filePath string) []Diagnostic

func (*LazyLookup) LookupDiagnosticsForFlatRange

func (l *LazyLookup) LookupDiagnosticsForFlatRange(file *scanner.File, idx uint32) []Diagnostic

func (*LazyLookup) LookupEnumEntries

func (l *LazyLookup) LookupEnumEntries(name string) []string

func (*LazyLookup) LookupExpression

func (l *LazyLookup) LookupExpression(filePath string, line, col int) *typeinfer.ResolvedType

func (*LazyLookup) LookupExpressionFlat

func (l *LazyLookup) LookupExpressionFlat(file *scanner.File, idx uint32) *typeinfer.ResolvedType

func (*LazyLookup) LookupFunction

func (l *LazyLookup) LookupFunction(key string) *typeinfer.ResolvedType

func (*LazyLookup) LookupSealedVariants

func (l *LazyLookup) LookupSealedVariants(name string) []string

func (*LazyLookup) Preload added in v0.2.0

func (l *LazyLookup) Preload()

Preload kicks off the JSON deserialization in a background goroutine so the first lookup observes a warm sync.Once instead of paying the load latency itself. On large repos (Kotlin compiler: ~41 MB types.json) the deferred load was ~500 ms, surfacing in per-rule timings as whichever rule happened to fire first — Preload moves that wall time off the rule path. Idempotent: multiple Preload calls (or Preload followed by a real lookup) coalesce on the same sync.Once.

func (*LazyLookup) Stats

func (l *LazyLookup) Stats() Stats

type Lookup

type Lookup interface {
	LookupClass(name string) *typeinfer.ClassInfo
	LookupSealedVariants(name string) []string
	LookupEnumEntries(name string) []string
	IsSubtype(a, b string) bool
	Dependencies() map[string]*Class
	LookupFunction(key string) *typeinfer.ResolvedType
	LookupExpression(filePath string, line, col int) *typeinfer.ResolvedType
	LookupAnnotations(key string) []string
	LookupCallTarget(filePath string, line, col int) string
	// LookupCallTargetSuspend returns suspend-call evidence for a resolved
	// callable at the given source position. The second return value is false
	// when the oracle has no resolved callable metadata for the position.
	LookupCallTargetSuspend(filePath string, line, col int) (bool, bool)
	// LookupCallTargetAnnotations returns the annotation FQNs recorded directly
	// on the resolved call-target symbol at the given source position. Unlike
	// LookupAnnotations (which requires Members+MemberAnnotations in the
	// declaration profile), these annotations are captured during call resolution
	// and require no declaration extraction at all.
	LookupCallTargetAnnotations(filePath string, line, col int) []string
	LookupDiagnostics(filePath string) []Diagnostic
}

Lookup is the interface for querying oracle type information. Implementations: *Oracle (real), *FakeOracle (test double).

type Member

type Member struct {
	Name        string   `json:"name"`
	Kind        string   `json:"kind"` // function, property
	ReturnType  string   `json:"returnType"`
	Nullable    bool     `json:"nullable"`
	Visibility  string   `json:"visibility"`
	IsOverride  bool     `json:"isOverride,omitempty"`
	IsAbstract  bool     `json:"isAbstract,omitempty"`
	Params      []*Param `json:"params,omitempty"`
	Annotations []string `json:"annotations,omitempty"` // FQNs
	Line        int      `json:"line,omitempty"`        // 1-based source line when known
	Column      int      `json:"column,omitempty"`      // 1-based source column when known
}

Member describes a function or property within a class.

type Oracle

type Oracle struct {
	// contains filtered or unexported fields
}

Oracle holds pre-computed type information from the Kotlin compiler.

func Load

func Load(path string) (*Oracle, error)

Load reads a JSON oracle file and builds lookup indexes.

func LoadFromData

func LoadFromData(raw *Data) (*Oracle, error)

LoadFromData builds an Oracle from an already-parsed Data struct (e.g., from a daemon response) without reading from disk.

func (*Oracle) Dependencies

func (o *Oracle) Dependencies() map[string]*Class

Dependencies returns the raw dependency map for reporting.

func (*Oracle) Index

func (o *Oracle) Index() *Index

Index returns the FQN reverse index. Built once during Load.

func (*Oracle) IsSubtype

func (o *Oracle) IsSubtype(a, b string) bool

IsSubtype checks if type a is a subtype of type b using the precomputed ancestor set. Constant-time after Load.

func (*Oracle) LookupAnnotations

func (o *Oracle) LookupAnnotations(key string) []string

LookupAnnotations returns annotation FQNs for a class or member key (e.g., "ClassName" or "ClassName.memberName").

func (*Oracle) LookupCallTarget

func (o *Oracle) LookupCallTarget(filePath string, line, col int) string

LookupCallTarget returns the FQN of the resolved call target for an expression at a specific source position (1-based line and column).

func (*Oracle) LookupCallTargetAnnotations

func (o *Oracle) LookupCallTargetAnnotations(filePath string, line, col int) []string

LookupCallTargetAnnotations returns annotation FQNs recorded directly on the resolved call-target symbol at the given source position. These are captured during krit-types call resolution and require no declaration extraction.

func (*Oracle) LookupCallTargetAnnotationsFlat

func (o *Oracle) LookupCallTargetAnnotationsFlat(file *scanner.File, idx uint32) []string

LookupCallTargetAnnotationsFlat returns annotations recorded on the resolved symbol for the FlatNode's byte range, falling back to line/column lookup.

func (*Oracle) LookupCallTargetFlat

func (o *Oracle) LookupCallTargetFlat(file *scanner.File, idx uint32) string

LookupCallTargetFlat returns the FQN of the resolved call target for a FlatNode's byte range, falling back to line/column lookup.

func (*Oracle) LookupCallTargetSuspend

func (o *Oracle) LookupCallTargetSuspend(filePath string, line, col int) (isSuspend bool, ok bool)

LookupCallTargetSuspend returns whether a KAA-resolved callable target is suspend at a specific source position. ok is false when the target is absent or came from lexical fallback rather than KAA resolution.

func (*Oracle) LookupCallTargetSuspendFlat

func (o *Oracle) LookupCallTargetSuspendFlat(file *scanner.File, idx uint32) (bool, bool)

LookupCallTargetSuspendFlat returns suspend-call evidence for the FlatNode's byte range, falling back to line/column lookup.

func (*Oracle) LookupClass

func (o *Oracle) LookupClass(name string) *typeinfer.ClassInfo

LookupClass returns ClassInfo for a type by FQN or simple name.

func (*Oracle) LookupDiagnostics

func (o *Oracle) LookupDiagnostics(filePath string) []Diagnostic

LookupDiagnostics returns compiler diagnostics for a source file.

func (*Oracle) LookupDiagnosticsForFlatRange

func (o *Oracle) LookupDiagnosticsForFlatRange(file *scanner.File, idx uint32) []Diagnostic

LookupDiagnosticsForFlatRange returns diagnostics whose byte range is inside the FlatNode. When old oracle data has no byte ranges it falls back to row containment so existing caches remain usable.

func (*Oracle) LookupEnumEntries

func (o *Oracle) LookupEnumEntries(name string) []string

LookupEnumEntries returns known enum entries.

func (*Oracle) LookupExpression

func (o *Oracle) LookupExpression(filePath string, line, col int) *typeinfer.ResolvedType

LookupExpression returns the compiler-resolved type for an expression at a specific source position (1-based line and column).

func (*Oracle) LookupExpressionFlat

func (o *Oracle) LookupExpressionFlat(file *scanner.File, idx uint32) *typeinfer.ResolvedType

LookupExpressionFlat returns the compiler-resolved type for the FlatNode's byte range when byte-range oracle data is available, falling back to the legacy line/column lookup otherwise.

func (*Oracle) LookupFunction

func (o *Oracle) LookupFunction(key string) *typeinfer.ResolvedType

LookupFunction returns the return type of a function by key (e.g., "ClassName.methodName").

func (*Oracle) LookupSealedVariants

func (o *Oracle) LookupSealedVariants(name string) []string

LookupSealedVariants returns known sealed variants.

func (*Oracle) SetExpressionFact

func (o *Oracle) SetExpressionFact(filePath string, line, col int, t *typeinfer.ResolvedType)

SetExpressionFact injects a single resolved expression fact into the oracle's expression map. Intended to be called from the targeted- resolution pre-pass, between Oracle.Load and the start of dispatch — there are no concurrent readers of expressions during that window. Calling this concurrently with rule dispatch is undefined.

A nil type is silently ignored so callers can pass through "no fact" markers from the resolver without checking each entry.

func (*Oracle) Stats

func (o *Oracle) Stats() Stats

Stats returns a snapshot of hit/miss counters for Oracle lookups. Not part of the Lookup interface (no fake wiring required).

type Param

type Param struct {
	Name     string `json:"name"`
	Type     string `json:"type"`
	Nullable bool   `json:"nullable"`
}

Param describes a function parameter.

type ReferenceLocation

type ReferenceLocation struct {
	FQN           string
	File          string
	Line          int
	Column        int
	IsDeclaration bool
}

ReferenceLocation is a single use of a symbol.

type SignatureStubDecompiler

type SignatureStubDecompiler struct {
	// Lookup returns the Class for an FQN, or nil if unknown.
	Lookup func(fqn string) *Class
}

SignatureStubDecompiler renders Kotlin-shaped source from the oracle's own Dependencies map. It is deliberately schematic: it shows the kind, modifiers, supertypes, and members so a navigation result is recognisable in an editor, but it does not reconstruct method bodies. When the real KAA-backed decompiler is wired through krit-types this implementation remains useful as a fallback for entries the daemon can't resolve.

func (*SignatureStubDecompiler) Decompile

func (d *SignatureStubDecompiler) Decompile(jarPath, fqn string) (string, error)

Decompile satisfies Decompiler.

type Stats

type Stats struct {
	ExprHits, ExprMisses   int64
	ClassHits, ClassMisses int64
	FuncHits, FuncMisses   int64
}

Stats is a snapshot of Oracle lookup hit/miss counters.

type TypeInfo

type TypeInfo struct {
	FQN       string
	Nullable  bool
	Arguments []TypeInfo
}

TypeInfo is a parsed expression type, with generic arguments recovered from the oracle's textual type representation.

Directories

Path Synopsis
Package oracletest provides a shared contract test that every implementation of oracle.Lookup must satisfy.
Package oracletest provides a shared contract test that every implementation of oracle.Lookup must satisfy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL