LSP-сервер CodeGraph

Реализация протокола Language Server Protocol (LSP) на основе CPG, обеспечивающая интеллектуальный анализ кода в реальном времени из базы данных Code Property Graph CodeGraph.

Содержание

Обзор

LSP-сервер CodeGraph соединяет любой LSP-совместимый редактор с CPG (Code Property Graph), которым во время выполнения владеет GoCPG. Сам LSP-сервер работает как gRPC-клиент: он не открывает DuckDB напрямую и создаёт только read-only нагрузку через GoCPG. Сервер предоставляет:

  • Диагностика безопасности – результаты 190+ правил шаблонов (привязка к CWE)
  • Обнаружение мёртвого кода – методы без вызывающих (fan_in=0)
  • Предупреждения о сложности – цикломатическая сложность выше настраиваемого порогового значения
  • Нарушения шаблонов – структурные проблемы качества кода
  • Метрики метода при наведении – сложность, fan-in/fan-out, вызывающие, результаты безопасности
  • Индикаторы CodeLens – количество вызывающих/вызываемых методов и информация о потоках данных (taint) над каждым методом
  • Автоисправления – быстрые исправления для 22 правил (SQL-инъекции, переполнение буфера, инъекция команд оболочки)

Поддерживает 11 языков: C, C++, C#, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, TypeScript.

Установка

LSP-сервер входит в пакет CodeGraph:

pip install -e .

Команда регистрирует точку входа CLI codegraph-lsp. Также можно запустить напрямую:

python -m codegraph_lsp --db <path-to-duckdb>

--db задаёт идентификатор целевой CPG-базы, которой владеет GoCPG. Сам процесс LSP не владеет файлом DuckDB и не открывает его напрямую.

Зависимости

  • pygls>=2.0.0 – фреймворк Python LSP
  • lsprotocol – определения типов LSP
  • Запущенный GoCPG gRPC server с доступом к целевой CPG-базе

Быстрый старт

  1. Соберите CPG для вашего проекта (если ещё не собран):
gocpg parse --input=. --output=project.duckdb --lang=python
  1. Запустите GoCPG, чтобы CPG была доступна по gRPC:
gocpg serve --data-dir .
  1. Запустите LSP-сервер:
python -m codegraph_lsp --db project.duckdb
  1. Настройте редактор для работы с сервером (см. разделы для конкретных редакторов ниже).

Диагностика

Сервер публикует диагностику при открытии и сохранении файла.

Результаты безопасности (severity: Error)

Результаты из cpg_pattern_results с category = 'security'. Каждая диагностика включает: - Идентификатор правила, привязанный к CWE, в качестве кода диагностики - Точную строку и столбец из анализа CPG - Описание уязвимости

Пример в редакторе:

Error [CWE-89]: SQL injection — user input concatenated into query (line 42)

Мёртвые методы (severity: Hint, tag: Unnecessary)

Методы, где fan_in = 0 AND is_entry_point = false AND is_external = false AND is_test = false. Отображаются с зачёркиванием в редакторах, поддерживающих тег Unnecessary.

Пример:

Hint [dead-method]: Dead method: 'unused_helper' has no callers (fan_in=0) (line 25)

Предупреждения о сложности

Методы, у которых cyclomatic_complexity превышает настроенное пороговое значение:

Сложность Уровень серьёзности
пороговое значение–19 Information
20–49 Warning
≥50 Error

Пример:

Warning [high-complexity]: Cyclomatic complexity of 'process_data' is 25 (threshold: 10) (line 100)

Нарушения шаблонов

Результаты из cpg_pattern_results, не относящиеся к безопасности. Уровень серьёзности определяется полем severity правила шаблона.

Наведение

При наведении на метод отображается таблица в формате Markdown:

Метрика Описание
Cyclomatic complexity Оценка сложности метода
Fan-in (callers) Количество уникальных вызывающих методов
Fan-out (callees) Количество уникальных вызываемых методов
Callers Вызывающие из edges_call
LOC Количество строк кода
Parameters Количество параметров
Security findings Количество результатов безопасности в файле
Flags точка входа, внешний, тест, мёртвый код

CodeLens

Каждый метод получает индикатор CodeLens:

3 callers | 5 callees | taint: read_inputexecute_query
  • Вызывающие/вызываемые из fan_in/fan_out в nodes_method
  • Поток данных (taint) отображается, когда метод участвует в пути потока данных (через edges_reaching_def)

Автоисправление (CodeAction)

Для нарушений шаблонов с доступными правилами автоисправления сервер предоставляет действия Quick Fix. 22 правила автоисправления включают:

Правило Язык Описание
autofix-py-format-sql Python Замена %-форматирования SQL на параметризованный запрос
autofix-py-concat-sql Python Замена конкатенации строк SQL на параметризованный запрос
autofix-py-fstring-sql Python Замена f-строки SQL на параметризованный запрос
autofix-py-ctypes-string-at Python Замена ctypes.string_at на безопасную альтернативу
autofix-py-subprocess-shell Python Замена shell=True на прямую команду
autofix-go-concat-sql Go Замена конкатенации строк SQL на параметризованный запрос
autofix-go-sprintf-sql Go Замена fmt.Sprintf SQL на параметризованный запрос
autofix-go-exec-shell Go Замена выполнения через оболочку на прямую команду
autofix-go-cgo-strcpy Go Замена CGO strcpy на безопасное копирование буфера
autofix-c-strcpy-to-strncpy C Замена strcpy на strncpy
autofix-c-sprintf-to-snprintf C Замена sprintf на snprintf
autofix-c-null-assert C Добавление проверки NULL после вызова функции
Плюс правила для захардкоженных строк для 10 языков

Автоисправление применяется, когда match_data в cpg_pattern_results содержит поле fix с кодом замены.

Подключение OpenCode

Добавьте LSP-сервер в opencode.json (пример конфигурации):

{
  "lsp": {
    "codegraph": {
      "command": ["python", "-m", "codegraph_lsp", "--db", "project.duckdb"],
      "languages": ["python", "go", "javascript", "typescript", "java", "c", "cpp"]
    }
  }
}

OpenCode автоматически: - Запускает LSP-сервер при открытии файлов на поддерживаемых языках - Показывает диагностику в строке и на панели проблем - Включает диагностику в контекст LLM через experimental.chat.system.transform - Предлагает быстрые исправления для шаблонов с поддержкой автоисправления

Пул подключений

LSP-сервер использует read-only пул запросов поверх GoCPG:

  • Максимум логических подключений: 3 (настраиваемо)
  • Только gRPC: процесс LSP не открывает DuckDB напрямую
  • Только чтение: diagnostics, hover, CodeLens и code actions идут через query RPC GoCPG
  • Потокобезопасность: используется threading.Lock
  • Отслеживание смены снимка: пул проверяет время модификации файла базы (mtime) и переподключает простаивающие соединения после обновления снимка CPG

Владение DuckDB остаётся внутри GoCPG. Когда GoCPG обновляет или пересоздаёт CPG, LSP-клиент получает новый снимок на следующих RPC-запросах.

Конфигурация

Параметры CLI

Параметр По умолчанию Описание
--db (обязательный) Путь к целевой CPG-базе, используемый GoCPG
--complexity-threshold 10 Пороговое значение предупреждения о цикломатической сложности
--transport stdio Транспорт: stdio или tcp
--host 127.0.0.1 TCP-хост (только для --transport tcp)
--port 2087 TCP-порт (только для --transport tcp)
--log-level info Уровень логирования: debug, info, warning, error

Режимы транспорта

stdio (по умолчанию): редактор запускает сервер как подпроцесс и обменивается данными через stdin/stdout. Оптимально для локального использования.

python -m codegraph_lsp --db project.duckdb

tcp: сервер слушает TCP-порт. Подходит для удалённых LSP-подключений или общих экземпляров.

python -m codegraph_lsp --db project.duckdb --transport tcp --port 2087

Устранение неполадок

Диагностика не отображается

  • Убедитесь, что GoCPG gRPC доступен и обслуживает нужную базу.
  • Убедитесь, что целевой DuckDB-файл существует и содержит CPG-данные, например через GoCPG lifecycle/query endpoints или gocpg stats --db project.duckdb.
  • Убедитесь, что пути к файлам в базе данных совпадают с путями в рабочем пространстве (прямые слэши, относительные пути).

Ошибка «Connection Pool Exhausted»

Означает, что активны 3 одновременных read-запроса. Это может произойти, если: - GoCPG выполняет медленные запросы к очень большой CPG - Одновременно были открыты несколько файлов

Решение: закройте часть файлов или увеличьте размер пула (требует изменения кода).

Устаревшая диагностика после обновления CPG

Если диагностика кажется устаревшей: - Закройте и откройте файл заново - Убедитесь, что GoCPG завершил update/reparse и сообщает read_available=true - Перепроверьте lifecycle status через CodeGraph /status или dogfood status

Сервер не запускается

  • Убедитесь, что pygls установлен: python -c "import pygls; print(pygls.__version__)"
  • Убедитесь, что GoCPG gRPC server запущен и доступен для процесса LSP
  • Проверьте сообщения об ошибках в stderr

Проблемы с путями в Windows

Сервер нормализует пути из URI файлов (file:///C:/...C:/...) и использует прямые слэши внутри. Если в базе данных CPG пути содержат обратные слэши, диагностика может не совпадать. Пересоберите CPG для обеспечения единообразия путей.