Подтвердить что ты не робот

Как исключить заголовки из АСТ в clang?

Я создаю АСТ, используя clang. У меня есть следующий файл (lambda.cpp) для синтаксического анализа:

#include <iostream>

void my_lambda()
{
    auto lambda = [](auto x, auto y) {return x + y;};
    std::cout << "fabricati diem"; 
}

Я разбираю это, используя следующую команду:

clang -Xclang -ast-dump -fsyntax-only lambda.cpp

Проблема заключается в том, что clang анализирует также содержимое заголовков. В результате у меня есть довольно большой (~ 3000 строк) файл с бесполезным (для меня) контентом.

Как исключить заголовки при создании АСТ?

4b9b3361

Ответ 1

clang-check может быть полезен в этом вопросе, clang-check имеет параметр -ast-dump-filter=<string>, как описано ниже

-свалка-АСТ-фильтр = < строка > - Используйте с -ast-dump или -ast-print, чтобы выгружать/печатать только узлы объявлений AST, имеющие определенную подстроку в квалифицированное имя. Используйте -ast-list для отображения всех фильтруемых объявлений nodeимена.

когда clang-check выполняется с -ast-dump-filter=my_lambda в примере кода (lambda.cpp)

#include <iostream>

void my_lambda()
{
    auto lambda = [](auto x, auto y) {return x + y;};
    std::cout << "fabricati diem"; 
}

Отбрасывает только согласованное объявление node FunctionDecl my_lambda 'void (void)'

Вот аргументы командной строки и несколько строк из вывода.

$ clang-check -extra-arg=-std=c++1y -ast-dump -ast-dump-filter=my_lambda lambda.cpp --

FunctionDecl 0x2ddf630 <lambda.cpp:3:1, line:7:1> line:3:6 my_lambda 'void (void)'
`-CompoundStmt 0x2de1558 <line:4:1, line:7:1>
  |-DeclStmt 0x2de0960 <line:5:9, col:57>

Ответ 2

Это проблема с С++, а не с clang: на С++ нет файлов, там только блок компиляции. Когда вы #include файл, вы включаете все определения в указанный файл (рекурсивно) в свой блок компиляции, и нет возможности их дифференцировать (это то, что стандарт ожидает от вашего компилятора).

Представьте себе другой сценарий:

/////////////////////////////
// headertmp.h
#if defined(A)
    struct Foo {
        int bar;
    };
#elif defined(B)
    struct Foo {
        short bar;
    };
#endif

/////////////////////////////
// foobar.cpp
#ifndef A
# define B
#endif

#include "headertmp.h"

void foobar(Foo foo) {
    // do stuff to foo.bar
}

Ваш foobar.cpp объявляет структуру с именем Foo и функцию с именем foobar, но headertmp.h сама не определяет Foo, если не определены A или B. Только в компиляционной единице foobar, где эти два объединяются, вы можете понять headertmp.h.

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

Ответ 3

Фильтрация на конкретном идентификаторе прекрасна, используя -ast-dump-filter. Но что, если вы хотите, чтобы ast из всех идентификаторов в одном файле?

Я придумал следующее решение:

Добавьте одну узнаваемую строку после включения:

#include <iostream>
int XX_MARKER_XX = 123234; // marker line for ast-dump
void my_lambda()
...

Затем сбросьте ast с помощью

clang-check -extra-arg=-std=c++1y -ast-dump lambda.cpp > ast.txt

Вы можете легко отрезать все вещи до XX_MARKER_XX с помощью sed:

cat ast.txt | sed -n '/XX_MARKER_XX/,$p'  | less

Еще много, но гораздо полезнее для больших файлов.