Назад к обновлениям
New releaseJul 24, 2026

trailmark v0.5.0

Создавайте и запрашивайте графовое представление исходного кода.

Поделиться

Trailmark

CI Mutation Testing

Разбирает исходный код в графы функций, классов, вызовов и семантических аннотаций, пригодные для запросов, для целей анализа безопасности.

Trailmark использует tree-sitter для языконезависимого разбора AST и rustworkx для высокопроизводительного обхода графа. Долгосрочная цель — объединить этот граф с мутационным тестированием и фаззингом с покрытием для выявления разрывов между предположениями и тестовым покрытием, достижимых из пользовательского ввода.

Как это работает

Trailmark работает в три фазы: разбор, индексация и запрос.

flowchart TD
    A["Source Files"] --> B["tree-sitter Parser"]
    B --> C["CodeGraph (nodes + edges)"]
    C --> D["rustworkx GraphStore"]
    D --> E["QueryEngine"]
    E --> F["JSON / Summary / Hotspots"]

    classDef src fill:#007bff26,stroke:#007bff,color:#007bff
    classDef parse fill:#28a74526,stroke:#28a745,color:#28a745
    classDef data fill:#6f42c126,stroke:#6f42c1,color:#6f42c1
    classDef query fill:#ffc10726,stroke:#e6a817,color:#e6a817

    class A src
    class B parse
    class C,D data
    class E,F query

1. Разбор

Парсер для конкретного языка обходит каталог, разбирает каждый файл в AST tree-sitter и извлекает:

  • Узлы — функции, методы, классы, структуры, интерфейсы, трейты, перечисления, модули, пространства имён
  • Рёбра — вызовы, наследование, реализация, вложенность, импорты
  • Метаданные — аннотации типов, цикломатическая сложность, ветвления, docstring'и, типы исключений

Поддерживаемые языки

ЯзыкРасширенияКлючевые конструкции
Python.pyфункции, классы, методы
JavaScript.js, .jsx, .mjs, .cjsфункции, классы, стрелочные функции
TypeScript.ts, .tsxфункции, классы, интерфейсы, перечисления
PHP.phpфункции, классы, интерфейсы, трейты
Ruby.rbметоды, классы, модули
C.c, .hфункции, структуры, перечисления
C++.cpp, .hpp, .cc, .hh, .cxx, .hxxфункции, классы, структуры, пространства имён
C#.csметоды, классы, интерфейсы, структуры, перечисления, пространства имён
Java.javaметоды, классы, интерфейсы, перечисления
Go.goфункции, методы, структуры, интерфейсы
Rust.rsфункции, структуры, трейты, перечисления, блоки impl, блоки verus!
Solidity.solконтракты, интерфейсы, библиотеки, функции, модификаторы, структуры, перечисления
Cairo.cairoфункции, трейты, структуры, перечисления, блоки impl, контракты StarkNet
Circom.circomшаблоны, функции, сигналы, компоненты
Haskell.hsфункции, типы данных, классы типов, экземпляры
Erlang.erlфункции, записи, поведения, модули
Miden Assembly.masmпроцедуры, точки входа, константы, вызовы
Swift.swiftфункции, классы, структуры, перечисления, протоколы, расширения
Objective-C.m, .mm, .hфункции C, классы, методы (именование на основе селекторов)
Kotlin.kt, .ktsфункции, классы, интерфейсы, классы данных, объекты, методы
Dart.dartфункции, классы, абстрактные классы, методы, конструкторы
Move.moveмодули, функции, импорты, прямые вызовы
Tact.tactконтракты, структуры, получатели, функции
Func.fc, .funcфункции, включения, прямые вызовы
Sway.swинтерфейсы ABI, структуры, методы impl, функции
Rego.regoпакеты, импорты, правила политик, вызовы правил
Proto.protoсервисы, RPC, сообщения, поля, перечисления
Thrift.thriftсервисы, функции, структуры, поля, перечисления
GraphQL.graphql, .gqlобъектные типы, корневые операции, поля, перечисления
SQL.sqlсхемы, таблицы, представления, функции, процедуры

Rust-парсер извлекает обычные функции, функции spec и proof с телами из блоков verus! { ... }. Грамматика Verus в настоящее время поддерживает только блоки, ограниченные фигурными скобками; verus!(...) и verus![...] пропускаются с предупреждением. Встроенные модули сохраняют квалифицированные идентификаторы (например, file.inner:function), а методы сохраняют своего владельца impl или trait. Каждый блок разбирается независимо; синтаксические ошибки порождают предупреждение с указанием файла и расположения блока. Квалифицированные вызовы, такие как vstd::prelude::verus!, также поддерживаются. Локальные вспомогательные функции сохраняют в своих идентификаторах объемлющую функцию (например, file:outer.inner). Вызовы этих вспомогательных функций и относительные импорты, такие как use super::*, разрешаются в объявления, присутствующие в файле. Повторяющиеся локальные имена в разных блоках получают суффикс байтового смещения, чтобы сохранить их узлы различимыми, а вызовы учитывают область видимости блока. Локальные структуры, перечисления, трейты и встроенные модули также сохраняют объемлющую функцию: например, file:outer.Guard.drop и file:outer.local.helper. Их тела имеют отдельные вызовы и сложность. Явные вызовы известных локальных типов и модулей разрешаются в пределах файла. Вызовы без квалификации ищут в областях видимости функций и модулей; ассоциированные элементы используют пути вида Type::method. Вызовы через точку разрешаются только когда получатель именует известную структуру или перечисление. Другие получатели-значения, включая self.method(), остаются неразрешенными. Неявные вызовы деструкторов и вывод типа получателя не моделируются. Эти правила применяются как к обычному Rust, так и к блокам Verus. Редактирование кода перед объявлением с суффиксом смещения изменяет его ID, поэтому trailmark diff может сообщить об этом объявлении как об удаленном и добавленном.

Trailmark не раскрывает произвольные макросы. Литеральные вызовы Verus внутри непрозрачных макросов или тел функций пропускаются с предупреждением. Невызванные определения macro_rules! не раскрываются. Сигнатуры функций без тел и вызовы в клаузах requires/ensures не извлекаются.

flowchart TD
    subgraph "Per-File Parsing"
        F["Source file"] --> TS["tree-sitter AST"]
        TS --> EX["Extract nodes"]
        TS --> EC["Extract call edges"]
        TS --> EB["Count branches"]
        TS --> ET["Resolve types"]
    end

    EX --> CG["CodeGraph"]
    EC --> CG
    EB --> CG
    ET --> CG

    classDef src fill:#007bff26,stroke:#007bff,color:#007bff
    classDef parse fill:#28a74526,stroke:#28a745,color:#28a745
    classDef extract fill:#ffc10726,stroke:#e6a817,color:#e6a817
    classDef data fill:#6f42c126,stroke:#6f42c1,color:#6f42c1

    class F src
    class TS parse
    class EX,EC,EB,ET extract
    class CG data

Идентификаторы узлов следуют схеме module:function, module:Class или module:Class.method для однозначного поиска. При разборе каталога разрешаются вызовы между файлами без указания модуля, если существует единственное определение; неоднозначные межфайловые вызовы остаются на исходной приблизительной цели и помечаются как uncertain. Достоверность рёбер помечается как certain (прямые вызовы, self.method()), inferred (доступ к атрибутам объектов, не являющихся self) или uncertain (динамическая диспетчеризация или неоднозначное разрешение).

2. Индекс

GraphStore загружает CodeGraph в rustworkx PyDiGraph и строит двунаправленные сопоставления ID/индексов для быстрого обхода.

3. Запросы

QueryEngine предоставляет высокоуровневый API поверх индексированного графа:

Категории