Skip to content
CAI
Software that uses CAICheck a score

elixir-lsp/elixir_sense

68.0

Adequate · 3 October 2026

28.9k

lines of production code

Elixir

primary language

2

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

ElixirSense is a stateless library that provides code intelligence capabilities for Elixir and Erlang, including type inference, documentation retrieval, and symbol navigation. It powers IDE features such as code completion, hover tooltips, and go-to-definition by analyzing code structure and context. The system supports specific frameworks like Ecto and Phoenix through a plugin architecture and maintains compatibility across various Elixir versions via normalized APIs and backports.

How it got here

2016–2019 — Version 2.0 architecture and type inference

11 changes.

The project underwent a major architectural shift to version 2.0, transitioning from an OTP application to a stateless library and raising the minimum Elixir requirement to 1.16. This period focused on implementing a comprehensive structural type-algebra engine for precise type inference and introspection, supported by normalized shims for Elixir's internal APIs. Extensive test coverage and project hygiene improvements, including modernized configuration and static analysis tooling, were integrated to support these core changes.

2023–2024 — completion engine rewrite and type inference

21 changes.

The project overhauled the completion subsystem with a new reducer-based architecture and added plugin support for Ecto and Phoenix frameworks. Significant improvements were made to type inference, introducing occurrence typing and guard handling for more accurate variable narrowing. The codebase was also refactored for Elixir 1.20+ compatibility, expanded to support Erlang navigation, and strengthened with comprehensive test coverage.

5 changes.

This period focused on improving navigation accuracy by replacing lexical analysis with an AST-based classifier in the SurroundContext module, fixing edge cases around symbol boundaries and operator captures. Concurrently, extensive test suites were added to verify the correctness of the completion engine, definition lookup in macros, and the new navigation logic against Elixir's standard library behavior.

Features

Added Erlang source location provider

Introduced a new location provider for Erlang files (\lib/elixir\_sense/providers/location/erl.ex\) that enables the IDE to locate type definitions, function definitions, and module declarations within \.erl\ files. This allows users to navigate to definitions and view symbol locations in Erlang codebases, extending the existing location capabilities beyond Elixir.

_lib/elixir\sense/providers/location · high confidence

Added utility modules for field type extraction and fuzzy name matching

New utility modules have been introduced to support provider functionality: \ElixirSense.Providers.Utils.Field\ now extracts field types from module metadata or via introspection, handling both public and private fields based on configuration, while \ElixirSense.Providers.Utils.Matcher\ implements a naive sequential fuzzy matching algorithm that requires the first character to match, improving how suggestions are filtered and ranked for users.

_lib/elixir\sense/providers/utils · high confidence

Ecto query and schema completion support

Added new completion providers for Ecto that enhance code intelligence when writing queries and defining schemas. The new \Ecto.Query\ provider offers suggestions for query clauses (such as \from\, \join\, and their options) and resolves field completions for bindings, including associations. The \Ecto.Schema\ provider provides autocomplete for schema field options (like \:default\, \:virtual\, \:primary\_key\) and association definitions (\belongs\_to\, \has\_one\, \has\_many\), including detailed documentation for options like \:on\_replace\ and \:on\_delete\. Additionally, the \Ecto.Types\ provider suggests built-in Ecto types (e.g., \:string\, \:integer\, \:utc\_datetime\) and custom types implementing \Ecto.Type\, with support for snippet insertion for complex types like arrays and maps.

_lib/elixir\sense/providers/plugins/ecto · high confidence

Hover provider now surfaces inferred types for variables

The hover provider in \lib/elixir\_sense/providers/hover/docs.ex\ has been updated to include inferred type information for variables. When hovering over a variable, the provider now attempts to render its best-effort inferred type using \TypePresentation.render\_hint\, displaying this type alongside the variable's name in the hover documentation. This enhances the developer experience by providing immediate type context for local variables without requiring explicit type annotations.

_lib/elixir\sense/providers/hover · high confidence

Introduce core type inference and introspection modules

This change adds a comprehensive set of new core modules to ElixirSense, including \Binding\, \Compiler\, \ElixirTypes\, \Introspection\, and \ExCkReader\. These modules implement a structural type-algebra engine for precise type inference, pattern matching refinement, and variable binding tracking. The update also integrates Elixir's native \Module.Types\ backend (where available) for enhanced expression typing and adds support for reading ExCk signature chunks from BEAM files to improve completion and hover accuracy.

_lib/elixir\sense/core · high confidence

New plugin-based completion providers for Ecto and Phoenix

The completion engine now uses a new plugin architecture to provide context-aware suggestions for Ecto and Phoenix code. A new \ModuleStore\ caches loaded modules and their behaviors to speed up lookups. The Ecto plugin offers completions for schema fields, associations, and query bindings, while the Phoenix plugin suggests controllers and actions within router definitions. These changes replace previous completion logic with a more modular, plugin-driven approach.

_lib/elixir\sense/providers/plugins · high confidence

Behavioural changes

Backports Elixir 1.17+ macro environment APIs for older versions

The library now supports macro expansion and aliasing APIs (such as \expand\_require\, \expand\_alias\, \define\_alias\, \define\_require\, and \define\_import\) on Elixir versions prior to 1.17. Previously, these operations relied on native \Macro.Env\ functions that were only available in Elixir 1.17 and later; the diff introduces a compatibility layer that delegates to the native implementation on Elixir 1.17+ but provides a custom, backported implementation for earlier versions. This ensures consistent behavior for code analysis and expansion across a wider range of Elixir versions, including specific handling for alias expansion and import definition logic that mirrors upstream changes.

_lib/elixir\sense/core/normalized/macro · high confidence

Compiler core refactored into modular components with Elixir 1.20+ support

The monolithic compiler implementation has been split into distinct modules (Bitstring, Clauses, Dispatch, Fn, Macro, Map, Quote, Rewrite, State, Typespec) to improve maintainability and align with upstream Elixir changes. This update adds support for Elixir 1.20, including version-specific behavior for \fn\ and \with\ expressions, and fixes crashes related to missing column information in \end\_of\_expression\ and undefined optional callbacks. It also improves type inference accuracy by preventing alias reference emission during typespec expansion and correctly handling bitstring alignment and size inference.

_lib/elixir\sense/core/compiler · high confidence

Completion engine ported from elixir-ls with state-based bitstring filtering

The completion subsystem has been replaced with a wholesale port from elixir-ls, introducing a new reducer-based architecture (CompletionEngine, GenericReducer, Suggestion) that processes cursor context to generate suggestions. This change restores state-based filtering for bitstring modifier suggestions, ensuring that only valid combinations (e.g., preventing \signed\ after \binary\) are offered to users. The engine also delegates cursor parsing to the host compiler's Code.Fragment to automatically inherit token-level fixes from the running Elixir version, and surfaces inferred types via TypePresentation for both hover and completion contexts.

_lib/elixir\sense/providers/completion · high confidence

Configurable logging and migration to new config syntax

The application now supports environment-specific configuration files (dev, prod, test) and has migrated from the legacy Mix.Config syntax to the modern import Config style. Users can now control logging behavior via the :elixir\_sense application's :logging\_enabled setting, which defaults to true in general configuration but is explicitly set to false in the production environment. Additionally, default settings for :use\_elixir\_types and :exck\_cache\_ttl are established in the base configuration.

config · high confidence

ElixirSense transitions from OTP application to stateless library

The ElixirSense module no longer starts as an OTP application; the \Application\ behavior and supervisor logic have been removed, making the library stateless and easier to integrate without managing a supervision tree. The public API has been refactored to delegate core functions (docs, definition, implementations, suggestions, signature, references) to specific provider modules, and a new \all\_modules/0\ function was added to list available modules. Additionally, the \string\_to\_quoted/5\ function now exposes an error-tolerant parser with configurable options, replacing the previous implementation.

lib · high confidence

Improved Phoenix scope resolution for nested routes

The Phoenix provider now correctly resolves module aliases within nested \scope\ blocks in Phoenix router files. By analyzing the AST path to the cursor, the tool can now accurately determine the full module name (e.g., \ExampleWeb.Router\ -\> \ExampleWeb.MyController\) even when scopes are wrapped or nested, ensuring that code completion and navigation work correctly inside complex routing definitions.

_lib/elixir\sense/providers/plugins/phoenix · high confidence

Improved navigation accuracy at symbol boundaries and for specific Elixir constructs

Navigation providers (definition, references, hover, etc.) now use a new AST-based classifier in \SurroundContext.Toxic\ instead of relying solely on lexical analysis. This change fixes two specific issues: it correctly resolves the module name when the cursor is placed immediately after an alias (e.g., at the end of \Foo\ in \Foo.bar()\), and it correctly identifies symbols when the cursor is positioned one column past the last character of a bare name. Additionally, the classifier provides more precise navigation for operator arity captures (like \&+/2\) and unary operators, while falling back to the standard library for cases where AST metadata is insufficient.

_lib/elixir\_sense/core/surround\context · high confidence

Improved type inference for guards and occurrence typing in control flow

The type inference engine now provides more precise type narrowing in \case\, \with\, and \cond\ expressions through a new occurrence typing system. This system narrows variable types based on matched patterns (e.g., recognizing that a variable is a specific struct or tuple within a branch) and leverages guard expressions to refine types further. Specifically, the new guard handling supports negative facts like \not is\_map\_key/2\ (marking keys as \:not\_set\ to prevent completion suggestions) and recognizes non-empty list shapes via \length(x) \> 0\. These changes result in more accurate type information for variables in conditional branches, leading to better code completion and error detection.

_lib/elixir\_sense/core/type\inference · high confidence

Introduce dedicated info structs for tracking code elements

The state management layer now uses specific data structures to track definitions and variables, replacing or supplementing previous generic storage. New modules include VarInfo for variables (tracking scope, version, and inferred types), AttributeInfo for module attributes, CallInfo for function calls, and ModFunInfo for module and function definitions (including parameters, positions, and type signatures). Additionally, RecordInfo, StructInfo, TypeInfo, and SpecInfo are introduced to capture details for records, structs, type definitions, and specs respectively. The Env struct has been updated to hold lists of these new info types, enabling more precise introspection and context tracking for features like variable type inference and documentation consumption.

_lib/elixir\sense/core/state · high confidence

Introduce normalized code and typespec shims for improved compatibility

Added new modules \ElixirSense.Core.Normalized.Code\ and \ElixirSense.Core.Normalized.Typespec\ to provide a stable, portable API layer over Elixir's internal \Code\ and \Code.Typespec\ modules. The \Code\ shim replicates the behavior of the deprecated \Code.get\_docs/2\, handling various documentation categories (functions, callbacks, types, module docs) and supporting multiple MIME types including Erlang HTML. The \Typespec\ shim wraps \Code.Typespec\ functions like \fetch\_specs\, \fetch\_types\, and \fetch\_callbacks\, ensuring consistent return formats and exposing helper functions for converting types and specs to quoted forms.

_lib/elixir\sense/core/normalized · high confidence

New definition locator implementation with toxic context support

The definition provider now uses a new \Locator\ module that routes navigation requests through the \SurroundContext.Toxic\ seam, enabling more accurate symbol location resolution. This change introduces support for finding definitions of variables, attributes, and functions defined within \\_\using\\_\ macros, including handling \defdelegate\ and \defguard\ constructs. The implementation also passes cursor position to binding resolution and includes fixes for multi-line use site detection, improving the reliability of 'go-to-definition' features for complex macro-generated code.

_lib/elixir\sense/providers/definition · high confidence

New implementation locator with cursor-aware context resolution

The implementation provider now uses a new \Locator\ module that determines symbol implementations by analyzing the surrounding code context at the cursor position. This change introduces a 'Toxic seam' via \SurroundContext.Toxic\ to route navigation locators, allowing the system to distinguish between different binding types (such as variables, attributes, or module functions) and resolve behavior implementations more accurately based on the specific cursor location rather than just the module scope.

_lib/elixir\sense/providers/implementation · high confidence

Project hygiene and documentation overhaul

The repository now includes formalized development standards and tooling: a \.credo.exs\ configuration enforces code style and refactoring checks, a \.dialyzer\_ignore.exs\ file manages static analysis warnings for version-gated code paths, and a \.formatter.exs\ standardizes code formatting. Additionally, the project is now MIT-licensed (replacing previous unspecified terms), includes a Code of Conduct, and features updated documentation with a supported Elixir/Erlang version matrix, installation instructions, and contributor credits.

(repo-wide) · high confidence

Refactored references locator to use SurroundContext.Toxic for context detection

The references provider now routes navigation location detection through the new SurroundContext.Toxic seam, replacing the previous logic for determining the context (variable, attribute, or module/function) at a cursor position. This change introduces a new Locator module that leverages this context to more accurately resolve references, including specific handling for variables via find\_var and improved binding resolution through the updated SurroundContext integration.

_lib/elixir\sense/providers/references · high confidence

Reimplemented completion engine with new reducer-based architecture

The completion subsystem has been replaced with a new reducer-based architecture that provides more accurate and context-aware suggestions. This change introduces dedicated reducers for specific completion types, including callbacks, overridable functions, protocol functions, record fields, parameter options, return values, and type specs. The new \CompleteEngine\ reducer populates context with grouped suggestions (modules, functions, macros, variables, attributes, and fields) which are then consumed by specialized reducers. Users will see improved completion for callbacks (including macrocallbacks), overridable functions, protocol functions, record fields (with support for Elixir 1.18+ record definitions), keyword parameter options, return value suggestions, and type specs. The system now also provides snippet suggestions for module attributes like @doc, @moduledoc, and @typedoc.

_lib/elixir\sense/providers/completion/reducers · high confidence

Test coverage

Added comprehensive test coverage for core type inference and binding logic; Added mock Elixir String module for testing; Added test coverage for completion engine, field type specs, and hover documentation; Added test coverage for metadata builder alias, import, require, and error recovery logic; Added test fixtures for Elixir language server capabilities; Added test fixtures for alias and require handling; Added test fixtures for import behavior; Added tests for Ecto query binding extraction with join associations; Added tests for SurroundContext.Toxic parity with Code.Fragment; Added tests for definition lookup in \_\using\\_ macros; Added tests for guard and occurrence type inference; Added tests for module listing and logging configuration; Added tests for normalized code and typespec documentation retrieval; Added tests for typespec expansion; Refactor test suite configuration and remove obsolete test file.

Dependencies

Major version bump to 2.0.0 with Elixir 1.16 requirement and new dev tooling

The project has been upgraded to version 2.0.0, raising the minimum supported Elixir version from 1.3 to 1.16. This change introduces a new dependency on the \toxic2\ parser (via git), replaces the legacy \mix.exs\ structure with a modern \Mix.Project\ module, and adds development dependencies for \credo\ (1.7), \dialyxir\ (1.0), \ex\_doc\ (0.18), and \stream\_data\ (1.1). The configuration also enables dialyzer flags for stricter type checking and updates the package metadata for Hex publishing.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Score

  • CAI 68 → 68 (-0.2)
  • Rubric changed (rubric-2026.09.15 → rubric-2026.10.1) — scores are not directly comparable.

Lenses

  • Code Health 87 → 87 (-0.0)
  • Architecture 100 → 85 (-14.7)
  • Maturity 51 → 52 (+0.9)
  • Readiness 76 → 78 (+1.7)
  • Security 96 → 97 (+0.8)

Resolved (12)

  • Duplicated block (12 lines × 2) (lib/elixir_sense/providers/definition/locator.ex)
  • Duplicated block (22 lines × 2) (lib/elixir_sense/core/compiler/dispatch.ex)
  • Duplicated block (6 lines × 3) (lib/elixir_sense/core/binding.ex)
  • Duplicated block (6 lines × 3) (lib/elixir_sense/core/binding.ex)
  • Hotspot: lib/elixir_sense/core/binding.ex (lib/elixir_sense/core/binding.ex)
  • Hotspot: lib/elixir_sense/core/compiler.ex (lib/elixir_sense/core/compiler.ex)
  • Hotspot: lib/elixir_sense/core/compiler/state.ex (lib/elixir_sense/core/compiler/state.ex)
  • Hotspot: lib/elixir_sense/core/elixir_types.ex (lib/elixir_sense/core/elixir_types.ex)
  • Hotspot: lib/elixir_sense/core/metadata.ex (lib/elixir_sense/core/metadata.ex)
  • Hotspot: lib/elixir_sense/core/surround_context/toxic.ex (lib/elixir_sense/core/surround_context/toxic.ex)
  • Hotspot: lib/elixir_sense/providers/completion/completion_engine.ex (lib/elixir_sense/providers/completion/completion_engine.ex)
  • Members sharing a duplicated core (4 members, 50+ identical tokens) (lib/elixir_sense/core/binding.ex)

New (9)

  • Duplicated block (10 lines × 2) (lib/elixir_sense/core/state/env.ex)
  • Duplicated block (14 lines × 2) (lib/elixir_sense/providers/definition/locator.ex)
  • Duplicated block (24 lines × 2) (lib/elixir_sense/core/compiler/dispatch.ex)
  • Duplicated block (6 lines × 3) (lib/elixir_sense/core/binding.ex)
  • Duplicated block (6 lines × 3) (lib/elixir_sense/core/binding.ex)
  • Duplicated block (8 lines × 2) (lib/elixir_sense/core/binding.ex)
  • Low cohesion: State (LCOM4 5) (lib/elixir_sense/core/compiler/state.ex)
  • Members sharing a duplicated core (4 members, 50+ identical tokens) (lib/elixir_sense/core/binding.ex)
  • Projects may be oversized for their cohesion

Changes since last survey

  • 1 commits — 0 feature/other, 1 fixes

By area

  • (repo) — 1 commit

Notable commits

  • fix: Merge pull request #343 from elixir-lsp/codex/fix-bitstring-completion-in

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

elixir-lsp/elixir_sense was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 3 October 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit da9f5b9148fa3b7f1bc0fda1b44d5e9efba1cac7 — the exact code this score is about.
  • Scored under rubric-2026.10.1 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-24c657e50118.