Как программно получить список всех процедур и функций из общего модуля в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Основной подход: получение и парсинг текста модуля

Единственный надежный способ получить список процедур и функций — это программно извлечь исходный текст общего модуля и затем проанализировать (распарсить) его для поиска ключевых слов Процедура и Функция. В современных реалиях для интеграции с внешними инструментами ИИ можно даже использовать MCP-сервер для доступа к текстам модулей 1С. Проанализируем этот метод подробно.

Суть метода заключается в следующих действиях:

  1. Получаем объект метаданных нужного общего модуля.
  2. С помощью метода ПолучитьТекст() извлекаем весь его исходный код в виде одной большой строки.
  3. Последовательно обрабатываем эту строку, находя объявления процедур и функций, извлекая их имена, параметры и флаг "Экспорт".

Давайте посмотрим, как это выглядит на практике, от простого примера к более комплексному и функциональному решению, которое позволит выполнить анализ и автоматическое редактирование модулей.

Решение 1: Простой перебор строк модуля

Самый простой вариант — это разбить текст модуля на строки и в цикле проверять каждую на наличие ключевых слов. Этот способ подойдет для простых случаев, но он не очень надежен, так как не учитывает комментарии или сложное форматирование кода.

Посмотрим на пример такого кода:


Процедура ПолучитьСписокФункций(ИмяМодуля)

    // Получаем текст модуля из метаданных
    ТекстМодуля = Метаданные.ОбщиеМодули[ИмяМодуля].ПолучитьТекст();
    
    // Создаем массив для хранения строк текста
    МассивСтрок = Новый Массив;
    
    // Заменяем символ переноса строки на специальный символ, чтобы потом разделить
    ТекстМодуля = СтрЗаменить(ТекстМодуля, Символы.ПС, "|");
    КоличествоСтрок = СтрЧислоВвхождений(ТекстМодуля, "|");
    
    // Разбиваем текст на строки и помещаем в массив
    Для Счетчик = 1 По КоличествоСтрок Цикл
        Стр = СтрПолучитьСтроку(ТекстМодуля, Счетчик);
        МассивСтрок.Добавить(Стр);
    КонецЦикла;
    
    // Перебираем строки и ищем объявления функций
    Для Каждого Стр Из МассивСтрок Цикл
        // Ищем ключевое слово "Функция" в начале строки (с учетом возможных пробелов)
        Если СтрНайти(СокрЛ(Стр), "Функция") = 1 Тогда
            // Проверяем, является ли функция экспортной
            Если СтрНайти(Стр, "Экспорт") > 0 Тогда
                Сообщить("Найдена экспортная функция: " + Стр);
            Иначе
                Сообщить("Найдена внутренняя функция: " + Стр);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;

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

Недостатки этого подхода:

Решение 2: Использование регулярных выражений

Более современным и гибким способом парсинга текста является использование регулярных выражений. Они позволяют описать шаблон искомой строки (в нашем случае — объявления процедуры или функции) и извлечь из нее нужные части (имя, параметры). Этот метод сложнее в освоении, но дает гораздо более точный результат.

Например, можно составить регулярное выражение, которое будет находить строки, начинающиеся со слов Процедура или Функция, и извлекать следующее за ними слово до открывающей скобки.

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

Решение 3: Комплексная функция для парсинга модуля

Рассмотрим наиболее полное и надежное решение, предложенное на форуме. Это готовая функция, которая учитывает большинство нюансов: комментарии, многострочные объявления, наличие или отсутствие параметров и ключевого слова Экспорт.

Эта функция возвращает таблицу значений с колонками: "Имя", "ЭтоФункция", "Экспорт", "Параметры" и "Описание" (если оно есть в виде комментария перед объявлением).

Проанализируем ее код и логику работы.


// Функция возвращает ТаблицуЗначений с процедурами и функциями модуля.
//
// Параметры:
//  ИмяОбщегоМодуля  - Строка - имя общего модуля, как оно задано в конфигураторе.
//  СодержитОписание - Булево - если Истина, в результат будет добавлена колонка "Описание",
//                              содержащая комментарий перед процедурой/функцией.
//
Функция ПолучитьПроцедурыИФункцииМодуля(ИмяОбщегоМодуля, СодержитОписание = Ложь) Экспорт

    ТекстМодуля = ОбщиеМодули[ИмяОбщегоМодуля].ПолучитьТекст();
    
    ТаблицаРезультат = Новый ТаблицаЗначений;
    ТаблицаРезультат.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
    ТаблицаРезультат.Колонки.Добавить("ЭтоФункция", Новый ОписаниеТипов("Булево"));
    ТаблицаРезультат.Колонки.Добавить("Экспорт", Новый ОписаниеТипов("Булево"));
    ТаблицаРезультат.Колонки.Добавить("Параметры", Новый ОписаниеТипов("Строка"));
    Если СодержитОписание Тогда
        ТаблицаРезультат.Колонки.Добавить("Описание", Новый ОписаниеТипов("Строка"));
    КонецЕсли;

    ТекстМодуляБезКомментариев = "";
    Описание = "";

    // Шаг 1: Очистка от комментариев и сбор описаний
    Для Счетчик = 1 По СтрЧислоСтрок(ТекстМодуля) Цикл
        Стр = СтрПолучитьСтроку(ТекстМодуля, Счетчик);
        ПозКомментария = СтрНайти(Стр, "//");
        
        Если ПозКомментария = 1 И СодержитОписание Тогда
            // Если строка начинается с комментария, считаем ее частью описания
            Описание = Описание + Сред(Стр, 3) + Символы.ПС;
        ИначеЕсли ПозКомментария > 0 Тогда
            // Если комментарий в середине строки, отрезаем его
            ТекстМодуляБезКомментариев = ТекстМодуляБезКомментариев + Лев(Стр, ПозКомментария - 1) + Символы.ПС;
            Описание = ""; // Сбрасываем описание
        Иначе
            ТекстМодуляБезКомментариев = ТекстМодуляБезКомментариев + Стр + Символы.ПС;
            Если Не ПустаяСтрока(СокрЛП(Стр)) Тогда
                Описание = ""; // Сбрасываем описание, если это не пустая строка
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    ТекстМодуля = ТекстМодуляБезКомментариев;

    // Шаг 2: Поиск процедур и функций в очищенном тексте
    Поз = 1;
    Пока Поз > 0 Цикл
        // Ищем вхождение слов "Процедура" или "Функция"
        ПозПроцедура = СтрНайти(ТекстМодуля, "Процедура",, Поз);
        ПозФункция = СтрНайти(ТекстМодуля, "Функция",, Поз);

        Если ПозПроцедура = 0 И ПозФункция = 0 Тогда
            // Больше не найдено, выходим из цикла
            Прервать;
        КонецЕсли;
        
        ЭтоФункция = Ложь;
        Если ПозПроцедура = 0 Или (ПозФункция > 0 И ПозФункция < ПозПроцедура) Тогда
            Поз = ПозФункция;
            ЭтоФункция = Истина;
        Иначе
            Поз = ПозПроцедура;
        КонецЕсли;
        
        // Получаем строку с объявлением
        КонецСтроки = СтрНайти(ТекстМодуля, Символы.ПС, , Поз);
        СтрокаОбъявления = Сред(ТекстМодуля, Поз, КонецСтроки - Поз);
        
        ПозИмени = СтрНайти(СтрокаОбъявления, ?(ЭтоФункция, "Функция", "Процедура")) + ?(ЭтоФункция, 7, 9);
        ПозОткрСкобки = СтрНайти(СтрокаОбъявления, "(");
        
        ИмяМетода = СокрЛП(Сред(СтрокаОбъявления, ПозИмени, ПозОткрСкобки - ПозИмени));
        
        // Шаг 3: Извлечение деталей (экспорт, параметры)
        НоваяСтрока = ТаблицаРезультат.Добавить();
        НоваяСтрока.Имя = ИмяМетода;
        НоваяСтрока.ЭтоФункция = ЭтоФункция;
        НоваяСтрока.Экспорт = (СтрНайти(Врег(СтрокаОбъявления), "ЭКСПОРТ") > 0);
        
        ПозЗакрСкобки = СтрНайти(СтрокаОбъявления, ")");
        Если ПозЗакрСкобки > ПозОткрСкобки Тогда
            НоваяСтрока.Параметры = Сред(СтрокаОбъявления, ПозОткрСкобки + 1, ПозЗакрСкобки - ПозОткрСкобки - 1);
        КонецЕсли;
        
        Если СодержитОписание Тогда
            НоваяСтрока.Описание = Описание;
        КонецЕсли;
        
        Поз = КонецСтроки + 1;
    КонецЦикла;
    
    Возврат ТаблицаРезультат;

КонецФункции

Как работает эта функция:

  1. Подготовка: Функция принимает имя общего модуля. Сначала она получает полный текст модуля через объект ОбщиеМодули. Создается пустая таблица значений для результата.
  2. Очистка от комментариев: В первом цикле код проходит по всем строкам текста. Он удаляет строчные комментарии и собирает многострочные комментарии, которые предшествуют объявлению процедуры.
  3. Основной цикл поиска: Во втором цикле функция ищет поочередно ближайшее вхождение слов Процедура или Функция.
  4. Извлечение имени: Найдя объявление, код "вырезает" из него имя метода.
  5. Анализ деталей: Для найденного метода определяется, является ли он экспортным. Чтобы быстро проверить использование этих методов, можно применить инструмент для поиска вызовов общих модулей в коде.
  6. Заполнение результата: Все полученные данные (имя, тип, экспорт, параметры) добавляются в результирующую таблицу.
  7. Возврат результата: После обхода всего текста модуля функция возвращает заполненную таблицу.

Этот подход является наиболее полным и практичным. Он позволяет не просто получить список имен, но и собрать дополнительную информацию. Полученные данные можно использовать для дальнейшего анализа или автоматизации разработки в 1С.

← На главную