typeinfer

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: 16 Imported by: 0

Documentation

Overview

Package typeinfer provides lightweight type inference for Kotlin source code. It builds a partial type system from AST analysis — no JVM, no classpath, no compilation required. Runs at tree-sitter speed.

What it resolves:

  • Import-based type resolution (java.util.Random → knows Random is java.util.Random)
  • Declaration-site types (val x: String = ... → knows x is String)
  • Nullable vs non-null tracking (String vs String?)
  • Partial class hierarchy from source (class Foo : Bar → knows Foo extends Bar)
  • Sealed class/enum variants (sealed class Result → knows Success, Failure)
  • Annotation arguments (@RequiresApi(26) → knows value is 26)

What it does NOT resolve:

  • Types from compiled dependencies (JARs)
  • Generic type argument inference
  • Complex expression type inference (result of chained calls)
  • Overload resolution

Index

Constants

This section is empty.

Variables

View Source
var ExceptionAncestors = map[string][]string{

	"Throwable":        {},
	"Exception":        {"Throwable"},
	"RuntimeException": {"Exception", "Throwable"},
	"Error":            {"Throwable"},

	"IOException":                  {"Exception", "Throwable"},
	"FileNotFoundException":        {"IOException", "Exception", "Throwable"},
	"InterruptedException":         {"Exception", "Throwable"},
	"TimeoutException":             {"Exception", "Throwable"},
	"ParseException":               {"Exception", "Throwable"},
	"CloneNotSupportedException":   {"Exception", "Throwable"},
	"ReflectiveOperationException": {"Exception", "Throwable"},
	"ClassNotFoundException":       {"ReflectiveOperationException", "Exception", "Throwable"},
	"NoSuchMethodException":        {"ReflectiveOperationException", "Exception", "Throwable"},
	"NoSuchFieldException":         {"ReflectiveOperationException", "Exception", "Throwable"},
	"URISyntaxException":           {"Exception", "Throwable"},
	"GeneralSecurityException":     {"Exception", "Throwable"},
	"NoSuchAlgorithmException":     {"GeneralSecurityException", "Exception", "Throwable"},
	"InvalidKeyException":          {"GeneralSecurityException", "Exception", "Throwable"},
	"CertificateException":         {"GeneralSecurityException", "Exception", "Throwable"},

	"SocketException":        {"IOException", "Exception", "Throwable"},
	"ConnectException":       {"SocketException", "IOException", "Exception", "Throwable"},
	"SocketTimeoutException": {"SocketException", "IOException", "Exception", "Throwable"},
	"MalformedURLException":  {"IOException", "Exception", "Throwable"},
	"UnknownHostException":   {"IOException", "Exception", "Throwable"},
	"EOFException":           {"IOException", "Exception", "Throwable"},
	"SSLException":           {"IOException", "Exception", "Throwable"},
	"SSLHandshakeException":  {"SSLException", "IOException", "Exception", "Throwable"},

	"NullPointerException":            {"RuntimeException", "Exception", "Throwable"},
	"IllegalArgumentException":        {"RuntimeException", "Exception", "Throwable"},
	"IllegalStateException":           {"RuntimeException", "Exception", "Throwable"},
	"CancellationException":           {"IllegalStateException", "RuntimeException", "Exception", "Throwable"},
	"NumberFormatException":           {"IllegalArgumentException", "RuntimeException", "Exception", "Throwable"},
	"IndexOutOfBoundsException":       {"RuntimeException", "Exception", "Throwable"},
	"ArrayIndexOutOfBoundsException":  {"IndexOutOfBoundsException", "RuntimeException", "Exception", "Throwable"},
	"StringIndexOutOfBoundsException": {"IndexOutOfBoundsException", "RuntimeException", "Exception", "Throwable"},
	"ClassCastException":              {"RuntimeException", "Exception", "Throwable"},
	"TypeCastException":               {"ClassCastException", "RuntimeException", "Exception", "Throwable"},
	"UnsupportedOperationException":   {"RuntimeException", "Exception", "Throwable"},
	"ConcurrentModificationException": {"RuntimeException", "Exception", "Throwable"},
	"NoSuchElementException":          {"RuntimeException", "Exception", "Throwable"},
	"ArithmeticException":             {"RuntimeException", "Exception", "Throwable"},
	"SecurityException":               {"RuntimeException", "Exception", "Throwable"},
	"NegativeArraySizeException":      {"RuntimeException", "Exception", "Throwable"},

	"KotlinNullPointerException":           {"NullPointerException", "RuntimeException", "Exception", "Throwable"},
	"UninitializedPropertyAccessException": {"RuntimeException", "Exception", "Throwable"},

	"VirtualMachineError":         {"Error", "Throwable"},
	"OutOfMemoryError":            {"VirtualMachineError", "Error", "Throwable"},
	"StackOverflowError":          {"VirtualMachineError", "Error", "Throwable"},
	"LinkageError":                {"Error", "Throwable"},
	"ExceptionInInitializerError": {"LinkageError", "Error", "Throwable"},
	"NoClassDefFoundError":        {"LinkageError", "Error", "Throwable"},
	"NotImplementedError":         {"Error", "Throwable"},
	"AssertionError":              {"Error", "Throwable"},

	"TimeoutCancellationException": {"CancellationException", "IllegalStateException", "RuntimeException", "Exception", "Throwable"},

	"AndroidException":          {"Exception", "Throwable"},
	"ActivityNotFoundException": {"RuntimeException", "Exception", "Throwable"},
	"RemoteException":           {"AndroidException", "Exception", "Throwable"},
	"DeadObjectException":       {"RemoteException", "AndroidException", "Exception", "Throwable"},
	"JSONException":             {"Exception", "Throwable"},
	"SQLiteException":           {"RuntimeException", "Exception", "Throwable"},
	"SQLiteConstraintException": {"SQLiteException", "RuntimeException", "Exception", "Throwable"},
	"BadParcelableException":    {"RuntimeException", "Exception", "Throwable"},
}

ExceptionAncestors maps exception class name -> ordered list of supertypes.

View Source
var JavaToKotlinTypes = map[string]string{

	"java.lang.String":    "kotlin.String",
	"java.lang.Integer":   "kotlin.Int",
	"java.lang.Long":      "kotlin.Long",
	"java.lang.Short":     "kotlin.Short",
	"java.lang.Byte":      "kotlin.Byte",
	"java.lang.Float":     "kotlin.Float",
	"java.lang.Double":    "kotlin.Double",
	"java.lang.Boolean":   "kotlin.Boolean",
	"java.lang.Character": "kotlin.Char",
	"java.lang.Object":    "kotlin.Any",
	"java.lang.Void":      "kotlin.Unit",
	"java.lang.Number":    "kotlin.Number",

	"java.util.List":          "kotlin.collections.List",
	"java.util.ArrayList":     "kotlin.collections.ArrayList",
	"java.util.Set":           "kotlin.collections.Set",
	"java.util.HashSet":       "kotlin.collections.HashSet",
	"java.util.LinkedHashSet": "kotlin.collections.LinkedHashSet",
	"java.util.TreeSet":       "kotlin.collections.TreeSet",
	"java.util.Map":           "kotlin.collections.Map",
	"java.util.HashMap":       "kotlin.collections.HashMap",
	"java.util.LinkedHashMap": "kotlin.collections.LinkedHashMap",
	"java.util.TreeMap":       "kotlin.collections.TreeMap",
	"java.util.Collection":    "kotlin.collections.Collection",
	"java.util.Iterator":      "kotlin.collections.Iterator",
	"java.lang.Iterable":      "kotlin.collections.Iterable",

	"java.lang.Comparable":       "kotlin.Comparable",
	"java.lang.Enum":             "kotlin.Enum",
	"java.lang.Annotation":       "kotlin.Annotation",
	"java.lang.Cloneable":        "kotlin.Cloneable",
	"java.lang.Throwable":        "kotlin.Throwable",
	"java.lang.Exception":        "kotlin.Exception",
	"java.lang.RuntimeException": "kotlin.RuntimeException",
	"java.lang.Error":            "kotlin.Error",

	"java.lang.Runnable": "kotlin.Runnable",
}

JavaToKotlinTypes maps Java FQNs to their Kotlin equivalents.

View Source
var KnownClassHierarchy = map[string][]string{

	"android.app.Activity":                     {"android.content.ContextWrapper", "android.content.Context"},
	"androidx.fragment.app.FragmentActivity":   {"android.app.Activity", "android.content.ContextWrapper", "android.content.Context"},
	"androidx.appcompat.app.AppCompatActivity": {"androidx.fragment.app.FragmentActivity", "android.app.Activity"},
	"android.app.Application":                  {"android.content.ContextWrapper", "android.content.Context"},
	"android.app.Service":                      {"android.content.ContextWrapper", "android.content.Context"},
	"android.content.BroadcastReceiver":        {},
	"android.content.ContentProvider":          {},

	"android.view.ViewGroup":        {"android.view.View"},
	"android.widget.LinearLayout":   {"android.view.ViewGroup", "android.view.View"},
	"android.widget.FrameLayout":    {"android.view.ViewGroup", "android.view.View"},
	"android.widget.RelativeLayout": {"android.view.ViewGroup", "android.view.View"},
	"android.widget.TextView":       {"android.view.View"},
	"android.widget.ImageView":      {"android.view.View"},
	"android.widget.Button":         {"android.widget.TextView", "android.view.View"},

	"java.lang.Exception":        {"java.lang.Throwable"},
	"java.lang.RuntimeException": {"java.lang.Exception", "java.lang.Throwable"},
}

KnownClassHierarchy maps FQN -> ordered list of supertypes (nearest first).

View Source
var KnownCloseableTypes = map[string]bool{
	"InputStream":           true,
	"OutputStream":          true,
	"Reader":                true,
	"Writer":                true,
	"BufferedReader":        true,
	"BufferedWriter":        true,
	"FileInputStream":       true,
	"FileOutputStream":      true,
	"FileReader":            true,
	"FileWriter":            true,
	"InputStreamReader":     true,
	"OutputStreamWriter":    true,
	"PrintWriter":           true,
	"PrintStream":           true,
	"Socket":                true,
	"ServerSocket":          true,
	"Connection":            true,
	"Statement":             true,
	"PreparedStatement":     true,
	"ResultSet":             true,
	"Cursor":                true,
	"TypedArray":            true,
	"ParcelFileDescriptor":  true,
	"HttpURLConnection":     true,
	"ZipFile":               true,
	"JarFile":               true,
	"RandomAccessFile":      true,
	"Channel":               true,
	"AssetFileDescriptor":   true,
	"Scanner":               true,
	"ByteArrayInputStream":  true,
	"ByteArrayOutputStream": true,
	"DataInputStream":       true,
	"DataOutputStream":      true,
	"ObjectInputStream":     true,
	"ObjectOutputStream":    true,
	"BufferedInputStream":   true,
	"BufferedOutputStream":  true,
}

KnownCloseableTypes lists types known to implement Closeable/AutoCloseable.

View Source
var KnownInterfaces = map[string][]string{
	"java.io.Serializable": {
		"java.lang.Number", "java.lang.String", "java.lang.Enum",
		"java.util.ArrayList", "java.util.HashMap", "java.util.HashSet",
		"java.util.LinkedList", "java.util.TreeMap", "java.util.TreeSet",
		"kotlin.Pair", "kotlin.Triple",
		"java.util.Date", "java.util.Calendar",
		"java.math.BigDecimal", "java.math.BigInteger",
		"java.io.File", "java.net.URL", "java.net.URI",
	},
	"java.io.Closeable": {
		"java.io.InputStream", "java.io.OutputStream",
		"java.io.FileInputStream", "java.io.FileOutputStream",
		"java.io.BufferedReader", "java.io.BufferedWriter",
		"java.io.InputStreamReader", "java.io.OutputStreamWriter",
		"java.io.PrintWriter", "java.io.PrintStream",
		"java.net.Socket", "java.net.ServerSocket",
		"java.sql.Connection", "java.sql.Statement", "java.sql.ResultSet",
		"java.util.Scanner",
	},
	"android.os.Parcelable": {
		"android.os.Bundle", "android.content.Intent",
		"android.net.Uri", "android.graphics.Bitmap",
	},
}

KnownInterfaces maps interface FQN -> known implementors.

View Source
var KnownValueTypes = map[string]bool{

	"String": true, "kotlin.String": true,
	"Int": true, "kotlin.Int": true,
	"Long": true, "kotlin.Long": true,
	"Double": true, "kotlin.Double": true,
	"Float": true, "kotlin.Float": true,
	"Boolean": true, "kotlin.Boolean": true,
	"Byte": true, "kotlin.Byte": true,
	"Short": true, "kotlin.Short": true,
	"Char": true, "kotlin.Char": true,
	"UInt": true, "kotlin.UInt": true,
	"ULong": true, "kotlin.ULong": true,
	"UByte": true, "kotlin.UByte": true,
	"UShort": true, "kotlin.UShort": true,

	"Pair": true, "kotlin.Pair": true,
	"Triple": true, "kotlin.Triple": true,

	"java.lang.String": true, "java.lang.Integer": true, "java.lang.Long": true,
	"java.lang.Double": true, "java.lang.Float": true, "java.lang.Boolean": true,
	"java.lang.Byte": true, "java.lang.Short": true, "java.lang.Character": true,

	"BigDecimal": true, "java.math.BigDecimal": true,
	"BigInteger": true, "java.math.BigInteger": true,
}

KnownValueTypes lists types where referential equality (===) is almost certainly wrong and structural equality (==) should be used instead. Both Kotlin and Java FQNs are included so the lookup works regardless of whether the resolver produced a simple name or a fully-qualified name.

View Source
var KotlinAutoImports = map[string]string{
	"Runtime":           "java.lang.Runtime",
	"ProcessBuilder":    "java.lang.ProcessBuilder",
	"Process":           "java.lang.Process",
	"Thread":            "java.lang.Thread",
	"ThreadLocal":       "java.lang.ThreadLocal",
	"ThreadGroup":       "java.lang.ThreadGroup",
	"Throwable":         "java.lang.Throwable",
	"Exception":         "java.lang.Exception",
	"RuntimeException":  "java.lang.RuntimeException",
	"Error":             "java.lang.Error",
	"System":            "java.lang.System",
	"Math":              "java.lang.Math",
	"StrictMath":        "java.lang.StrictMath",
	"Class":             "java.lang.Class",
	"ClassLoader":       "java.lang.ClassLoader",
	"Object":            "java.lang.Object",
	"Number":            "java.lang.Number",
	"Void":              "java.lang.Void",
	"Package":           "java.lang.Package",
	"StackTraceElement": "java.lang.StackTraceElement",
	"Enum":              "java.lang.Enum",
}

KotlinAutoImports maps simple names of types Kotlin auto-imports from java.lang.* (which is implicitly visible in every Kotlin file even without an explicit import statement) to their Java FQNs.

These names are only used when no explicit import, alias, primitive, or stdlib mapping wins first. Several java.lang.* types are remapped by Kotlin to kotlin.* counterparts (String, Throwable, Exception, Object, ...) — those live in PrimitiveTypes / KotlinStdlibTypes and are not duplicated here. The entries below are types Kotlin uses by their java.lang.* FQN.

View Source
var KotlinStdlibTypes = map[string]string{
	"List":              "kotlin.collections.List",
	"MutableList":       "kotlin.collections.MutableList",
	"Set":               "kotlin.collections.Set",
	"MutableSet":        "kotlin.collections.MutableSet",
	"Map":               "kotlin.collections.Map",
	"MutableMap":        "kotlin.collections.MutableMap",
	"Sequence":          "kotlin.sequences.Sequence",
	"Flow":              "kotlinx.coroutines.flow.Flow",
	"StateFlow":         "kotlinx.coroutines.flow.StateFlow",
	"SharedFlow":        "kotlinx.coroutines.flow.SharedFlow",
	"MutableStateFlow":  "kotlinx.coroutines.flow.MutableStateFlow",
	"MutableSharedFlow": "kotlinx.coroutines.flow.MutableSharedFlow",
	"Job":               "kotlinx.coroutines.Job",
	"Deferred":          "kotlinx.coroutines.Deferred",
	"Pair":              "kotlin.Pair",
	"Triple":            "kotlin.Triple",
	"Result":            "kotlin.Result",
	"Lazy":              "kotlin.Lazy",
	"Comparable":        "kotlin.Comparable",
	"Iterable":          "kotlin.collections.Iterable",
	"Iterator":          "kotlin.collections.Iterator",
	"Collection":        "kotlin.collections.Collection",
	"Array":             "kotlin.Array",
	"IntArray":          "kotlin.IntArray",
	"LongArray":         "kotlin.LongArray",
	"ByteArray":         "kotlin.ByteArray",
	"CharArray":         "kotlin.CharArray",
	"BooleanArray":      "kotlin.BooleanArray",
	"FloatArray":        "kotlin.FloatArray",
	"DoubleArray":       "kotlin.DoubleArray",
	"ShortArray":        "kotlin.ShortArray",
}

KotlinStdlibTypes maps common stdlib type simple names to FQNs.

View Source
var PrimitiveTypes = map[string]string{
	"Int": "kotlin.Int", "Long": "kotlin.Long", "Short": "kotlin.Short",
	"Byte": "kotlin.Byte", "Float": "kotlin.Float", "Double": "kotlin.Double",
	"Boolean": "kotlin.Boolean", "Char": "kotlin.Char", "String": "kotlin.String",
	"Unit": "kotlin.Unit", "Nothing": "kotlin.Nothing", "Any": "kotlin.Any",
}

PrimitiveTypes maps Kotlin primitive type names to their FQNs.

View Source
var StdlibMethods map[string]*StdlibMethod

StdlibMethods maps "ReceiverType.methodName" -> return type info. The receiver type uses simple names (String, List, Map, etc.). For collection types, List/Collection/Iterable/MutableList share entries.

Functions

func ClearTypeIndexCache

func ClearTypeIndexCache(dir string) error

func ImplementsInterface

func ImplementsInterface(typeFQN, interfaceFQN string) bool

ImplementsInterface checks whether a given FQN is a known implementor of the specified interface FQN.

func IsKnownCloseable

func IsKnownCloseable(typeName string) bool

IsKnownCloseable returns true if the type name (simple name) is known to implement Closeable.

func IsKnownSubtype

func IsKnownSubtype(typeFQN, supertypeFQN string) bool

IsKnownSubtype checks whether typeFQN is a known subtype of supertypeFQN using KnownClassHierarchy (transitive) and KnownInterfaces.

func IsKnownValueType

func IsKnownValueType(rt *ResolvedType) bool

IsKnownValueType returns true if the resolved type (by Name or FQN) is a known value type where structural equality should be preferred.

func IsSubtypeOfException

func IsSubtypeOfException(a, b string) bool

IsSubtypeOfException checks if exceptionA is a subtype of exceptionB.

func MapJavaToKotlin

func MapJavaToKotlin(javaFQN string) string

MapJavaToKotlin returns the Kotlin equivalent FQN for a Java FQN. Returns "" if no mapping exists.

func NewResolver

func NewResolver() *defaultResolver

NewResolver creates a new resolver backed by source-level analysis.

func TypeIndexCacheDir

func TypeIndexCacheDir(repoDir string) string

TypeIndexCacheDir returns the per-file source type-index cache directory.

Types

type ClassInfo

type ClassInfo struct {
	Name       string   // Simple name
	FQN        string   // Fully qualified name
	Kind       string   // "class", "interface", "object", "enum", "sealed class", "sealed interface"
	Supertypes []string // FQNs of direct supertypes
	IsSealed   bool
	IsData     bool
	IsInner    bool
	IsAbstract bool
	IsOpen     bool
	Members    []MemberInfo
	File       string // Source file path
	Line       int
}

ClassInfo holds information about a class resolved from source.

type ExtensionFuncInfo

type ExtensionFuncInfo struct {
	ReceiverType string        // Simple name of the receiver type (e.g., "String")
	Name         string        // Function name
	ReturnType   *ResolvedType // Return type
}

ExtensionFuncInfo describes an extension function from source.

type FakeResolver

type FakeResolver struct {
	NodeTypes   map[string]*ResolvedType // node text → type
	NameTypes   map[string]*ResolvedType // variable name → type
	Imports     map[string]string        // simple name → FQN
	Nullability map[string]*bool         // node text → nullable
	Classes     map[string]*ClassInfo    // type name → class info
	SealedMap   map[string][]string      // sealed class → variants
	EnumMap     map[string][]string      // enum class → entries
	Annotations map[string]string        // "AnnotationName.argName" → value
}

FakeResolver is a configurable test double for TypeResolver. Set up responses before using in tests.

func NewFakeResolver

func NewFakeResolver() *FakeResolver

NewFakeResolver creates a FakeResolver with all maps initialized.

func (*FakeResolver) AnnotationValueFlat

func (f *FakeResolver) AnnotationValueFlat(_ uint32, _ *scanner.File, annotationName, argName string) string

func (*FakeResolver) ClassHierarchy

func (f *FakeResolver) ClassHierarchy(typeName string) *ClassInfo

ClassHierarchy returns the configured ClassInfo for the type name, or nil.

func (*FakeResolver) EnumEntries

func (f *FakeResolver) EnumEntries(enumTypeName string) []string

EnumEntries returns the configured entries for the enum class, or nil.

func (*FakeResolver) IsExceptionSubtype

func (f *FakeResolver) IsExceptionSubtype(a, b string) bool

IsExceptionSubtype delegates to the global ExceptionAncestors table.

func (*FakeResolver) IsNullableFlat

func (f *FakeResolver) IsNullableFlat(idx uint32, file *scanner.File) *bool

func (*FakeResolver) ResolveByNameFlat

func (f *FakeResolver) ResolveByNameFlat(name string, _ uint32, _ *scanner.File) *ResolvedType

func (*FakeResolver) ResolveFlatNode

func (f *FakeResolver) ResolveFlatNode(idx uint32, file *scanner.File) *ResolvedType

func (*FakeResolver) ResolveImport

func (f *FakeResolver) ResolveImport(simpleName string, _ *scanner.File) string

ResolveImport returns the configured FQN for the simple name, or "".

func (*FakeResolver) SealedVariants

func (f *FakeResolver) SealedVariants(sealedTypeName string) []string

SealedVariants returns the configured variants for the sealed class, or nil.

type FileTypeInfo

type FileTypeInfo struct {
	Path        string
	ImportTable *ImportTable
	RootScope   *ScopeTable
	Classes     []*ClassInfo
	SealedSubs  map[string][]string      // supertype name → subclass names
	EnumEntries map[string][]string      // enum class name → entry names
	TypeAliases map[string]*ResolvedType // alias name or FQN → target type
	Functions   map[string]*ResolvedType // function name → return type
	Extensions  []*ExtensionFuncInfo     // extension functions
}

FileTypeInfo holds all type information extracted from a single file. It is produced independently per file with no shared state, enabling embarrassingly parallel indexing.

func IndexFileParallel

func IndexFileParallel(file *scanner.File) *FileTypeInfo

IndexFileParallel extracts type info from a single file without touching any shared state. Returns a FileTypeInfo that can be merged later.

type ImportTable

type ImportTable struct {
	Explicit map[string]string // import com.foo.Bar → "Bar" → "com.foo.Bar"
	Wildcard []string          // import com.foo.* → ["com.foo"]
	Aliases  map[string]string // import com.foo.Bar as Baz → "Baz" → "com.foo.Bar"
}

ImportTable maps simple names to FQNs for a single file.

func (*ImportTable) Resolve

func (it *ImportTable) Resolve(simpleName string) string

Resolve returns the FQN for a simple name, checking explicit imports, Kotlin stdlib, and primitives.

type MemberInfo

type MemberInfo struct {
	Name       string
	Kind       string        // "function", "property"
	Type       *ResolvedType // function: return type; property: declared type
	Visibility string        // "public", "private", "internal", "protected"
	IsOverride bool
	IsAbstract bool
	// Params is the parameter list for function members. Nil for
	// properties or for functions where parameters could not be
	// extracted. The order matches the source declaration. Each
	// ParamInfo records the parameter's simple name and best-effort
	// resolved type — types from same-workspace declarations populate
	// fully; library-typed parameters carry only the simple name with
	// a TypeUnknown ResolvedType until classpath-aware resolution lands.
	Params []ParamInfo
	// TypeParameters is the simple list of generic type parameter names
	// declared on the function (e.g. ["T", "R"] for `fun <T, R> f()`).
	// Populated for function members; nil for properties.
	TypeParameters []string
}

MemberInfo holds information about a class member.

type ParamInfo added in v0.2.0

type ParamInfo struct {
	Name       string
	Type       *ResolvedType
	HasDefault bool
}

ParamInfo describes a function parameter as recorded in MemberInfo.

type ResolvedType

type ResolvedType struct {
	Name       string         // Simple name: "String", "MutableList"
	FQN        string         // Fully qualified: "kotlin.String", "kotlin.collections.MutableList"
	Kind       TypeKind       // What category of type
	Nullable   bool           // Is this T?
	TypeArgs   []ResolvedType // Generic type arguments
	Supertypes []string       // Known supertypes from source (FQN)
}

ResolvedType represents a type resolved from source analysis.

func UnknownType

func UnknownType() *ResolvedType

UnknownType returns a type with no resolution.

func (*ResolvedType) IsMutable

func (t *ResolvedType) IsMutable() bool

IsMutable returns whether this is a known mutable collection type.

func (*ResolvedType) IsNullable

func (t *ResolvedType) IsNullable() bool

IsNullable returns whether this type allows null values.

func (*ResolvedType) IsPrimitive

func (t *ResolvedType) IsPrimitive() bool

IsPrimitive returns whether this is a Kotlin primitive type.

func (*ResolvedType) IsSubtypeOf

func (t *ResolvedType) IsSubtypeOf(typeName string) bool

IsSubtypeOf checks if this type is a known subtype of the given type name.

type ScopeTable

type ScopeTable struct {
	Parent         *ScopeTable
	Children       []*ScopeTable
	Entries        map[string]*ResolvedType // name → type
	SmartCasts     map[string]bool          // variable names known to be non-null in this scope
	SmartCastTypes map[string]*ResolvedType // variable names narrowed by is-checks
	StartByte      uint32                   // byte offset where this scope begins
	EndByte        uint32                   // byte offset where this scope ends
}

ScopeTable tracks variable declarations and their types within a scope.

func (*ScopeTable) Declare

func (s *ScopeTable) Declare(name string, typ *ResolvedType)

Declare adds a variable to the current scope.

func (*ScopeTable) FindScopeAtOffset

func (s *ScopeTable) FindScopeAtOffset(offset uint32) *ScopeTable

FindScopeAtOffset finds the most specific (deepest) scope containing the given byte offset.

func (*ScopeTable) IsSmartCastNonNull

func (s *ScopeTable) IsSmartCastNonNull(name string) bool

IsSmartCastNonNull checks if a name is smart-cast to non-null in this scope or any parent.

func (*ScopeTable) Lookup

func (s *ScopeTable) Lookup(name string) *ResolvedType

Lookup finds a variable in the current scope or any parent. If the variable is smart-cast to non-null in the current scope chain, the returned type will have Nullable set to false. If the variable has been narrowed by an is-check, the narrowed type is returned.

func (*ScopeTable) NewScope

func (s *ScopeTable) NewScope() *ScopeTable

NewScope creates a child scope.

func (*ScopeTable) NewScopeForNode

func (s *ScopeTable) NewScopeForNode(node interface {
	StartByte() uint32
	EndByte() uint32
}) *ScopeTable

NewScopeForNode creates a child scope with byte range from the given node.

type StdlibMethod

type StdlibMethod struct {
	ReturnType         *ResolvedType
	Nullable           bool
	ReturnTypeArgIndex int // -1 = use fixed ReturnType; 0+ = use receiver's TypeArgs[i]
}

StdlibMethod describes a known stdlib method's return type.

func LookupStdlibMethod

func LookupStdlibMethod(receiverType, methodName string) *StdlibMethod

LookupStdlibMethod looks up a stdlib method by receiver type name and method name. It tries the exact receiver first, then falls back to common supertype aliases.

type TypeKind

type TypeKind int

TypeKind represents the category of a resolved type.

const (
	TypeUnknown   TypeKind = iota
	TypeClass              // class, interface, object, enum
	TypePrimitive          // Int, Long, Boolean, etc.
	TypeNullable           // T? wrapper
	TypeFunction           // (A, B) -> C
	TypeGeneric            // T, with bounds
	TypeArray              // Array<T>, IntArray, etc.
	TypeUnit               // Unit (void equivalent)
	TypeNothing            // Nothing (bottom type)
)

type TypeResolver

type TypeResolver interface {
	// ResolveFlatNode returns the inferred type at a flat-tree index.
	// This is the preferred production API.
	// Returns UnknownType if the type cannot be determined.
	ResolveFlatNode(idx uint32, file *scanner.File) *ResolvedType

	// ResolveByName looks up a variable/property name in the current scope.
	ResolveByNameFlat(name string, idx uint32, file *scanner.File) *ResolvedType

	// ResolveImport returns the FQN for an imported simple name.
	// Returns "" if not imported.
	ResolveImport(simpleName string, file *scanner.File) string

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

	// ClassHierarchy returns the known class hierarchy for a type.
	ClassHierarchy(typeName string) *ClassInfo

	// SealedVariants returns known variants of a sealed class/interface.
	SealedVariants(sealedTypeName string) []string

	// EnumEntries returns known entries of an enum class.
	EnumEntries(enumTypeName string) []string

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

	// IsExceptionSubtype checks if exceptionA is a known subtype of exceptionB.
	IsExceptionSubtype(a, b string) bool
}

TypeResolver resolves types from Kotlin source ASTs. It is the main interface rules use to query type information.

Jump to

Keyboard shortcuts

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