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

Что такое канонические типы в Clang?

У меня есть простой анализатор заголовков на основе clang, и я получаю typedefs из некоторого источника.

struct _poire {
int g;
tomate rouge;
};
typedef struct _poire kudamono;

После синтаксического анализа у меня есть clang::TypedefDecl, тогда я получаю clang::QualType typedef с clang::TypedefDecl::getUnderlyingType()

С помощью QualType, если я использую метод getAsString, я могу найти "struct _poire" std::string. Все это хорошо.

Проблема в том, что если я попытаюсь увидеть, является ли этот тип каноническим типом, с QualType::isCanonical() он возвращает false.

Итак, я пытаюсь получить канонический тип с QualType::getCanonicalType().getAsString() и возвращает ту же строку "struct _poire".

согласно ссылке clang по типу http://clang.llvm.org/docs/InternalsManual.html#canonical-types, я думал, что isCanonical() должен вернуться true, когда не задействован typedef.

Так что же такое канонический тип?

4b9b3361

Ответ 1

После дальнейших исследований и вопроса в списке рассылки clang, я думаю, что я выяснил, что такое канонический тип.

Во-первых, важно не сосредоточиться на QualType, чтобы понять тип Canonical. Посмотрите это (код/​​псевдокод):

исходный файл:

typedef struct _poire kudamono; 

clang code:

QualType t = clang::TypedefDecl::getUnderlyingType()

t.getAsString() // "struct _poire"
t.isCanonical() // false
t.getTypePtr()->getTypeClassName() // ElaboredType

c = t.getCanonicalType()
c.getAsString() // "struct _poire"
c.isCanonical() // true
c.getTypePtr()->getTypeClassName() // RecordType

c и t не являются одинаковыми QualType, даже если они имеют одинаковое строковое представление. QualType используются для связывания квалификаторов ( "const", "volatile"...) с типом clang. Существует много классов типов Clang, потому что clang должен отслеживать типы заданных пользователем типов для диагностики. (http://clang.llvm.org/docs/InternalsManual.html#the-type-class-and-its-subclasses и http://clang.llvm.org/doxygen/classclang_1_1Type.html)

Используемые типы clang сильно зависят от синтаксических сахаров или модификаторов, связанных с типами C/С++ в исходном файле.

В приведенном выше примере QualType t связан с ElaboratedType. Этот тип позволяет отслеживать имя типа, как указано в исходном коде. Но канонический QualType связан с типом RecordType.

Другой пример: исходный файл:

typedef struct _poire kudamono;
typedef kudamono tabemono;

clang code:

QualType t = clang::TypedefDecl::getUnderlyingType()
t.getAsString() // "kudamono"
t.isCanonical() // false
t.getTypePtr()->getTypeClassName() // TypedefType

c = t.getCanonicalType()
c.getAsString() // "struct _poire"
c.isCanonical() // true
c.getTypePtr()->getTypeClassName() // RecordType

Здесь мы видим, что базовый тип typedef записывается как "kudamono" TypedefType, а не "struct_poire", разработанный тип.

Канонический тип для TypedefType "kudamono" - это тип записи "struct_poire" RecordType.

Другие примеры, которые я получил из списка рассылки clang (http://article.gmane.org/gmane.comp.compilers.clang.devel/38371/match=canonical+type):

Рассмотрим:

int (x);

Тип x не является встроенным типом; это ParenType, канонический тип которого является встроенным типом. И учитывая

struct X { int n; };
struct X x;

тип x, вероятно, будет представлен как разработанный тип, канонический тип которого является типом RecordType.

Таким образом, канонический тип в clang - это классы типов, которые не связаны ни с синтаксическими сахарами, ни с модификаторами, ни с typedef (например, BuiltinType или RecordType). Другие классы типов (например, ParentType, TypedefType или ElaboratedType) используются для отслеживания дорожек пользовательского типа для диагностики (сообщение об ошибке...).

Ответ 2

Кажется, вы подняли интересный момент. Я что-то придумал, но, поскольку я не могу проверить свою интуицию прямо сейчас, я не могу быть на 100% уверен. В любом случае, вот что я буду делать:

Если я проанализирую ваш код (с небольшим расширением для объявления переменной kudamono), вот что я могу сказать из этого:

struct _poire {
    int g;
    char rouge; // tomate is probably one of your classes so I just changed the type of the field.
};
typedef struct _poire kudamono;

int maFonction(){
    kudamono une_poire;
    return 0;
}

При анализе typedef вот что получается:

-TypedefDecl 0x23b4620 <line:5:1, col:23> kudamono 'struct _poire':'struct _poire'

Когда я объявляю переменную типа kudamono, ниже ее AST-дампа:

-VarDecl 0x2048040 <col:2, col:11> une_poire 'kudamono':'struct _poire'

NB: вы можете получить AST Dump своего кода с помощью этой командной строки, может быть очень полезно понять, как будет анализироваться ваш код:

clang -Xclang -ast-dump -std = С++ 11 -fsyntax-only test.cpp (просто удалите -std = С++ 11, если вы хотите скомпилировать file_name.c файл)

Теперь, из того, что я понимаю, я сделаю компаразон между VarDecl и TypedefDecl:

1 °) Этот VarDecl называется une_poire и имеет тип kudamono, который является typedef из типа struct _poire.

2 °) Этот TypedefDecl называется kudamono и имеет тип struct _poire, который typedef из типа struct _poire

Итак, странная часть здесь. struct _poire считается typedef из struct _poire.

Вы заметите, что я попытался сделать typedef с обычным типом:

typedef int numbers;

И на этот раз AST-dump дает:

TypedefDecl 0x25d9680 <line:7:1, col:13> numbers 'int', поэтому, по-моему, у парсера могут быть проблемы с типами ручной работы (обычно это структуры).

Я вижу один грязный способ узнать, является ли ваш тип каноническим или нет (без ложных срабатываний или ложных негативов):

Убедитесь, что QualType и канонический QualType не совпадают.

Я не знаю, будет ли простой '=' между Qualtype делать ложные срабатывания или ложные негативы (как я не могу проверить), но вы все равно можете сравнить имена типов с strcmp

Итак, подведем итог немного:

  • Ваше понимание канонического типа прекрасное.
  • У Clang, похоже, есть проблемы с типами ручной работы, но должно быть хорошо с Typedef от обычных типов (например, typedef int int32_t).
  • Если вы хотите знать, является ли тип каноническим или нет, вы можете сравнить имя типа и имя канонического типа, но оно довольно грязное. В обычном типе isCanonical() работает хорошо.