I have a simple header parser based on clang and I get the typedefs from some source.
struct _poire { int g; tomate rouge; }; typedef struct _poire kudamono;
After parsing this I have a clang::TypedefDecl
then I get the clang::QualType
of the typedef with clang::TypedefDecl::getUnderlyingType()
With the QualType
if I use the getAsString
method I can find the "struct _poire" std::string
. All this is Ok.
The problem is if I try to see if this type is a canonical type, with QualType::isCanonical()
, it returns false.
So I try to get the canonical type with QualType::getCanonicalType().getAsString()
and it returns the same string "struct _poire".
according to the clang reference on type http://clang.llvm.org/docs/InternalsManual.html#canonical-types , I thought that the isCanonical() should return true when no typedef is involved.
So what are really canonical type?
LibClang is a stable high level C interface to clang. When in doubt LibClang is probably the interface you want to use. Consider the other interfaces only when you have a good reason not to use LibClang. Canonical examples of when to use LibClang: Xcode.
To configure a Visual Studio project to use Clang, right-click on the project node in Solution Explorer and choose Properties. Typically, you should first choose All configurations at the top of the dialog. Then, under General > Platform Toolset, choose LLVM (clang-cl) and then OK.
After further investigations and a question in the clang mailing list, I think I have figured out what is a canonical type.
Firstly it 's important to not focus on the QualType in order to understand Canonical Type. Look this (code /pseudocode):
source file :
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 and t are not the same QualType even if they have the same string representation. QualType are used to associate qualifiers ("const", "volatile"...) with a clang type. There are a lot of Clang Types classes because clang needs to keep tracks of the user-specified types for diagnostics.( http://clang.llvm.org/docs/InternalsManual.html#the-type-class-and-its-subclasses and http://clang.llvm.org/doxygen/classclang_1_1Type.html )
The clang types used depends heavily on the syntaxic sugars or modifiers associated with the C/C++ types in the source file.
In the exemple above, the QualType t is associated with an ElaboratedType. This type allows to keep track of the type name as written in the source code. But the canonical QualType is associated with a RecordType.
Another example: source file:
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
Here we can see that the underlying type of the typedef is recorded as "kudamono" a TypedefType and not "struct _poire" an ElaboratedType.
The canonical type for the TypedefType "kudamono" is a RecordType "struct _poire".
Another examples that I have had from the clang mailing-list ( http://article.gmane.org/gmane.comp.compilers.clang.devel/38371/match=canonical+type ):
Consider:
int (x);
The type of x is not a BuiltinType; it's a ParenType whose canonical type is a BuiltinType. And given
struct X { int n; }; struct X x;
the type of x will probably be represented as an ElaboratedType whose canonical type is a RecordType.
So the canonical Type in clang are classes of types that are not associated with any syntaxic sugars or modifiers or typedef (like BuiltinType or RecordType). Other classes of types (like ParentType, TypedefType or ElaboratedType) are used to keep tracks of the user type for diagnostics (error message ...).
It seems that you have raised an interesting point. I have figured out something, but since I can't actually test my intuition right now, I can't be 100% sure. Anyway here is what I would do :
If I parse your code (with a little extension to declare a kudamono variable), here is what I can say from this:
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; }
When the typedef is parsed, here is what is yielded :
-TypedefDecl 0x23b4620 <line:5:1, col:23> kudamono 'struct _poire':'struct _poire'
When I declare a variable of type kudamono
, here is below its AST-dump :
-VarDecl 0x2048040 <col:2, col:11> une_poire 'kudamono':'struct _poire'
NB : You can get the AST Dump of your code with this command line, it can be really handy to understand how your code will be parsed :
clang -Xclang -ast-dump -std=c++11 -fsyntax-only test.cpp (just remove -std=c++11 if you want to compile a file_name.c file)
Now, from what I understand, I will make a comparaison between the VarDecl
and the TypedefDecl
:
1°) This VarDecl
is named une_poire and has the type kudamono which is a typedef from the type struct _poire.
2°) This TypedefDecl
is named kudamono and has the type struct _poire which is a typedef from the type struct _poire
So, the weird part is right here. struct _poire is considered as typedef from struct _poire.
You'll note that I tried to make a typedef with a usual type :
typedef int numbers;
And this time, AST-dump yields :
TypedefDecl 0x25d9680 <line:7:1, col:13> numbers 'int'
, so I guess the parser may have some troubles with handmade types (typically structs).
I can see one dirty way to know if your type is canonical or not (without getting false positives or false negatives) :
Check that the QualType and the canonical QualType are not the same
I don't know if a simple '=' between Qualtype
will make false positives or false negatives (as I can't test), but you can still compare the names of the types with strcmp
So, to sum up a little bit :
typedef int int32_t
). If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With