You can see that even though all the decls and types know that it’s an int there, because it’s in all of their display names and spellings, the underlying type in the AST (last line) ultimately ends up as TypeKind::Unexposed instead of TypeKind::Int.
How is this information getting lost? And where could I fix it?
That is a surprise to me – I’m not certain how you would get that behavior, but the way I’d debug it is to put breakpoints in CXType.cpp in the GetTypeKind() and GetBuiltinTypeKind() functions where they return an unexposed index. From there you can look to see what the unexposed type actually is.
Thanks Aaron! I actually ended up writing a RecursiveASTVisitor last night to be able to inspect the AST directly. Bit slow-going since it’s been a while since I touched the C++ API, but that gives me this for the same snippet:
FunctionProtoType 0x56512f563650 'int (int *)' cdecl
|-SubstTemplateTypeParmType 0x56512f563510 'int' sugar
| |-TemplateTypeParmType 0x56512f53e890 'T' dependent depth 0 index 0
| | `-TemplateTypeParm 0x56512f53e840 'T'
| `-BuiltinType 0x56512f4f78d0 'int'
`-PointerType 0x56512f563580 'int *'
`-SubstTemplateTypeParmType 0x56512f563510 'int' sugar
|-TemplateTypeParmType 0x56512f53e890 'T' dependent depth 0 index 0
| `-TemplateTypeParm 0x56512f53e840 'T'
`-BuiltinType 0x56512f4f78d0 'int'
You can see that it’s a SubstTemplateTypeParmType. Interestingly the decl for the method is FunctionTemplate which is getting exposed in libclang as a CXXMethod, which I would have interpreted as being a CXXMethodDecl underneath. How does that association work?
So for my specific problem, I guess the obvious answer is to check for SubstTemplateTypeParmType and handle that. Would it make sense just to return the substitution type directly, or would it be better to add API to get the substitution type (clang_Type_getTemplateSubstitution()?), and add a new CXType_SubstTemplate that could be used to identify this situation and call the new function?
Ah okay, that makes sense! We don’t seem to expose a cursor for that.
Hmmm, I would have expected FunctionTemplateDecl to be exposed as CXCursor_FunctionTemplate and not CXCursor_CXXMethod. A FunctionTemplateDecl is a template type that wraps a FunctionDecl which represents the uninstantiated template and it carries a list of all the specializations of that function template.
I think it might be best to expose the substitution type. 1) I think we want the C indexing API to model the AST so it’s easier to reason about from things like an AST dump. 2) This type exists to make it clear that the type came out of a template substitution and is not a canonical type. 3) The type exposes more information, like getting the replaced TemplateTypeParmDecl object from the substituted type.