Documentation
¶
Overview ¶
Package csresolve implements the C# language in-process type resolver. It implements the typresolve.Resolver interface, resolving C# call expressions and type references using tree-sitter AST walking and a shared type registry built from extracted definitions.
Index ¶
- func BuildRegistry(defs []typresolve.ResolverDef) *typresolve.Registry
- func EvalExprType(ctx *ResolveContext, node *sitter.Node) *typresolve.Type
- func IsBuiltinFunc(name string) bool
- func IsKeywordSelf(name string) bool
- func LookupExtensionMethod(reg *typresolve.Registry, receiverQN string, methodName string) *typresolve.RegisteredFunc
- func LookupField(reg *typresolve.Registry, typeQN string, fieldName string) *typresolve.Type
- func LookupMethod(reg *typresolve.Registry, typeQN string, methodName string) *typresolve.RegisteredFunc
- func ParseTypeNode(node *sitter.Node, content []byte, namespaceQN string, usings []UsingInfo, ...) *typresolve.Type
- func PredefinedAlias(name string) string
- func ProcessStatement(ctx *ResolveContext, node *sitter.Node)
- func RegisterCSharpStdlib(reg *typresolve.Registry)
- func ResolveCallsInFile(ctx *ResolveContext, root *sitter.Node, fileHash types.Hash, repoURL string, ...) []types.Edge
- func ResolveTypeName(raw string, namespaceQN string, usings []UsingInfo, ...) string
- func SubstituteTypeParams(t *typresolve.Type, paramNames []string, paramArgs []*typresolve.Type) *typresolve.Type
- func UnwrapNullable(t *typresolve.Type) *typresolve.Type
- func UnwrapTask(t *typresolve.Type) *typresolve.Type
- type CSharpResolver
- type ResolveContext
- type UsingInfo
- type UsingKind
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildRegistry ¶
func BuildRegistry(defs []typresolve.ResolverDef) *typresolve.Registry
BuildRegistry builds a typresolve.Registry from ResolverDef entries. Registers classes, interfaces, structs, enums, methods (with receiver type), constructors, and properties (as methods). Handles partial class merging by accumulating methods and fields from multiple definitions of the same type QN. Pre-seeds with C# stdlib types (System.String, Console, List, etc.) via RegisterCSharpStdlib so that resolution works without LSP enrichment.
func EvalExprType ¶
func EvalExprType(ctx *ResolveContext, node *sitter.Node) *typresolve.Type
EvalExprType evaluates the type of a C# expression AST node using scope lookup, registry lookup, member access, invocation, and literal types. Port of cs_eval_expr_type from cs_lsp.c lines 716-884.
func IsBuiltinFunc ¶
IsBuiltinFunc returns true if the given name is a C# expression keyword that should not be resolved as a user-defined call.
func IsKeywordSelf ¶
IsKeywordSelf returns true for C# self-referencing keywords "this" and "base".
func LookupExtensionMethod ¶
func LookupExtensionMethod(reg *typresolve.Registry, receiverQN string, methodName string) *typresolve.RegisteredFunc
LookupExtensionMethod searches for a static extension method accessible via using-imported namespaces. An extension method is a static method whose first parameter name starts with "this". Checks receiver compatibility via type match or base class match. Port of cs_lookup_extension from cs_lsp.c lines 506-569.
This is a linear scan over all registered functions (O(N)), which is acceptable for Tier 1 resolution.
func LookupField ¶
func LookupField(reg *typresolve.Registry, typeQN string, fieldName string) *typresolve.Type
LookupField looks up a field on a named type, walking the inheritance chain with BFS and cycle detection. Returns the field's type if found.
func LookupMethod ¶
func LookupMethod(reg *typresolve.Registry, typeQN string, methodName string) *typresolve.RegisteredFunc
LookupMethod looks up a method on a named type, walking the inheritance chain (base classes and interfaces via EmbeddedTypes) using BFS with a visited set for cycle detection, up to maxInheritDepth levels deep. Falls back to System.Object methods (ToString, Equals, GetHashCode, GetType). Port of cs_lookup_method from cs_lsp.c lines 445-499.
func ParseTypeNode ¶
func ParseTypeNode(node *sitter.Node, content []byte, namespaceQN string, usings []UsingInfo, registry *typresolve.Registry) *typresolve.Type
ParseTypeNode converts a tree-sitter C# type AST node to a typresolve.Type. It handles predefined_type, nullable_type, array_type, pointer_type, tuple_type, generic_name, qualified_name, identifier, ref_type, and implicit_type node kinds.
func PredefinedAlias ¶
PredefinedAlias returns the System.* fully qualified name for C# predefined type aliases (int -> System.Int32, string -> System.String, etc.). Returns empty string if name is not a predefined alias.
func ProcessStatement ¶
func ProcessStatement(ctx *ResolveContext, node *sitter.Node)
ProcessStatement processes a C# statement node to bind variables into the current scope. Handles local_declaration_statement, foreach_statement, for_statement, using_statement, variable_declaration, and expression_statement.
func RegisterCSharpStdlib ¶
func RegisterCSharpStdlib(reg *typresolve.Registry)
RegisterCSharpStdlib registers core System types and their methods/fields into the given registry. This enables the resolver to track return types through stdlib call chains (e.g. Console.WriteLine, String.Contains, List<T>.Add, Task<T>.Result).
Port of the implicit stdlib knowledge from cs_lsp.c: the C reference registers these at runtime via the registry builder; we pre-seed them so resolution works even without LSP enrichment.
func ResolveCallsInFile ¶
func ResolveCallsInFile(ctx *ResolveContext, root *sitter.Node, fileHash types.Hash, repoURL string, filePath string) []types.Edge
ResolveCallsInFile walks a C# file's AST resolving call expressions and emitting edges. Uses the shared registry, per-file scope chain, using map, and namespace stack. Processes namespace declarations, class/struct/interface declarations, method/constructor declarations, invocations, and object creation.
func ResolveTypeName ¶
func ResolveTypeName(raw string, namespaceQN string, usings []UsingInfo, registry *typresolve.Registry, enclosingClassQN string, moduleQN string) string
ResolveTypeName resolves a bare type name through the C# resolution chain. It follows the 10-step algorithm ported from cs_lsp.c lines 317-442:
- Strip global:: prefix, normalize :: to .
- Strip generic args for lookup
- Check predefined alias (int -> System.Int32)
- Exact registry hit
- Nested type under enclosing class
- Each namespace prefix from innermost outward
- Module-prefixed (file-local QN)
- using namespace X -> try X.bare
- using A = X alias substitution
- Short-name fallback
- Return bare name as last resort
func SubstituteTypeParams ¶
func SubstituteTypeParams(t *typresolve.Type, paramNames []string, paramArgs []*typresolve.Type) *typresolve.Type
SubstituteTypeParams substitutes type parameters in a type using the given parallel name/arg arrays. Port of cs_substitute_type_params from cs_lsp.c.
func UnwrapNullable ¶
func UnwrapNullable(t *typresolve.Type) *typresolve.Type
UnwrapNullable unwraps Nullable<T> types. Same heuristic as UnwrapTask: if the type name matches System.Nullable, return Unknown (the caller resolves the inner type from context).
func UnwrapTask ¶
func UnwrapTask(t *typresolve.Type) *typresolve.Type
UnwrapTask unwraps async Task<T>/ValueTask<T> types. Since typresolve.Type does not store generic type arguments at the Named level, this uses a name-based heuristic: if the type name matches a Task/ValueTask pattern, return Unknown (the caller resolves the concrete return type via the registry's function signature). For bare Task/ValueTask (void-returning async), also returns Unknown.
Types ¶
type CSharpResolver ¶
type CSharpResolver struct {
// contains filtered or unexported fields
}
CSharpResolver implements typresolve.Resolver for C#. It uses tree-sitter AST walking and a shared type registry to resolve call expressions and type references without requiring an external LSP server.
func NewCSharpResolver ¶
func NewCSharpResolver() *CSharpResolver
NewCSharpResolver creates a new CSharpResolver.
func (*CSharpResolver) InitWorkspace ¶
func (r *CSharpResolver) InitWorkspace(ctx context.Context, defs []typresolve.ResolverDef) error
InitWorkspace builds the cross-file type registry from extracted definitions. Called once before any ResolveFile calls.
func (*CSharpResolver) Language ¶
func (r *CSharpResolver) Language() string
Language returns "csharp".
func (*CSharpResolver) ResolveFile ¶
func (r *CSharpResolver) ResolveFile(ctx context.Context, opts typresolve.ResolveFileOpts) ([]types.Edge, error)
ResolveFile resolves type references in a single C# file. Thread-safe after InitWorkspace completes (registry is read-only, all mutable state is stack-local).
type ResolveContext ¶
type ResolveContext struct {
Registry *typresolve.Registry
Scope *typresolve.Scope
Usings []UsingInfo
NamespaceStack []string
Content []byte
EnclosingFuncQN string
EnclosingClassQN string
EnclosingBaseQN string
ModuleQN string
EvalDepth int
// TypeParamNames holds the type parameter names for the current generic
// context (class or method). Parallel array with TypeParamArgs.
TypeParamNames []string
// TypeParamArgs holds the concrete type arguments substituted for
// TypeParamNames. When resolving inside a generic type/method, bare
// identifiers matching TypeParamNames[i] resolve to TypeParamArgs[i].
TypeParamArgs []*typresolve.Type
}
ResolveContext holds per-file state for C# type resolution.
type UsingInfo ¶
type UsingInfo struct {
Kind UsingKind
LocalName string // for aliases: the local alias name
TargetQN string // the target namespace/class/type
IsGlobal bool
}
UsingInfo represents a single C# using directive with its kind, local name (for aliases), target qualified name, and global flag.