Skip to content

Semantic Index

SemanticIndex is the core semantic database used for completion and definition.

Data model

  • PsiElement base class with file and location.
  • Types: Module, Class, Enum, Method, InstanceVar, ClassVar, LocalVar, Alias, EnumMember.
  • TypeRef: lightweight type handle with a name, generic args, and union variants.

Indexing passes

  • SkeletonIndexer: builds type shells and records type variables and superclasses.
  • SemanticIndexer: attaches methods, includes, enum members, and aliases.
  • Macro pre-expansion: expands supported macros into virtual files for indexing.

Type hints

Type inference is intentionally light. The indexer extracts TypeRef from:

  • explicit type annotations
  • simple assignments when the RHS is a Foo.new call
  • array or hash literals with an explicit of type
  • casts, metaclasses, and union/generic type syntax

Resolution

find_definitions resolves:

  • types and namespaces (Path, Generic)
  • enum members
  • aliases
  • methods with arity filtering, including inherited methods (including class vs instance, includes, superclasses)
  • locals, instance vars, class vars
  • constructors (new -> initialize/self.new)
  • call hierarchy edges (outgoing/incoming) via resolved calls
  • references for types/aliases across files (path matching)

Dependencies

Include/extend and superclass edges are tracked. When a file changes, dependent types and their files are reindexed.

Macro expansion

Supported macros:

  • built-in: getter, setter, property, record
  • user-defined: interpreted via a small MacroInterpreter

Expanded nodes are indexed under crystal-macro: virtual URIs.