resolution

package
v0.0.0-...-fee3e51 Latest Latest
Warning

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

Go to latest
Published: Nov 16, 2025 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package resolution provides type information structures for type resolution and inference.

This package defines the type system used by the type inference engine and registry packages. It contains data structures that track variable bindings and function scopes during type analysis.

Type Information

The core type information is defined in the core package (core.TypeInfo), while this package focuses on scope and binding management:

typeInfo := &core.TypeInfo{
    TypeFQN:    "builtins.str",
    Source:     "literal",
    Confidence: 1.0,
}

binding := &resolution.VariableBinding{
    VarName: "username",
    Type:    typeInfo,
}

Function Scopes

FunctionScope tracks variable bindings within a function:

scope := resolution.NewFunctionScope("myapp.views.login")
scope.AddVariable(&resolution.VariableBinding{
    VarName: "user",
    Type:    &core.TypeInfo{TypeFQN: "myapp.models.User"},
})

Breaking Circular Dependencies

This package was created to resolve the circular dependency between builtin_registry.go and type_inference.go by providing shared type definitions that both packages can depend on without depending on each other.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractCallSites

func ExtractCallSites(filePath string, sourceCode []byte, importMap *core.ImportMap) ([]*core.CallSite, error)

ExtractCallSites extracts all function/method call sites from a Python file. It traverses the AST to find call expressions and builds CallSite objects with caller context, callee information, and arguments.

Algorithm:

  1. Parse source code with tree-sitter Python parser
  2. Traverse AST to find call expressions
  3. For each call, extract: - Caller function/method (containing context) - Callee name (function/method being called) - Arguments (positional and keyword) - Source location (file, line, column)
  4. Build CallSite objects for each call

Parameters:

  • filePath: absolute path to the Python file being analyzed
  • sourceCode: contents of the Python file as byte array
  • importMap: import mappings for resolving qualified names

Returns:

  • []CallSite: list of all call sites found in the file
  • error: if parsing fails or source is invalid

Example:

Source code:
  def process_data():
      result = sanitize(data)
      db.query(result)

Extracts CallSites:
  [
    {Caller: "process_data", Callee: "sanitize", Args: ["data"]},
    {Caller: "process_data", Callee: "db.query", Args: ["result"]}
  ]

func ExtractImports

func ExtractImports(filePath string, sourceCode []byte, registry *core.ModuleRegistry) (*core.ImportMap, error)

ExtractImports extracts all import statements from a Python file and builds an ImportMap. It handles four main import styles:

  1. Simple imports: import module
  2. From imports: from module import name
  3. Aliased imports: from module import name as alias
  4. Relative imports: from . import module, from .. import module

The resulting ImportMap maps local names (aliases or imported names) to their fully qualified module paths, enabling later resolution of function calls.

Algorithm:

  1. Parse source code with tree-sitter Python parser
  2. Traverse AST to find all import statements
  3. Process each import to extract module paths and aliases
  4. Resolve relative imports using module registry
  5. Build ImportMap with resolved fully qualified names

Parameters:

  • filePath: absolute path to the Python file being analyzed
  • sourceCode: contents of the Python file as byte array
  • registry: module registry for resolving module paths and relative imports

Returns:

  • ImportMap: map of local names to fully qualified module paths
  • error: if parsing fails or source is invalid

Example:

Source code:
  import os
  from myapp.utils import sanitize
  from myapp.db import query as db_query
  from . import helper
  from ..config import settings

Result ImportMap:
  {
    "os": "os",
    "sanitize": "myapp.utils.sanitize",
    "db_query": "myapp.db.query",
    "helper": "myapp.submodule.helper",
    "settings": "myapp.config.settings"
  }

func IsDjangoORMPattern

func IsDjangoORMPattern(target string) (bool, string)

IsDjangoORMPattern checks if a call target matches Django ORM pattern. Django ORM pattern: ModelName.objects.<method>

Examples:

  • "Task.objects.filter" → true
  • "User.objects.get" → true
  • "Annotation.objects.all" → true
  • "task.save" → false (instance method, not manager)

Parameters:

  • target: call target string (e.g., "Task.objects.filter")

Returns:

  • true if it matches Django ORM pattern
  • the method name if matched (e.g., "filter")

func IsORMPattern

func IsORMPattern(target string) (bool, string, string)

IsORMPattern checks if a call target matches any known ORM pattern.

Parameters:

  • target: call target string

Returns:

  • true if it matches any ORM pattern
  • the ORM pattern name (e.g., "Django ORM")
  • the method name (e.g., "filter")

func IsSQLAlchemyORMPattern

func IsSQLAlchemyORMPattern(target string) (bool, string)

IsSQLAlchemyORMPattern checks if a call target matches SQLAlchemy ORM pattern. SQLAlchemy patterns are more varied, but common ones include:

  • session.query(Model).filter(...)
  • db.session.query(Model).all()
  • Model.query.filter_by(...)

Parameters:

  • target: call target string

Returns:

  • true if it matches SQLAlchemy ORM pattern
  • the method name if matched

func MergeReturnTypes

func MergeReturnTypes(statements []*ReturnStatement) map[string]*core.TypeInfo

MergeReturnTypes combines multiple return statements for same function. Takes the highest confidence return type.

func PrintAttributeFailureStats

func PrintAttributeFailureStats()

PrintAttributeFailureStats prints detailed statistics about attribute chain failures.

func ResolveAttributePlaceholders

func ResolveAttributePlaceholders(
	registry *registry.AttributeRegistry,
	typeEngine *TypeInferenceEngine,
	moduleRegistry *core.ModuleRegistry,
	codeGraph *graph.CodeGraph,
)

ResolveAttributePlaceholders resolves placeholder types in the attribute registry Placeholders are created during extraction when we can't determine the exact type:

  • class:User → resolve to fully qualified class name
  • call:calculate → resolve to function return type
  • param:User → resolve to fully qualified class name

This is Pass 3 of the attribute extraction algorithm.

Parameters:

  • registry: attribute registry with placeholder types
  • typeEngine: type inference engine with return types
  • moduleRegistry: module registry for resolving class names
  • codeGraph: code graph for finding class definitions

func ResolveChainedCall

func ResolveChainedCall(
	target string,
	typeEngine *TypeInferenceEngine,
	builtins *registry.BuiltinRegistry,
	moduleRegistry *core.ModuleRegistry,
	codeGraph *graph.CodeGraph,
	callerFQN string,
	currentModule string,
	callGraph *core.CallGraph,
) (string, bool, *core.TypeInfo)

ResolveChainedCall resolves a method chain by walking each step and tracking types.

Algorithm:

  1. Parse chain into individual steps
  2. Resolve first step: - If it's a call: resolve as function call, get return type - If it's a variable: look up type in scopes
  3. For each subsequent step: - Use previous step's type to resolve method - Get method's return type from builtins or return type registry - Track confidence through the chain (multiply confidences)
  4. Return final type and resolution status

Parameters:

  • target: the full target string (e.g., "create_builder().append().upper()")
  • typeEngine: type inference engine with scopes and return types
  • builtins: builtin registry for builtin method lookups
  • registry: module registry for validation
  • codeGraph: code graph for function lookups
  • callerFQN: FQN of the calling function (for scope lookups)
  • currentModule: current module path
  • callGraph: call graph for function lookups

Returns:

  • targetFQN: the fully qualified name of the final call
  • resolved: true if chain was successfully resolved
  • typeInfo: type information for the final result

func ResolveClassInstantiation

func ResolveClassInstantiation(
	callNode *sitter.Node,
	sourceCode []byte,
	modulePath string,
	importMap *core.ImportMap,
	registry *core.ModuleRegistry,
) *core.TypeInfo

ResolveClassInstantiation attempts to resolve class instantiation patterns.

func ResolveDjangoORMCall

func ResolveDjangoORMCall(target string, modulePath string, registry *core.ModuleRegistry, codeGraph *graph.CodeGraph) (string, bool)

ResolveDjangoORMCall attempts to resolve a Django ORM call pattern. It constructs a synthetic FQN for the ORM method even though it doesn't exist in source code, because Django generates these methods at runtime.

Parameters:

  • target: the call target (e.g., "Task.objects.filter")
  • modulePath: the current module path
  • registry: module registry
  • codeGraph: the parsed code graph (for model validation)

Returns:

  • fully qualified name for the ORM call
  • true if successfully resolved as Django ORM

func ResolveORMCall

func ResolveORMCall(target string, modulePath string, registry *core.ModuleRegistry, codeGraph *graph.CodeGraph) (string, bool)

ResolveORMCall attempts to resolve any ORM pattern.

Parameters:

  • target: the call target
  • modulePath: the current module path
  • registry: module registry
  • codeGraph: the parsed code graph

Returns:

  • fully qualified name for the ORM call
  • true if successfully resolved as any ORM pattern

func ResolveSQLAlchemyORMCall

func ResolveSQLAlchemyORMCall(target string, modulePath string) (string, bool)

ResolveSQLAlchemyORMCall attempts to resolve a SQLAlchemy ORM call pattern.

Parameters:

  • target: the call target
  • modulePath: the current module path

Returns:

  • fully qualified name for the ORM call
  • true if successfully resolved as SQLAlchemy ORM

func ResolveSelfAttributeCall

func ResolveSelfAttributeCall(
	target string,
	callerFQN string,
	typeEngine *TypeInferenceEngine,
	builtins *registry.BuiltinRegistry,
	callGraph *core.CallGraph,
) (string, bool, *core.TypeInfo)

ResolveSelfAttributeCall resolves self.attribute.method() patterns This is the core of Phase 3 Task 12 - using extracted attributes to resolve calls.

Algorithm:

  1. Detect pattern: target starts with "self." and has 2+ dots
  2. Parse: self.attr.method → attr="attr", method="method"
  3. Find containing class from callerFQN
  4. Lookup attribute type in AttributeRegistry
  5. Resolve method on inferred type

Example:

Input: self.value.upper (caller: test_chaining.StringBuilder.process)
Steps:
  1. Parse → attr="value", method="upper"
  2. Extract class → test_chaining.StringBuilder
  3. Lookup value type → builtins.str
  4. Resolve upper on str → builtins.str.upper
Output: (builtins.str.upper, true, TypeInfo{builtins.str, 1.0, "self_attribute"})

Parameters:

  • target: call target string (e.g., "self.value.upper")
  • callerFQN: fully qualified name of calling function
  • typeEngine: type inference engine with attribute registry
  • builtins: builtin registry for method lookup
  • callGraph: call graph for class lookup

Returns:

  • resolvedFQN: fully qualified method name
  • resolved: true if resolution succeeded
  • typeInfo: inferred type information

func ValidateDjangoModel

func ValidateDjangoModel(modelName string, codeGraph *graph.CodeGraph) bool

ValidateDjangoModel checks if a name is likely a Django model by examining the code graph for the class definition and checking if it inherits from django.db.models.Model or has "Model" in its name.

This is a heuristic check since we can't always definitively determine if something is a Django model without runtime information.

Parameters:

  • modelName: the name to check (e.g., "Task", "User")
  • codeGraph: the parsed code graph

Returns:

  • true if the name is likely a Django model

Types

type ChainStep

type ChainStep struct {
	Expression string         // The full expression for this step (e.g., "create_builder()")
	MethodName string         // Just the method/function name (e.g., "create_builder")
	IsCall     bool           // True if this step is a function call (has parentheses)
	Type       *core.TypeInfo // Resolved type after this step
}

ChainStep represents a single step in a method chain. For example, in "obj.method1().method2()", there are 2 steps:

  • Step 1: obj.method1() → returns some type
  • Step 2: result.method2() → returns some type

func ParseChain

func ParseChain(target string) []ChainStep

ParseChain parses a method chain into individual steps.

Examples:

  • "create_builder().append()" → ["create_builder()", "append()"]
  • "text.strip().upper().split()" → ["text.strip()", "upper()", "split()"]
  • "obj.attr.method()" → ["obj.attr.method()"] (not a chain, just nested attribute)

A chain is identified by the pattern "().": a call followed by more method access.

Parameters:

  • target: the full target string from call site

Returns:

  • []ChainStep: parsed chain steps, or nil if not a chain

type FailureStats

type FailureStats struct {
	TotalAttempts          int
	NotSelfPrefix          int
	DeepChains             int // 3+ levels
	ClassNotFound          int
	AttributeNotFound      int
	MethodNotInBuiltins    int
	CustomClassUnsupported int

	// Pattern samples for analysis
	DeepChainSamples         []string
	AttributeNotFoundSamples []string
	CustomClassSamples       []string
}

FailureStats tracks why attribute chain resolution fails.

type FunctionScope

type FunctionScope struct {
	FunctionFQN string                      // Fully qualified name of the function
	Variables   map[string]*VariableBinding // Variable name -> binding
	ReturnType  *core.TypeInfo              // Inferred return type of the function
}

FunctionScope represents the type environment within a function. It tracks variable types and return type for a specific function.

func NewFunctionScope

func NewFunctionScope(functionFQN string) *FunctionScope

NewFunctionScope creates a new function scope with initialized maps.

Parameters:

  • functionFQN: fully qualified name of the function

Returns:

  • Initialized FunctionScope

func (*FunctionScope) AddVariable

func (fs *FunctionScope) AddVariable(binding *VariableBinding)

AddVariable adds or updates a variable binding in the scope.

Parameters:

  • binding: the variable binding to add

func (*FunctionScope) GetVariable

func (fs *FunctionScope) GetVariable(varName string) *VariableBinding

GetVariable retrieves a variable binding by name.

Parameters:

  • varName: the variable name to look up

Returns:

  • VariableBinding if found, nil otherwise

func (*FunctionScope) HasVariable

func (fs *FunctionScope) HasVariable(varName string) bool

HasVariable checks if a variable exists in the scope.

Parameters:

  • varName: the variable name to check

Returns:

  • true if the variable exists, false otherwise

type Location

type Location struct {
	File      string // File path
	Line      uint32 // Line number
	Column    uint32 // Column number
	StartByte uint32 // Starting byte offset
	EndByte   uint32 // Ending byte offset
}

Location represents a source code location.

type ORMPattern

type ORMPattern struct {
	Name        string   // Pattern name (e.g., "Django ORM")
	MethodNames []string // Common ORM method names
	Description string   // Human-readable description
}

ORMPattern represents a recognized ORM pattern (e.g., Django ORM, SQLAlchemy). These patterns are dynamically generated at runtime and won't be found in source code, but we can still resolve them by recognizing the pattern.

type ReturnStatement

type ReturnStatement struct {
	FunctionFQN string
	ReturnType  *core.TypeInfo
	Location    Location
}

ReturnStatement represents a return statement in a function.

func ExtractReturnTypes

func ExtractReturnTypes(
	filePath string,
	sourceCode []byte,
	modulePath string,
	builtinRegistry *registry.BuiltinRegistry,
) ([]*ReturnStatement, error)

ExtractReturnTypes analyzes return statements in all functions in a file.

type StdlibRegistryRemote

type StdlibRegistryRemote interface{}

StdlibRegistryRemote will be defined in registry package. For now, use an interface or accept nil.

type TypeInferenceEngine

type TypeInferenceEngine struct {
	Scopes         map[string]*FunctionScope   // Function FQN -> scope
	ReturnTypes    map[string]*core.TypeInfo   // Function FQN -> return type
	Builtins       *registry.BuiltinRegistry   // Builtin types registry
	Registry       *core.ModuleRegistry        // Module registry reference
	Attributes     *registry.AttributeRegistry // Class attributes registry (Phase 3 Task 12)
	StdlibRegistry *core.StdlibRegistry        // Python stdlib registry (PR #2)
	StdlibRemote   interface{}                 // Remote loader for lazy module loading (PR #3)
}

TypeInferenceEngine manages type inference across the codebase. It maintains function scopes, return types, and references to other registries.

func NewTypeInferenceEngine

func NewTypeInferenceEngine(registry *core.ModuleRegistry) *TypeInferenceEngine

NewTypeInferenceEngine creates a new type inference engine. The engine is initialized with empty scopes and return types.

Parameters:

  • registry: module registry for resolving module paths

Returns:

  • Initialized TypeInferenceEngine

func (*TypeInferenceEngine) AddReturnTypesToEngine

func (te *TypeInferenceEngine) AddReturnTypesToEngine(returnTypes map[string]*core.TypeInfo)

AddReturnTypesToEngine populates TypeInferenceEngine with return types.

func (*TypeInferenceEngine) AddScope

func (te *TypeInferenceEngine) AddScope(scope *FunctionScope)

AddScope adds or updates a function scope in the engine.

Parameters:

  • scope: the function scope to add

func (*TypeInferenceEngine) GetScope

func (te *TypeInferenceEngine) GetScope(functionFQN string) *FunctionScope

GetScope retrieves a function scope by its fully qualified name.

Parameters:

  • functionFQN: fully qualified name of the function

Returns:

  • FunctionScope if found, nil otherwise

func (*TypeInferenceEngine) ResolveVariableType

func (te *TypeInferenceEngine) ResolveVariableType(
	assignedFrom string,
	confidence float32,
) *core.TypeInfo

ResolveVariableType resolves the type of a variable assignment from a function call. It looks up the return type of the called function and propagates it with confidence decay.

Parameters:

  • assignedFrom: Function FQN that was called
  • confidence: Base confidence from assignment

Returns:

  • TypeInfo with propagated type, or nil if function has no return type

func (*TypeInferenceEngine) UpdateVariableBindingsWithFunctionReturns

func (te *TypeInferenceEngine) UpdateVariableBindingsWithFunctionReturns()

UpdateVariableBindingsWithFunctionReturns resolves "call:funcName" placeholders. It iterates through all scopes and replaces placeholder types with actual return types.

This enables inter-procedural type propagation:

user = create_user()  # Initially typed as "call:create_user"
# After update, typed as "test.User" based on create_user's return type

type VariableBinding

type VariableBinding struct {
	VarName      string         // Variable name
	Type         *core.TypeInfo // Inferred type information
	AssignedFrom string         // FQN of function that assigned this value (if from function call)
	Location     Location       // Source location of the assignment
}

VariableBinding tracks a variable's type within a scope. It captures the variable name, its inferred type, and source location.

Jump to

Keyboard shortcuts

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