Кратко
_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 методов, и в шести из них единственный метод — призрак.
Из этого видно три вещи:
- Комментарии не отбрасываются. Строковые литералы отбрасываются (
V6 отработал верно) — за это отвечает _PROC_STRING_LITERAL_RE (bsl_knowledge.py:164). Для // аналога нет.
- Регекс не заякорен.
V3 — объявление в середине прозаической строки, и оно всё равно захватывается. Это .search(), а не .match().
- Настоящий метод теряется, а не просто получает неверные координаты. Это следствие того, как продвигается курсор (ниже).
Место в коде
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)
Кратко
_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):Фактический результат:
Ожидалось:
То есть:
ОпределитьНастройкине существует в модуле, но лежит в индексе как экспортный метод, с параметрами, вытащенными из текста комментария;end_line=13— этоКонецПроцедурынастоящей процедуры, то есть призрак поглощает её тело;НастроитьВарианты— настоящий экспортный метод — в индексе отсутствует. Никакой поиск по имени его не найдёт.Что именно триггерит
Семь модулей, по одному на вариант, один прогон
index build:V1Простой// Процедура Призрак() Экспорт+// КонецПроцедурыПризрак,is_export=1, 1–4V2БезЗакрытия// Процедура Призрак(А)Призрак, 1–3V3ВСередине// См. также Процедура Призрак() из другого модуляПризрак, 1–3V4Отступ//\t\t\tПроцедура Призрак()Призрак, 1–3V5Функция// Функция Призрак()Призрак, типФункция, 1–5V6СтрокаТ = "Процедура Призрак()";внутри телаНастоящая— верноV7English// Procedure Ghost() ExportGhost,is_export=1, 1–4Во всех случаях кроме
V6настоящий метод из индекса исчезает: 7 модулей → 7 методов, и в шести из них единственный метод — призрак.Из этого видно три вещи:
V6отработал верно) — за это отвечает_PROC_STRING_LITERAL_RE(bsl_knowledge.py:164). Для//аналога нет.V3— объявление в середине прозаической строки, и оно всё равно захватывается. Это.search(), а не.match().Место в коде
src/rlm_tools_bsl/bsl_knowledge.py:15:src/rlm_tools_bsl/bsl_index.py:2397— незаякоренный поиск по строке, без учёта комментариев:src/rlm_tools_bsl/bsl_index.py:2440-2445— курсор перескакивает заend_lineпризрака, поэтому настоящее объявление вообще не рассматривается:Показательно, что рядом в этом же файле уже есть заякоренный вариант того же паттерна —
_PROC_DEF_PREFIX_RE(bsl_knowledge.py:160) с^\s*, используемый для склейки многострочных сигнатур. И в самомbsl_index.pyкомментарии в других местах отбрасываются штатно: строки 1586, 4875, 4924 (stripped.startswith("//")). То есть обе нужные конвенции в кодовой базе уже приняты, просто не применены на этом пути.Предлагаемое исправление
Минимально: перед поиском объявления убирать хвост от
//(с учётом того, что//внутри строкового литерала не начинает комментарий — маска_PROC_STRING_LITERAL_REдля этого уже есть), и заякорить паттерн на начало логической строки:Заякоривание само по себе закрывает
V3, но неV1,V2,V4,V5,V7— там объявление стоит в начале строки, просто за//. Поэтому нужны оба изменения.Стоит учесть, что это меняет содержимое индекса, то есть требует bump версии билдера, чтобы существующие базы перестроились.
Почему это ощутимо
Индекс — источник для
find_definition,search,get_module_outlineиfind_callers_context. Потеря настоящего экспортного метода означает, что:find_definition("НастроитьВарианты")не находит существующую процедуру;get_module_outlineотдаёт структуру, которой в файле нет, и при этом молчит;В БСП шапка с примером вызова — стандартный стиль оформления переопределяемых модулей, поэтому попадание неслучайное и концентрируется именно в тех модулях, которые чаще всего разбирают.
Отдельно отмечу: сравнение шло с
bsl-analyzerv0.2.62 (полноценный парсер BSL) на том же корпусе — он на всех 12 290 модулях дал 0 диагностик и во всех 70 расхождениях прав именно он. Расхождения были только по методам; области (regions) совпали на всех 12 290 модулях, включая имена с хвостовым//-комментарием и области внутри тел методов.Окружение
rlm-tools-bsl/rlm-bsl-index1.29.1, darwin-arm64*.bslbsl-analyzerv0.2.62 (rev9a6cb15d)