Что такое канонические типы в 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.
Так что же такое канонический тип?
Ответы
Ответ 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() работает хорошо.