Skip to content

Закомментированное объявление индексируется как метод, а настоящий экспортный метод теряется (70 из 12290 модулей) #23

Description

@zeegin

Кратко

_parse_procedures_from_lines ищет объявления методов регексом .search() по строкам файла, не отбрасывая комментарии. Поэтому // Процедура Имя(...) в шапке-примере попадает в индекс как настоящий метод — а настоящий метод, чьё тело этот призрак «съедает» по end_line, из индекса исчезает совсем.

На реальной вендорской конфигурации это 70 модулей из 12 290, включая ядро БСП: ОбщегоНазначенияКлиент, СтандартныеПодсистемыКлиент, СтандартныеПодсистемыСервер, УправлениеДоступом, УправлениеПечатью, ДлительныеОперации, Пользователи, ВариантыОтчетов, РаботаСФайламиКлиент, ОтчетыКлиентСервер.

Проверено на 1.29.1. src/rlm_tools_bsl/bsl_index.py побайтово идентичен в v1.29.1 и v1.30.1, так что в 1.30.1 поведение то же (готового бинарника 1.30.1 под рукой не было, поэтому прогон — на 1.29.1).

Минимальное воспроизведение

src/CommonModules/Демо/Ext/Module.bsl (UTF-8 с BOM):

#Область ПрограммныйИнтерфейс

// Пример вызова:
//
// Процедура ОпределитьНастройки(Форма, Ключ) Экспорт
// 	// Код процедуры.
// КонецПроцедуры
//
Процедура НастроитьВарианты(Настройки) Экспорт

	Возврат;

КонецПроцедуры

Процедура ВтораяПроцедура() Экспорт

	Возврат;

КонецПроцедуры

#КонецОбласти
RLM_INDEX_DIR=./idx rlm-bsl-index index build ./src
sqlite3 ./idx/*/bsl_index.db \
  "select name, type, is_export, line, end_line, params from methods order by line;"

Фактический результат:

name                 type       is_export  line  end_line  params
-------------------  ---------  ---------  ----  --------  -----------
ОпределитьНастройки  Процедура  1          5     13        Форма, Ключ
ВтораяПроцедура      Процедура  1          15    19

Ожидалось:

НастроитьВарианты    Процедура  1          9     13        Настройки
ВтораяПроцедура      Процедура  1          15    19

То есть:

  • ОпределитьНастройки не существует в модуле, но лежит в индексе как экспортный метод, с параметрами, вытащенными из текста комментария;
  • end_line=13 — это КонецПроцедуры настоящей процедуры, то есть призрак поглощает её тело;
  • НастроитьВарианты — настоящий экспортный метод — в индексе отсутствует. Никакой поиск по имени его не найдёт.

Что именно триггерит

Семь модулей, по одному на вариант, один прогон index build:

Модуль Содержимое Что в индексе
V1Простой // Процедура Призрак() Экспорт + // КонецПроцедуры Призрак, is_export=1, 1–4
V2БезЗакрытия только // Процедура Призрак(А) Призрак, 1–3
V3ВСередине // См. также Процедура Призрак() из другого модуля Призрак, 1–3
V4Отступ //\t\t\tПроцедура Призрак() Призрак, 1–3
V5Функция // Функция Призрак() Призрак, тип Функция, 1–5
V6Строка Т = "Процедура Призрак()"; внутри тела Настоящаяверно
V7English // Procedure Ghost() Export Ghost, is_export=1, 1–4

Во всех случаях кроме V6 настоящий метод из индекса исчезает: 7 модулей → 7 методов, и в шести из них единственный метод — призрак.

Из этого видно три вещи:

  1. Комментарии не отбрасываются. Строковые литералы отбрасываются (V6 отработал верно) — за это отвечает _PROC_STRING_LITERAL_RE (bsl_knowledge.py:164). Для // аналога нет.
  2. Регекс не заякорен. V3 — объявление в середине прозаической строки, и оно всё равно захватывается. Это .search(), а не .match().
  3. Настоящий метод теряется, а не просто получает неверные координаты. Это следствие того, как продвигается курсор (ниже).

Место в коде

src/rlm_tools_bsl/bsl_knowledge.py:15:

"procedure_def": r"(Процедура|Функция|Procedure|Function)\s+(\w+)\s*\(([^)]*)\)\s*(Экспорт|Export)?",

src/rlm_tools_bsl/bsl_index.py:2397 — незаякоренный поиск по строке, без учёта комментариев:

m = _PROC_DEF_RE.search(merged)

src/rlm_tools_bsl/bsl_index.py:2440-2445 — курсор перескакивает за end_line призрака, поэтому настоящее объявление вообще не рассматривается:

# Advance m_idx past the КонецПроцедуры line.
new_m = m_idx + 1
while new_m < total_merged and line_map[new_m] <= end_line:
    new_m += 1
m_idx = new_m

Показательно, что рядом в этом же файле уже есть заякоренный вариант того же паттерна — _PROC_DEF_PREFIX_RE (bsl_knowledge.py:160) с ^\s*, используемый для склейки многострочных сигнатур. И в самом bsl_index.py комментарии в других местах отбрасываются штатно: строки 1586, 4875, 4924 (stripped.startswith("//")). То есть обе нужные конвенции в кодовой базе уже приняты, просто не применены на этом пути.

Предлагаемое исправление

Минимально: перед поиском объявления убирать хвост от // (с учётом того, что // внутри строкового литерала не начинает комментарий — маска _PROC_STRING_LITERAL_RE для этого уже есть), и заякорить паттерн на начало логической строки:

"procedure_def": r"^\s*(Процедура|Функция|Procedure|Function)\s+(\w+)\s*\(([^)]*)\)\s*(Экспорт|Export)?",

Заякоривание само по себе закрывает V3, но не V1, V2, V4, V5, V7 — там объявление стоит в начале строки, просто за //. Поэтому нужны оба изменения.

Стоит учесть, что это меняет содержимое индекса, то есть требует bump версии билдера, чтобы существующие базы перестроились.

Почему это ощутимо

Индекс — источник для find_definition, search, get_module_outline и find_callers_context. Потеря настоящего экспортного метода означает, что:

  • find_definition("НастроитьВарианты") не находит существующую процедуру;
  • get_module_outline отдаёт структуру, которой в файле нет, и при этом молчит;
  • призрак предлагается как экспортное API.

В БСП шапка с примером вызова — стандартный стиль оформления переопределяемых модулей, поэтому попадание неслучайное и концентрируется именно в тех модулях, которые чаще всего разбирают.

Отдельно отмечу: сравнение шло с bsl-analyzer v0.2.62 (полноценный парсер BSL) на том же корпусе — он на всех 12 290 модулях дал 0 диагностик и во всех 70 расхождениях прав именно он. Расхождения были только по методам; области (regions) совпали на всех 12 290 модулях, включая имена с хвостовым //-комментарием и области внутри тел методов.

Окружение

  • rlm-tools-bsl / rlm-bsl-index 1.29.1, darwin-arm64
  • корпус для статистики: выгрузка Designer, платформа 8.3.27.2074, формат 2.20, 12 290 файлов *.bsl
  • сверка: bsl-analyzer v0.2.62 (rev 9a6cb15d)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions