<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Dear Manuel,<div><br></div><div>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</div><div><br></div><div>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.</div><div><br></div><div>For instance:</div><div><br></div><div>class Bar {…};</div><div>class Foo {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>smart_ptr<Bar> _bar;</div><div>};</div><div><br></div><div>void func() {</div><div> Foo a; ;; <- Nothing needs to be defined as a root because smart_ptr<Bar> is on the stack and MPS will find it there.</div><div> 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<Bar> b->_bar is on the heap.</div><div>}</div><div><br></div><div>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.</div><div><br></div><div>I also need to identify every varDecl() and fieldDecl and match them up to their respective RecordDecl.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><div><br></div><div><font face="Courier">(defun template-arg-as-string (template-arg)</font></div><div><font face="Courier"> (let* ((template-arg-kind (cast:get-kind template-arg)))</font></div><div><font face="Courier"> (case template-arg-kind</font></div><div><font face="Courier"> (ast-tooling:type</font></div><div><font face="Courier"> (cast:get-as-string (cast:get-as-type template-arg)))</font></div><div><font face="Courier"> (ast-tooling:integral</font></div><div><font face="Courier"> (format nil "INTEGRAL[~a]" (llvm:to-string (cast:get-as-integral template-arg) 10 t)))</font></div><div><font face="Courier"> (otherwise</font></div><div><font face="Courier"> (error "Add support for template-arg-as-string of kind: ~a" template-arg-kind)))))</font></div><div><font face="Courier"><br></font></div><div><font face="Courier"><br></font></div><div><font face="Courier"><br></font></div><div><font face="Courier">(defun record-key (decl-node)</font></div><div><font face="Courier"> (or decl-node (error "There is a problem, the decl-node is nil"))</font></div><div><font face="Courier"> (case (type-of decl-node)</font></div><div><font face="Courier"> (cast:cxxrecord-decl</font></div><div><font face="Courier"> (format nil "class_~a" (cast:get-name decl-node)))</font></div><div><font face="Courier"> (cast:record-decl</font></div><div><font face="Courier"> (format nil "struct_~a" (cast:get-name decl-node)))</font></div><div><font face="Courier"> (cast:enum-decl</font></div><div><font face="Courier"> (format nil "enum_~a" (cast:get-name decl-node)))</font></div><div><font face="Courier"> (cast:class-template-specialization-decl</font></div><div><font face="Courier"> (let* ((decl-name (cast:get-name decl-node))</font></div><div><font face="Courier"> (template-args (cast:get-template-args decl-node))</font></div><div><font face="Courier"> (template-args-as-list (loop :for i :from 0 :below (cast:size template-args)</font></div><div><font face="Courier"> :collect (let* ((template-arg (cast:template-argument-list-get template-args i)))</font></div><div><font face="Courier"> (template-arg-as-string template-arg)))))</font></div><div><font face="Courier"> (format nil "class-template-specialization-decl_~a<~{~a~^,~}>" (cast:get-name decl-node) template-args-as-list)))</font></div><div><font face="Courier"> (cast:class-template-partial-specialization-decl</font></div><div><font face="Courier"> (let* ((decl-name (cast:get-name decl-node))</font></div><div><font face="Courier"> (template-args (cast:get-template-args decl-node))</font></div><div><font face="Courier"> (template-args-as-list (loop :for i :from 0 :below (cast:size template-args)</font></div><div><font face="Courier"> :collect (cast:get-as-string (cast:get-as-type (cast:template-argument-list-get template-args i))))))</font></div><div><font face="Courier"> (format nil "class-template-partial-specialization-decl_~a<~{~a~^,~}>" (cast:get-name decl-node) template-args-as-list)))</font></div><div><font face="Courier"> (otherwise</font></div><div><font face="Courier"> (format t "Add support for record-key for ~a get-name->~a~%" decl-node (cast:get-name decl-node))</font></div><div><font face="Courier"> (break "Check the decl-node"))))</font></div></div><div><font face="Courier"><br></font></div><div><br></div><div><br></div><div><br></div><div><div apple-content-edited="true">
Christian Schafmeister<br><a href="mailto:chris.schaf@verizon.net">chris.schaf@verizon.net</a><br><br>
</div>
<br><div><div>On Feb 23, 2014, at 12:31 PM, Manuel Klimek <<a href="mailto:klimek@google.com">klimek@google.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Feb 20, 2014 at 8:08 PM, Christian Schafmeister <span dir="ltr"><<a href="mailto:chris.schaf@verizon.net" target="_blank">chris.schaf@verizon.net</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>I’m creating AST Matchers to match recordDecls and varDecls and match the types for the varDecls to recordDecls.</div>
<div>In many cases the varDecls are instantiating template classes and some of the template classes are specialized.</div><div><br></div><div>If I use this matcher:</div><div>recordDecl(isTemplateInstantiation(), isSameOrDerivedFrom(recordDecl(hasName("BAR")))).bind(“WHOLE”) —> FOO<A> node</div>
<div>or</div><div>recordDecl(isExplicitTemplateSpecialization(), isSameOrDerivedFrom(recordDecl(hasName("BAR")))).bind(“WHOLE”) —> FOO<int> node</div><div><br></div><div>How do I get the full name of the nodes that match and are bound to “WHOLE”?</div>
<div><br></div><div>node.getName() —> “FOO” not “FOO<A>” or “FOO<int>"</div></div></blockquote><div><br></div><div>I don't have a good answer. Generally, getName() (or getNameAsString()) will print the full declaration for anything that's a declaration context. So if you match a member m in FOO, you'd get FOO<int>::m. This will be expanded for everything but the last part.</div>
<div>I don't know whether there's a good way to get the expansion for everything. I've never needed it, though; out of curiosity, what do you need it for?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word"><div><br></div><div><br></div><div><br></div><div>Here is the sample code:</div><div><br></div><div><div class=""><div><font face="Courier">#include <stdio.h></font></div><div><font face="Courier">#include <core/foundation.h></font></div>
<div><font face="Courier">#include <core/object.h></font></div><div><font face="Courier">#include <core/holder.h></font></div><div><font face="Courier"><br></font></div><div><font face="Courier">namespace asttooling {</font></div>
<div><font face="Courier"><br></font></div></div><div><font face="Courier"> class BAR {};</font></div><div><font face="Courier"><br></font></div><div><font face="Courier"> template<typename T> class FOO : public BAR {};</font></div>
<div><font face="Courier"> class A {};</font></div><div><font face="Courier"> </font></div><div><font face="Courier"> template<> class FOO<int> : public BAR {};</font></div><div><font face="Courier"><br>
</font></div><div><font face="Courier"> void tinyFunc()</font></div><div><font face="Courier"> {</font></div><div><font face="Courier"> FOO<A> xa;</font></div><div><font face="Courier"> FOO<int> xi;</font></div>
<div><font face="Courier"> printf("Hi there, this is tinyFunc @%p %p\n", &xa, &xi);</font></div><div><font face="Courier"> }</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">};</font></div>
</div><div><br></div><br><div>
Christian Schafmeister<br><a href="mailto:chris.schaf@verizon.net" target="_blank">chris.schaf@verizon.net</a><br><br>
</div><div><div class="h5">
<br><div><div>On Feb 20, 2014, at 6:56 AM, Manuel Klimek <<a href="mailto:klimek@google.com" target="_blank">klimek@google.com</a>> wrote:</div><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><br>
<div class="gmail_quote">On Thu, Feb 20, 2014 at 3:49 PM, Christian Schafmeister <span dir="ltr"><<a href="mailto:chris.schaf@verizon.net" target="_blank">chris.schaf@verizon.net</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">Manuel,<div><br></div><div>I completely missed those predicates - thank you!</div><div>
<br></div><div>How do I get the full name of an instantiated template recordDecl?</div><div><br></div><div>As in:</div><div>template <class T> class X;</div><div>class A;</div><div><br></div><div>X<A> xa;</div>
<div><br></div><div>If a varDecl(…) matches on xa - how do I get the "X<A>” name?</div></div></blockquote><div><br></div><div>Do you want to "get" it or "match" it. Assuming you want to "get" it, you'd say something like varDecl(hasType(qualType().bind("t"))) (untested ;), and then in the callback extract the QualType and call getAsString() on it.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><br></div><div>Best,</div><div><br></div><div>.Chris.<span><font color="#888888"><br>
<div>
Christian Schafmeister<br><a href="mailto:chris.schaf@verizon.net" target="_blank">chris.schaf@verizon.net</a><br><br>
</div>
<br></font></span><div><div><div>On Feb 20, 2014, at 12:53 AM, Manuel Klimek <<a href="mailto:klimek@google.com" target="_blank">klimek@google.com</a>> wrote:</div><br></div><div><blockquote type="cite">
<div dir="ltr"><div>hasAncestor(decl(anyOf(recordDecl(</div><div> isTemplateInstantiation()),</div><div> functionDecl(isTemplateInstantiation()))</div><div><br></div><div>should do what you want.</div></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Wed, Feb 19, 2014 at 11:01 PM, Christian Schafmeister <span dir="ltr"><<a href="mailto:chris.schaf@verizon.net" target="_blank">chris.schaf@verizon.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word"><div><br></div><div>If I match a varDecl() that is in a method of a template class I get a match for the template and instantiated templates </div><div>- is there a way to tell the difference by matching some difference in the ancestors of the varDecl node?</div>
<div><br></div><div>I get a match for the translate::from_object<T> a0(*args); varDecl in the method activate (see below) that has this type:</div><div>from_object<type-parameter-0-0, struct std::__1::integral_constant<_Bool, true> ></div>
<div><br></div><div>I also get a match that I think is from the instantiation TestFunctoid<int> j(“test”) in tinyFunc - it has this type: "struct translate::from_object<int, std::true_type>"</div><div>
<br></div><div>There is a clear difference in the name - but I was looking for something that didn’t feel like a hack.</div><div><br></div><div>Are there differences in the AST class node for TestFunctoid when it is a template class vs when it is an instantiated template class?</div>
<div><br></div><div><br></div><div><font face="Courier"><br></font></div><div><div><font face="Courier">#include <stdio.h></font></div><div><font face="Courier">#include <core/foundation.h></font></div><div><font face="Courier">#include <core/object.h></font></div>
<div><font face="Courier">#include <core/holder.h></font></div><div><font face="Courier"><br></font></div><div><font face="Courier">namespace asttooling {</font></div><div><font face="Courier"><br></font></div><div>
<font face="Courier"><br></font></div><div><font face="Courier"> template<typename T></font></div><div><font face="Courier"> class TestFunctoid : public core::Functoid {</font></div><div><font face="Courier"> public:</font></div>
<div><font face="Courier"><br></font></div><div><font face="Courier"> TestFunctoid(const string& name) : core::Functoid(name) {};</font></div><div><font face="Courier"> core::T_mv activate( core::const_ActivationFrame_spREF closedOverFrame, int numArgs, ArgArray args )</font></div>
<div><font face="Courier"> {</font></div><div><font face="Courier"> translate::from_object<T> a0(*args);</font></div><div><font face="Courier"> printf( "Address of a0= %p\n", &a0);</font></div>
<div><font face="Courier"> return Values0<core::T_O>();</font></div><div><font face="Courier"> }</font></div><div><font face="Courier"> };</font></div><div><font face="Courier"><br></font></div>
<div><font face="Courier"><br></font></div><div><font face="Courier"><br></font></div><div><font face="Courier"> void tinyFunc()</font></div><div><font face="Courier"> {</font></div><div><font face="Courier"> TestFunctoid<int> j("test");</font></div>
<div><font face="Courier"> TinyStruct x(10);</font></div><div><font face="Courier"> tinyFunc(x);</font></div><div><font face="Courier"> printf("Hi there, this is tinyFunc\n");</font></div><div>
<font face="Courier"> }</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">};</font></div></div><div><br></div><div>
<div><div>Christian Schafmeister</div><div>Associate Professor</div><div>Chemistry Department</div><div>Temple University</div></div>
</div>
<br></div></blockquote></div><br></div>
</blockquote></div></div><br></div></div></blockquote></div><br></div></div>
</blockquote></div><br></div></div></div></blockquote></div><br></div></div>
</blockquote></div><br></div></body></html>