Dear Manuel,
Thank you - after banging my head against the wall for a couple of days I realized that I needed to extract the template arguments from the ClassTemplateSpecializationDecl myself using ClassTemplateSpecializationDecl::getTemplateArgs
I’m writing a program that digs through the 165 C++ source files that is the C++ core of my Common Lisp system and analyzes classes and variables to construct the interface to a copying, generational garbage collector (the Memory-Pool-System (MPS) by Ravenbrook systems). I’m working on adding this garbage collector to my Common Lisp system and I don’t want to do it by hand because it would be a huge job to write and maintain. I have hundreds of classes/instantiated template classes and thousands of variable declarations that need to be matched to each other in the analysis.
For instance:
class Bar {…};
class Foo {
smart_ptr _bar;
};
void func() {
Foo a; ;; ← Nothing needs to be defined as a root because smart_ptr is on the stack and MPS will find it there.
Foo* b = new Foo(); ;; <— MPS needs to be informed that this is a root because the *b is on the heap and the smart_ptr b->_bar is on the heap.
}
So I need to analyze every class (matcher: recordDecl(…) ) like Foo and classify them whether they store pointers on the heap for the situation where an instance is stored on the stack or the heap. Then I use that info to construct the garbage collector interface or print warnings so that I can go in and by hand and fix to be compatible with the garbage collector.
I also need to identify every varDecl() and fieldDecl and match them up to their respective RecordDecl.
I’ve been struggling to construct a unique key for each RecordDecl given that I have CXXRecordDecls and instantiated ClassTemplateSpecializationDecls all over the place and I need to generate matching keys from the type of each varDecl.
I can’t use the AST node directly because I’m scanning 165 files and I can’t load all of the AST’s into memory at once - that requires tens of gigabytes and brings my machine to it’s knees. Once one file is processed, its AST nodes get destroyed so I need to generate keys based on the RecordDecl’s names.
I figured it out though - I wrote these functions (Common Lisp) that generate the name of each RecordDecl by checking what kind of RecordDecl it is and doing different things based on that. If it’s a ClassTemplateSpecializationDecl it gets the arguments using getTemplateArgs and builds a list of argument names and attaches it to the name of the template class.
(defun template-arg-as-string (template-arg)
(let* ((template-arg-kind (cast:get-kind template-arg)))
(case template-arg-kind
(ast-tooling:type
(cast:get-as-string (cast:get-as-type template-arg)))
(ast-tooling:integral
(format nil “INTEGRAL[~a]” (llvm:to-string (cast:get-as-integral template-arg) 10 t)))
(otherwise
(error “Add support for template-arg-as-string of kind: ~a” template-arg-kind)))))
(defun record-key (decl-node)
(or decl-node (error “There is a problem, the decl-node is nil”))
(case (type-of decl-node)
(cast:cxxrecord-decl
(format nil “class_~a” (cast:get-name decl-node)))
(cast:record-decl
(format nil “struct_~a” (cast:get-name decl-node)))
(cast:enum-decl
(format nil “enum_~a” (cast:get-name decl-node)))
(cast:class-template-specialization-decl
(let* ((decl-name (cast:get-name decl-node))
(template-args (cast:get-template-args decl-node))
(template-args-as-list (loop :for i :from 0 :below (cast:size template-args)
:collect (let* ((template-arg (cast:template-argument-list-get template-args i)))
(template-arg-as-string template-arg)))))
(format nil “class-template-specialization-decl_~a<~{~a~^,~}>” (cast:get-name decl-node) template-args-as-list)))
(cast:class-template-partial-specialization-decl
(let* ((decl-name (cast:get-name decl-node))
(template-args (cast:get-template-args decl-node))
(template-args-as-list (loop :for i :from 0 :below (cast:size template-args)
:collect (cast:get-as-string (cast:get-as-type (cast:template-argument-list-get template-args i))))))
(format nil “class-template-partial-specialization-decl_~a<~{~a~^,~}>” (cast:get-name decl-node) template-args-as-list)))
(otherwise
(format t “Add support for record-key for ~a get-name->~a~%” decl-node (cast:get-name decl-node))
(break “Check the decl-node”))))
Christian Schafmeister
chris.schaf@verizon.net