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 ¶
- func ExtractCallSites(filePath string, sourceCode []byte, importMap *core.ImportMap) ([]*core.CallSite, error)
- func ExtractImports(filePath string, sourceCode []byte, registry *core.ModuleRegistry) (*core.ImportMap, error)
- func IsDjangoORMPattern(target string) (bool, string)
- func IsORMPattern(target string) (bool, string, string)
- func IsSQLAlchemyORMPattern(target string) (bool, string)
- func MergeReturnTypes(statements []*ReturnStatement) map[string]*core.TypeInfo
- func PrintAttributeFailureStats()
- func ResolveAttributePlaceholders(registry *registry.AttributeRegistry, typeEngine *TypeInferenceEngine, ...)
- func ResolveChainedCall(target string, typeEngine *TypeInferenceEngine, ...) (string, bool, *core.TypeInfo)
- func ResolveClassInstantiation(callNode *sitter.Node, sourceCode []byte, modulePath string, ...) *core.TypeInfo
- func ResolveDjangoORMCall(target string, modulePath string, registry *core.ModuleRegistry, ...) (string, bool)
- func ResolveORMCall(target string, modulePath string, registry *core.ModuleRegistry, ...) (string, bool)
- func ResolveSQLAlchemyORMCall(target string, modulePath string) (string, bool)
- func ResolveSelfAttributeCall(target string, callerFQN string, typeEngine *TypeInferenceEngine, ...) (string, bool, *core.TypeInfo)
- func ValidateDjangoModel(modelName string, codeGraph *graph.CodeGraph) bool
- type ChainStep
- type FailureStats
- type FunctionScope
- type Location
- type ORMPattern
- type ReturnStatement
- type StdlibRegistryRemote
- type TypeInferenceEngine
- func (te *TypeInferenceEngine) AddReturnTypesToEngine(returnTypes map[string]*core.TypeInfo)
- func (te *TypeInferenceEngine) AddScope(scope *FunctionScope)
- func (te *TypeInferenceEngine) GetScope(functionFQN string) *FunctionScope
- func (te *TypeInferenceEngine) ResolveVariableType(assignedFrom string, confidence float32) *core.TypeInfo
- func (te *TypeInferenceEngine) UpdateVariableBindingsWithFunctionReturns()
- type VariableBinding
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:
- Parse source code with tree-sitter Python parser
- Traverse AST to find call expressions
- For each call, extract: - Caller function/method (containing context) - Callee name (function/method being called) - Arguments (positional and keyword) - Source location (file, line, column)
- 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:
- Simple imports: import module
- From imports: from module import name
- Aliased imports: from module import name as alias
- 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:
- Parse source code with tree-sitter Python parser
- Traverse AST to find all import statements
- Process each import to extract module paths and aliases
- Resolve relative imports using module registry
- 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 ¶
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 ¶
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 ¶
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:
- Parse chain into individual steps
- 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
- 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)
- 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 ¶
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:
- Detect pattern: target starts with "self." and has 2+ dots
- Parse: self.attr.method → attr="attr", method="method"
- Find containing class from callerFQN
- Lookup attribute type in AttributeRegistry
- 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 ¶
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 ¶
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 ¶
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.