csresolve

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2026 License: MIT Imports: 8 Imported by: 0

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

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

func IsBuiltinFunc(name string) bool

IsBuiltinFunc returns true if the given name is a C# expression keyword that should not be resolved as a user-defined call.

func IsKeywordSelf

func IsKeywordSelf(name string) bool

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

func PredefinedAlias(name string) string

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:

  1. Strip global:: prefix, normalize :: to .
  2. Strip generic args for lookup
  3. Check predefined alias (int -> System.Int32)
  4. Exact registry hit
  5. Nested type under enclosing class
  6. Each namespace prefix from innermost outward
  7. Module-prefixed (file-local QN)
  8. using namespace X -> try X.bare
  9. using A = X alias substitution
  10. Short-name fallback
  11. 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.

func BuildUsingMap

func BuildUsingMap(root *sitter.Node, content []byte) []UsingInfo

BuildUsingMap extracts all using directives from the C# AST root and returns a slice of UsingInfo. Always includes implicit "using System".

type UsingKind

type UsingKind int

UsingKind classifies the kind of a C# using directive.

const (
	// UsingNamespace is a plain "using Namespace;" directive.
	UsingNamespace UsingKind = iota
	// UsingStatic is a "using static Class;" directive.
	UsingStatic
	// UsingAlias is a "using Alias = Target;" directive.
	UsingAlias
)

Jump to

Keyboard shortcuts

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