OSDN Git Service

ed72cf946b9fc6bed7a097561be897d80afffa1c
[qt-creator-jp/qt-creator-jp.git] / src / libs / qtcreatorcdbext / containers.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "containers.h"
35 #include "symbolgroupvalue.h"
36 #include "symbolgroup.h"
37 #include "stringutils.h"
38
39 #include <functional>
40 #include <iterator>
41
42 typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbolGroupNodePtrVector;
43 typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
44 typedef std::vector<int>::size_type VectorIndexType;
45
46 // Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
47 static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
48 {
49     const unsigned pointerSize = SymbolGroupValue::pointerSize();
50     const ULONG allocSize = pointerSize * count;
51     ULONG bytesRead = 0;
52     void *data = new unsigned char[allocSize];
53     const HRESULT hr = ctx.dataspaces->ReadVirtual(address, data, allocSize, &bytesRead);
54     if (FAILED(hr) || bytesRead != allocSize) {
55         delete [] data;
56         return 0;
57     }
58     return data;
59 }
60
61 template <class UInt>
62 inline void dumpHexArray(std::ostream &os, const UInt *a, int count)
63 {
64     os << std::showbase << std::hex;
65     std::copy(a, a + count, std::ostream_iterator<UInt>(os, ", "));
66     os << std::noshowbase << std::dec;
67 }
68
69 static inline void dump32bitPointerArray(std::ostream &os, const void *a, int count)
70 {
71     dumpHexArray(os, reinterpret_cast<const ULONG32 *>(a), count);
72 }
73
74 static inline void dump64bitPointerArray(std::ostream &os, const void *a, int count)
75 {
76     dumpHexArray(os, reinterpret_cast<const ULONG64 *>(a), count);
77 }
78
79 // Fix the inner type of containers (that is, make it work smoothly with AddSymbol)
80 // by prefixing it with the module except for well-known types like STL/Qt types
81 static inline std::string fixInnerType(std::string type,
82                                        const SymbolGroupValue &container)
83 {
84     const std::string stripped
85         = SymbolGroupValue::stripConst(SymbolGroupValue::stripClassPrefixes(type));
86     const KnownType kt = knownType(stripped, 0);
87     // Resolve types unless they are POD or pointers to POD (that is, qualify 'Foo' and 'Foo*')
88     const bool needResolve = kt == KT_Unknown || kt ==  KT_PointerType || !(kt & KT_POD_Type);
89     const std::string fixed = needResolve ?
90                 SymbolGroupValue::resolveType(stripped, container.context(), container.module()) :
91                 stripped;
92     if (SymbolGroupValue::verbose) {
93         DebugPrint dp;
94         dp << "fixInnerType (resolved=" << needResolve << ") '" << type << "' [";
95         formatKnownTypeFlags(dp, kt);
96         dp << "] -> '" << fixed <<"'\n";
97     }
98     return fixed;
99 }
100
101 // Return size from an STL vector (last/first iterators).
102 static inline int msvcStdVectorSize(const SymbolGroupValue &v)
103 {
104     if (const SymbolGroupValue myFirstPtrV = v["_Myfirst"]) {
105         if (const SymbolGroupValue myLastPtrV = v["_Mylast"]) {
106             const ULONG64 firstPtr = myFirstPtrV.pointerValue();
107             const ULONG64 lastPtr = myLastPtrV.pointerValue();
108             if (!firstPtr || lastPtr < firstPtr)
109                 return -1;
110             if (lastPtr == firstPtr)
111                 return 0;
112             // Subtract the pointers: We need to do the pointer arithmetics ourselves
113             // as we get char *pointers.
114             const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v);
115             const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
116             if (size == 0)
117                 return -1;
118             return static_cast<int>((lastPtr - firstPtr) / size);
119         }
120     }
121     return -1;
122 }
123
124 // Return size of container or -1
125 int containerSize(KnownType kt, SymbolGroupNode *n, const SymbolGroupValueContext &ctx)
126 {
127     QTC_TRACE_IN
128     if ((kt & KT_ContainerType) == 0)
129         return -1;
130     const int ct = containerSize(kt, SymbolGroupValue(n, ctx));
131     QTC_TRACE_OUT
132     return ct;
133 }
134
135 /*! Determine size of containers \ingroup qtcreatorcdbext */
136 int containerSize(KnownType kt, const SymbolGroupValue &v)
137 {
138     switch (kt) {
139     case KT_QStringList:
140         if (const SymbolGroupValue base = v[unsigned(0)])
141             return containerSize(KT_QList, base);
142         break;
143     case KT_QList:
144         if (const SymbolGroupValue dV = v["d"]) {
145             if (const SymbolGroupValue beginV = dV["begin"]) {
146                 const int begin = beginV.intValue();
147                 const int end = dV["end"].intValue();
148                 if (begin >= 0 && end >= begin)
149                     return end - begin;
150             }
151         }
152         break;
153     case KT_QLinkedList:
154     case KT_QHash:
155     case KT_QMap:
156     case KT_QVector:
157         if (const SymbolGroupValue sizeV = v["d"]["size"])
158             return sizeV.intValue();
159         break;
160     case KT_QMultiHash:
161         if (const SymbolGroupValue qHash = v[unsigned(0)])
162             return containerSize(KT_QHash, qHash);
163         break;
164     case KT_QQueue:
165         if (const SymbolGroupValue qList= v[unsigned(0)])
166             return containerSize(KT_QList, qList);
167         break;
168     case KT_QStack:
169         if (const SymbolGroupValue qVector = v[unsigned(0)])
170             return containerSize(KT_QVector, qVector);
171         break;
172     case KT_QSet:
173         if (const SymbolGroupValue base = v[unsigned(0)])
174             return containerSize(KT_QHash, base);
175         break;
176     case KT_QMultiMap:
177         if (const SymbolGroupValue base = v[unsigned(0)])
178             return containerSize(KT_QMap, base);
179         break;
180     case KT_StdVector: {
181         if (const SymbolGroupValue base = v[unsigned(0)]) {
182             const int msvc10Size = msvcStdVectorSize(base);
183             if (msvc10Size >= 0)
184                 return msvc10Size;
185         }
186         const int msvc8Size = msvcStdVectorSize(v);
187         if (msvc8Size >= 0)
188             return msvc8Size;
189     }
190         break;
191     case KT_StdList:
192         if (const SymbolGroupValue sizeV =  v["_Mysize"]) // VS 8
193             return sizeV.intValue();
194         if (const SymbolGroupValue sizeV = v[unsigned(0)][unsigned(0)]["_Mysize"]) // VS10
195             return sizeV.intValue();
196         break;
197     case KT_StdDeque: {
198         const SymbolGroupValue msvc10sizeV =  v[unsigned(0)]["_Mysize"]; // VS10
199         if (msvc10sizeV)
200             return msvc10sizeV.intValue();
201         const SymbolGroupValue msvc8sizeV =  v["_Mysize"]; // VS8
202         if (msvc8sizeV)
203             return msvc8sizeV.intValue();
204     }
205         break;
206     case KT_StdStack:
207         if (const SymbolGroupValue deque =  v[unsigned(0)])
208             return containerSize(KT_StdDeque, deque);
209         break;
210     case KT_StdSet:
211     case KT_StdMap:
212     case KT_StdMultiMap:
213         if (const SymbolGroupValue baseV = v[unsigned(0)]) {
214             if (const SymbolGroupValue sizeV = baseV["_Mysize"]) // VS 8
215                 return sizeV.intValue();
216             if (const SymbolGroupValue sizeV = baseV[unsigned(0)][unsigned(0)]["_Mysize"]) // VS 10
217                 return sizeV.intValue();
218         }
219         break;
220     }
221     return -1;
222 }
223
224 /* Generate a list of children by invoking the functions to obtain the value
225  * and the next link */
226 template <class ValueFunction, class NextFunction>
227 AbstractSymbolGroupNodePtrVector linkedListChildList(SymbolGroupValue headNode,
228                                                      int count,
229                                                      ValueFunction valueFunc,
230                                                      NextFunction nextFunc)
231 {
232     AbstractSymbolGroupNodePtrVector rc;
233     rc.reserve(count);
234     for (int i =0; i < count && headNode; i++) {
235         if (const SymbolGroupValue value = valueFunc(headNode)) {
236             rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, value.node()));
237             headNode = nextFunc(headNode);
238         } else {
239             break;
240         }
241     }
242     return rc;
243 }
244
245 // Helper function for linkedListChildList that returns a member by name
246 class MemberByName : public std::unary_function<const SymbolGroupValue &, SymbolGroupValue>
247 {
248 public:
249     explicit MemberByName(const char *name) : m_name(name) {}
250     SymbolGroupValue operator()(const SymbolGroupValue &v) { return v[m_name]; }
251
252 private:
253     const char *m_name;
254 };
255
256 // std::list<T>: Dummy head node and then a linked list of "_Next", "_Myval".
257 static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count,
258                                                         const SymbolGroupValueContext &ctx)
259 {
260     if (!count)
261         return AbstractSymbolGroupNodePtrVector();
262     const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"];
263     if (!head) {
264         if (SymbolGroupValue::verbose)
265             DebugPrint() << "std::list failure: " << head;
266         return AbstractSymbolGroupNodePtrVector();
267     }
268     return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
269 }
270
271 // QLinkedList<T>: Dummy head node and then a linked list of "n", "t".
272 static inline AbstractSymbolGroupNodePtrVector qLinkedListChildList(SymbolGroupNode *n, int count,
273                                                         const SymbolGroupValueContext &ctx)
274 {
275     if (count)
276         if (const SymbolGroupValue head = SymbolGroupValue(n, ctx)["e"]["n"])
277             return linkedListChildList(head, count, MemberByName("t"), MemberByName("n"));
278     return AbstractSymbolGroupNodePtrVector();
279 }
280
281 /* Helper for array-type containers:
282  * Add a series of "*(innertype *)0x (address + n * size)" fake child symbols.
283  * for a function generating a sequence of addresses. */
284
285 template <class AddressFunc>
286 AbstractSymbolGroupNodePtrVector arrayChildList(SymbolGroup *sg, AddressFunc addressFunc,
287                                                 const std::string &module,
288                                                 const std::string &innerType,
289                                                 int count)
290 {
291     AbstractSymbolGroupNodePtrVector rc;
292     if (!count)
293         return rc;
294     std::string errorMessage;
295     rc.reserve(count);
296     for (int i = 0; i < count; i++) {
297         const std::string name = SymbolGroupValue::pointedToSymbolName(addressFunc(), innerType);
298         if (SymbolGroupNode *child = sg->addSymbol(module, name, std::string(), &errorMessage)) {
299             rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child));
300         } else {
301             if (SymbolGroupValue::verbose)
302                 DebugPrint() << "addSymbol fails in arrayChildList";
303             break;
304         }
305     }
306     if (SymbolGroupValue::verbose)
307         DebugPrint() << "arrayChildList '" << innerType << "' count=" << count << " returns "
308                      << rc.size() << " elements";
309     return rc;
310 }
311
312 // Helper function for arrayChildList() taking a reference to an address and simply generating
313 // a sequence of address, address + delta, address + 2 * delta...
314 class AddressSequence
315 {
316 public:
317     explicit inline AddressSequence(ULONG64 &address, ULONG delta) : m_address(address), m_delta(delta) {}
318     inline ULONG64 operator()()
319     {
320         const ULONG64 rc = m_address;
321         m_address += m_delta;
322         return rc;
323     }
324
325 private:
326     ULONG64 &m_address;
327     const ULONG m_delta;
328 };
329
330 static inline AbstractSymbolGroupNodePtrVector
331     arrayChildList(SymbolGroup *sg, ULONG64 address, const std::string &module,
332                    const std::string &innerType, int count)
333 {
334     if (const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str()))
335         return arrayChildList(sg, AddressSequence(address, innerTypeSize),
336                               module, innerType, count);
337     return AbstractSymbolGroupNodePtrVector();
338 }
339
340 // std::vector<T>
341 static inline AbstractSymbolGroupNodePtrVector
342     stdVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
343 {
344     if (count) {
345         // std::vector<T>: _Myfirst is a pointer of T*. Get address
346         // element to obtain address.
347         const SymbolGroupValue vec(n, ctx);
348         SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010
349         if (!myFirst)
350             myFirst = vec["_Myfirst"]; // MSVC2008
351         if (myFirst) {
352             if (const ULONG64 address = myFirst.pointerValue()) {
353                 const std::string firstType = myFirst.type();
354                 const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec);
355                 if (SymbolGroupValue::verbose)
356                     DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
357                 return arrayChildList(n->symbolGroup(), address, n->module(), innerType, count);
358             }
359         }
360     }
361     return AbstractSymbolGroupNodePtrVector();
362 }
363
364 // Helper for std::deque<>: From the array of deque blocks, read out the values.
365 template<class AddressType>
366 AbstractSymbolGroupNodePtrVector
367     stdDequeChildrenHelper(SymbolGroup *sg,
368                            const AddressType *blockArray, ULONG64 blockArraySize,
369                            const std::string &module,
370                            const std::string &innerType, ULONG64 innerTypeSize,
371                            ULONG64 startOffset, ULONG64 dequeSize, int count)
372 {
373     AbstractSymbolGroupNodePtrVector rc;
374     rc.reserve(count);
375     std::string errorMessage;
376     // Determine block number and offset in the block array T[][dequeSize]
377     // and create symbol by address.
378     for (int i = 0; i < count; i++) {
379         // see <deque>-header: std::deque<T>::iterator::operator*
380         const ULONG64 offset = startOffset + i;
381         ULONG64 block = offset / dequeSize;
382         if (block >= blockArraySize)
383             block -= blockArraySize;
384         const ULONG64 blockOffset = offset % dequeSize;
385         const ULONG64 address = blockArray[block] + innerTypeSize * blockOffset;
386         if (SymbolGroupNode *n = sg->addSymbol(module, SymbolGroupValue::pointedToSymbolName(address, innerType), std::string(), &errorMessage)) {
387             rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, n));
388         } else {
389             return AbstractSymbolGroupNodePtrVector();
390         }
391     }
392     return rc;
393 }
394
395 // std::deque<>
396 static inline AbstractSymbolGroupNodePtrVector
397     stdDequeDirectChildList(const SymbolGroupValue &deque, int count)
398 {
399     if (!count)
400         return AbstractSymbolGroupNodePtrVector();
401     // From MSVC10 on, there is an additional base class
402     const ULONG64 arrayAddress = deque["_Map"].pointerValue();
403     const int startOffset = deque["_Myoff"].intValue();
404     const int mapSize  = deque["_Mapsize"].intValue();
405     if (!arrayAddress || startOffset < 0 || mapSize <= 0)
406         return AbstractSymbolGroupNodePtrVector();
407     const std::vector<std::string> innerTypes = deque.innerTypes();
408     if (innerTypes.empty())
409         return AbstractSymbolGroupNodePtrVector();
410     const std::string innerType = fixInnerType(innerTypes.front(), deque);
411     // Get the deque size (block size) which is an unavailable static member
412     // (cf <deque> for the actual expression).
413     const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
414     if (!innerTypeSize)
415         return AbstractSymbolGroupNodePtrVector();
416     const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ?
417                                8 : innerTypeSize <= 4 ? 4 : innerTypeSize <= 8 ? 2 : 1;
418     // Read out map array (pointing to the blocks)
419     void *mapArray = readPointerArray(arrayAddress, mapSize, deque.context());
420     if (!mapArray)
421         return AbstractSymbolGroupNodePtrVector();
422     const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ?
423         stdDequeChildrenHelper(deque.node()->symbolGroup(),
424                                reinterpret_cast<const ULONG64 *>(mapArray), mapSize,
425                                deque.module(), innerType, innerTypeSize, startOffset, dequeSize, count) :
426         stdDequeChildrenHelper(deque.node()->symbolGroup(),
427                                reinterpret_cast<const ULONG32 *>(mapArray), mapSize,
428                                deque.module(), innerType, innerTypeSize, startOffset, dequeSize, count);
429     delete [] mapArray;
430     return rc;
431 }
432
433 // std::deque<>
434 static inline AbstractSymbolGroupNodePtrVector
435     stdDequeChildList(const SymbolGroupValue &v, int count)
436 {
437     // MSVC10 has a base class. If that fails, try direct (MSVC2008)
438     const AbstractSymbolGroupNodePtrVector msvc10rc = stdDequeDirectChildList(v[unsigned(0)], count);
439     return msvc10rc.empty() ? stdDequeDirectChildList(v, count) : msvc10rc;
440 }
441
442 /* Helper class for std::map<>,std::set<> based on std::__Tree:
443  * We locally rebuild the structure in using instances of below class 'StdMapNode'
444  * with 'left' and 'right' pointers and the values. Reason being that while it is
445  * possible to write the iteration in terms of class SymbolGroupValue, it involves
446  * going back up the tree over the flat node->parent pointers. Doing that in the debugger
447  * sometimes ends up in nirvana, apparently due to it not being able to properly expand it.
448  * StdMapNode has a buildMap() to build a hierarchy from a __Tree value,
449  * begin() to return the first node and next() to iterate. The latter are modeled
450  * after the _Tree::iterator base classes. (_Tree::begin, _Tree::iterator::operator++() */
451
452 class StdMapNode
453 {
454 private:
455     StdMapNode(const StdMapNode &);
456     StdMapNode &operator=(const StdMapNode &);
457
458 public:
459     explicit StdMapNode(StdMapNode *p, const SymbolGroupValue &node, const SymbolGroupValue &value);
460     ~StdMapNode() { delete m_left; delete m_right; }
461
462     // Iterator helpers: Return first and move to next
463     const StdMapNode *begin() const { return StdMapNode::leftMost(this); }
464     static const StdMapNode *next(const StdMapNode *s);
465
466     const SymbolGroupValue &value() const { return m_value; }
467
468     // Build the hierarchy
469     static StdMapNode *buildMap(const SymbolGroupValue &n);
470
471     // Debug helpers
472     void debug(std::ostream &os, unsigned depth = 0) const;
473
474 private:
475     static StdMapNode *buildMapRecursion(const SymbolGroupValue &n, ULONG64 headAddress, StdMapNode *parent);
476     static const StdMapNode *leftMost(const StdMapNode *n);
477
478     StdMapNode *const m_parent;
479     StdMapNode *m_left;
480     StdMapNode *m_right;
481     const SymbolGroupValue m_node;
482     const SymbolGroupValue m_value;
483 };
484
485 StdMapNode::StdMapNode(StdMapNode *p, const SymbolGroupValue &n, const SymbolGroupValue &v) :
486     m_parent(p), m_left(0), m_right(0), m_node(n), m_value(v)
487 {
488 }
489
490 const StdMapNode *StdMapNode::leftMost(const StdMapNode *n)
491 {
492     for ( ; n->m_left ; n = n->m_left ) ;
493     return n;
494 }
495
496 const StdMapNode *StdMapNode::next(const StdMapNode *s)
497 {
498     if (s->m_right) // If we have a right node, return its left-most
499         return StdMapNode::leftMost(s->m_right);
500     do { // Climb looking for 'right' subtree, that is, we are left of it
501         StdMapNode *parent = s->m_parent;
502         if (!parent || parent->m_right != s)
503             return parent;
504         s = parent;
505     } while (true);
506     return 0;
507 }
508
509 StdMapNode *StdMapNode::buildMapRecursion(const SymbolGroupValue &n, ULONG64 headAddress, StdMapNode *parent)
510 {
511     const SymbolGroupValue value = n["_Myval"];
512     if (!value)
513         return 0;
514     StdMapNode *node = new StdMapNode(parent, n, value);
515     // Get left and right nodes. A node pointing to head terminates the recursion
516     if (const SymbolGroupValue left = n["_Left"])
517         if (const ULONG64 leftAddr = left.pointerValue())
518             if (leftAddr != headAddress)
519                 node->m_left = buildMapRecursion(left, headAddress, node);
520     if (const SymbolGroupValue right = n["_Right"])
521         if (const ULONG64 rightAddr = right.pointerValue())
522             if (rightAddr != headAddress)
523                 node->m_right = buildMapRecursion(right, headAddress, node);
524     return node;
525 }
526
527 StdMapNode *StdMapNode::buildMap(const SymbolGroupValue &n)
528 {
529     // Goto root of tree (see _Tree::_Root())
530     if (const SymbolGroupValue head = n["_Myhead"])
531         if (const ULONG64 headAddress = head.pointerValue())
532             return buildMapRecursion(head["_Parent"], headAddress, 0);
533     return 0;
534 }
535
536 static inline void indentStream(std::ostream &os, unsigned indent)
537 {
538     for (unsigned i = 0; i < indent; i++)
539         os << ' ';
540 }
541
542 // Debugging helper for a SymbolGroupValue containing a __Tree::node of
543 // a map (assuming a std::pair inside).
544 static inline void debugMSVC2010MapNode(const SymbolGroupValue &n, std::ostream &os, unsigned indent = 0)
545 {
546     indentStream(os, indent);
547     os << "Node at " << std::hex << std::showbase << n.address()
548        << std::dec << std::noshowbase
549        << " Value='" << wStringToString(n.value()) << "', Parent=" << wStringToString(n["_Parent"].value())
550        << ", Left=" << wStringToString(n["_Left"].value())
551        << ", Right=" << wStringToString(n["_Right"].value())
552        << ", nil='" <<  wStringToString(n["_Isnil"].value());
553     if (const SymbolGroupValue pairBase = n["_Myval"][unsigned(0)]) {
554         os << "', key='"  << wStringToString(pairBase["first"].value())
555            << "', value='"   << wStringToString(pairBase["second"].value())
556            << '\'';
557     } else {
558         os << "', key='"  << wStringToString(n["_Myval"].value()) << '\'';
559     }
560     os << '\n';
561 }
562
563 void StdMapNode::debug(std::ostream &os, unsigned depth) const
564 {
565     indentStream(os, 2 * depth);
566     os << "StdNode=" << this << " Left=" << m_left  << " Right=" << m_right << '\n';
567     debugMSVC2010MapNode(m_node, os, 2 * depth);
568     if (m_left)
569         m_left->debug(os, depth + 1);
570     if (m_right)
571         m_right->debug(os, depth + 1);
572 }
573
574 // Helper for std::map<>,std::set<> based on std::__Tree:
575 // Return the list of children (pair for maps, direct children for set)
576 static inline SymbolGroupValueVector
577     stdTreeChildList(const SymbolGroupValue &tree, int count, bool *isMSVC2010In = 0)
578 {
579     if (!count)
580         return SymbolGroupValueVector();
581     // MSVC2010: "class _Tree : public _Tree_val: public _Tree_nod".
582     // MSVC2008: Direct class
583     const int size = tree[unsigned(0)][unsigned(0)]["_Mysize"].intValue();
584     const bool isMSVC2010 = size >= 0 && size <= count; // Count may be limited
585     if (isMSVC2010In)
586         *isMSVC2010In = isMSVC2010;
587     const SymbolGroupValue treeNode = isMSVC2010 ? tree[unsigned(0)][unsigned(0)] : tree;
588     if (!treeNode)
589         return SymbolGroupValueVector();
590     // Build the tree and iterate it.
591     const StdMapNode *nodeTree = StdMapNode::buildMap(treeNode);
592     if (!nodeTree)
593         return SymbolGroupValueVector();
594     SymbolGroupValueVector rc;
595     rc.reserve(count);
596     int i = 0;
597     for (const StdMapNode *n = nodeTree->begin() ; n && i < count; n = StdMapNode::next(n), i++)
598         rc.push_back(n->value());
599     delete nodeTree;
600     if (rc.size() != count)
601         return SymbolGroupValueVector();
602     return rc;
603 }
604
605 // std::set<>: Children directly contained in list
606 static inline AbstractSymbolGroupNodePtrVector
607     stdSetChildList(const SymbolGroupValue &set, int count)
608 {
609     const SymbolGroupValueVector children = stdTreeChildList(set[unsigned(0)], count);
610     if (int(children.size()) != count)
611         return AbstractSymbolGroupNodePtrVector();
612     AbstractSymbolGroupNodePtrVector rc;
613     rc.reserve(count);
614     for (int i = 0; i < count; i++)
615         rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, children.at(i).node()));
616     return rc;
617 }
618
619 // std::map<K,V>: A list of std::pair<K,V> (derived from std::pair_base<K,V>)
620 static inline AbstractSymbolGroupNodePtrVector
621     stdMapChildList(const SymbolGroupValue &map, int count)
622 {
623     bool isMSVC2010 = true;
624     const SymbolGroupValueVector children = stdTreeChildList(map[unsigned(0)], count, &isMSVC2010);
625     if (int(children.size()) != count)
626         return AbstractSymbolGroupNodePtrVector();
627     AbstractSymbolGroupNodePtrVector rc;
628     rc.reserve(count);
629     for (int i = 0; i < count; i++) {
630         // MSVC2010 introduces a std::pair_base.
631         const SymbolGroupValue pairBase = isMSVC2010?
632                     children.at(i)[unsigned(0)] : children.at(i);
633         const SymbolGroupValue key = pairBase["first"];
634         const SymbolGroupValue value = pairBase["second"];
635         if (key && value) {
636             rc.push_back(MapNodeSymbolGroupNode::create(i, pairBase.address(),
637                                                         pairBase.type(),
638                                                         key.node(), value.node()));
639         } else {
640             return AbstractSymbolGroupNodePtrVector();
641         }
642     }
643     return rc;
644 }
645
646 // QVector<T>
647 static inline AbstractSymbolGroupNodePtrVector
648     qVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
649 {
650     if (count) {
651         // QVector<T>: p/array is declared as array of T. Dereference first
652         // element to obtain address.
653         const SymbolGroupValue vec(n, ctx);
654         if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
655             if (const ULONG64 arrayAddress = firstElementV.address()) {
656                 const std::string fixedInnerType = fixInnerType(firstElementV.type(), vec);
657                 return arrayChildList(n->symbolGroup(), arrayAddress, n->module(), fixedInnerType, count);
658             }
659         }
660     }
661     return AbstractSymbolGroupNodePtrVector();
662 }
663
664 // Helper function for arrayChildList() for use with QLists of large types that are an
665 // array of pointers to allocated elements: Generate a pointer sequence by reading out the array.
666 template <class AddressType>
667 class AddressArraySequence
668 {
669 public:
670     explicit inline AddressArraySequence(const AddressType *array) : m_array(array) {}
671     inline ULONG64 operator()() { return *m_array++; }
672
673 private:
674     const AddressType *m_array;
675 };
676
677 // QList<>.
678 static inline AbstractSymbolGroupNodePtrVector
679     qListChildList(const SymbolGroupValue &v, int count)
680 {
681     // QList<T>: d/array is declared as array of void *[]. Dereference first
682     // element to obtain address.
683     if (!count)
684         return AbstractSymbolGroupNodePtrVector();
685     const SymbolGroupValue dV = v["d"];
686     if (!dV)
687         return AbstractSymbolGroupNodePtrVector();
688     const int begin = dV["begin"].intValue();
689     if (begin < 0)
690         return AbstractSymbolGroupNodePtrVector();
691     const SymbolGroupValue firstElementV = dV["array"][unsigned(0)];
692     if (!firstElementV)
693         return AbstractSymbolGroupNodePtrVector();
694      ULONG64 arrayAddress = firstElementV.address();
695      if (!arrayAddress)
696          return AbstractSymbolGroupNodePtrVector();
697      const std::vector<std::string> innerTypes = v.innerTypes();
698      if (innerTypes.size() != 1)
699          return AbstractSymbolGroupNodePtrVector();
700      const std::string innerType = fixInnerType(innerTypes.front(), v);
701      const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
702      if (SymbolGroupValue::verbose)
703          DebugPrint() << "QList " << v.name() << " inner type " << innerType << ' ' << innerTypeSize;
704      if (!innerTypeSize)
705          return AbstractSymbolGroupNodePtrVector();
706      /* QList<> is:
707       * 1) An array of 'void *[]' where T values are coerced into the elements for
708       *    POD/pointer types and small, movable or primitive Qt types. That is, smaller
709       *    elements are also aligned at 'void *' boundaries.
710       * 2) An array of 'T *[]' (pointer to allocated instances) for anything else
711       *    (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
712       *    isStatic depends on QTypeInfo specializations and hardcoded flags for types. */
713      const unsigned pointerSize = SymbolGroupValue::pointerSize();
714      arrayAddress += begin * pointerSize;
715      if (SymbolGroupValue::isPointerType(innerType)) // Quick check: Any pointer is T[]
716          return arrayChildList(v.node()->symbolGroup(),
717                                AddressSequence(arrayAddress, pointerSize),
718                                v.module(), innerType, count);
719      // Check condition for large||static.
720      bool isLargeOrStatic = innerTypeSize > pointerSize;
721      if (!isLargeOrStatic && !SymbolGroupValue::isPointerType(innerType)) {
722          const KnownType kt = knownType(innerType, false); // inner type, no 'class ' prefix.
723          if (kt != KT_Unknown && !(kt & (KT_POD_Type|KT_Qt_PrimitiveType|KT_Qt_MovableType)))
724              isLargeOrStatic = true;
725      }
726      if (SymbolGroupValue::verbose)
727          DebugPrint() << "isLargeOrStatic " << isLargeOrStatic;
728      if (isLargeOrStatic) {
729          // Retrieve the pointer array ourselves to avoid having to evaluate '*(class foo**)'
730          if (void *data = readPointerArray(arrayAddress, count, v.context()))  {
731              // Generate sequence of addresses from pointer array
732              const AbstractSymbolGroupNodePtrVector rc = pointerSize == 8 ?
733                          arrayChildList(v.node()->symbolGroup(),
734                                         AddressArraySequence<ULONG64>(reinterpret_cast<const ULONG64 *>(data)),
735                                         v.module(), innerType, count) :
736                          arrayChildList(v.node()->symbolGroup(), AddressArraySequence<ULONG32>(reinterpret_cast<const ULONG32 *>(data)),
737                                         v.module(), innerType, count);
738              delete [] data;
739              return rc;
740          }
741          return AbstractSymbolGroupNodePtrVector();
742      }
743      return arrayChildList(v.node()->symbolGroup(),
744                            AddressSequence(arrayAddress, pointerSize),
745                            v.module(), innerType, count);
746 }
747
748 // Return the list of buckets of a 'QHash<>' as 'QHashData::Node *' values from
749 // the list of addresses passed in
750 template<class AddressType>
751 SymbolGroupValueVector hashBuckets(SymbolGroup *sg, const std::string &hashNodeType,
752                                    const AddressType *pointerArray,
753                                    int numBuckets,
754                                    AddressType ePtr,
755                                    const std::string &module,
756                                    const SymbolGroupValueContext &ctx)
757 {
758     SymbolGroupValueVector rc;
759     rc.reserve(numBuckets);
760     const AddressType *end = pointerArray + numBuckets;
761     std::string errorMessage;
762     // Skip 'e' special values as they are used as placeholder for reserve(d)
763     // empty array elements.
764     for (const AddressType *p = pointerArray; p < end; p++) {
765         if (*p != ePtr) {
766             const std::string name = SymbolGroupValue::pointedToSymbolName(*p, hashNodeType);
767             if (SymbolGroupNode *child = sg->addSymbol(module, name, std::string(), &errorMessage)) {
768                 rc.push_back(SymbolGroupValue(child, ctx));
769             } else {
770                 return std::vector<SymbolGroupValue>();
771                 break;
772             }
773         }
774     }
775     return rc;
776 }
777
778 // Return the node type of a QHash/QMap:
779 // "class QHash<K,V>[ *]" -> [struct] "QtCored4!QHashNode<K,V>";
780 static inline std::string qHashNodeType(const SymbolGroupValue &v,
781                                         const char *nodeType)
782 {
783     std::string qHashType = SymbolGroupValue::stripPointerType(v.type());
784     const std::string::size_type pos = qHashType.find('<');
785     if (pos != std::string::npos)
786         qHashType.insert(pos, nodeType);
787     // A map node must be qualified with the current module and
788     // the Qt namespace (particularly QMapNode, QHashNodes work also for
789     // the unqualified case).
790     const QtInfo &qtInfo = QtInfo::get(v.context());
791     const std::string currentModule = v.module();
792     return QtInfo::prependModuleAndNameSpace(qHashType, currentModule, qtInfo.nameSpace);
793 }
794
795 // Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>".
796 SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
797                                   VectorIndexType count)
798 {
799     if (!count)
800         return SymbolGroupValueVector();
801     const SymbolGroupValue hashData = v["d"];
802     // 'e' is used as a special value to indicate empty hash buckets in the array.
803     const ULONG64 ePtr = v["e"].pointerValue();
804     if (SymbolGroupValue::verbose)
805         DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr;
806     if (!hashData || !ePtr)
807         return SymbolGroupValueVector();
808     // Retrieve the array of buckets of 'd'
809     const int numBuckets = hashData["numBuckets"].intValue();
810     const ULONG64 bucketArray = hashData["buckets"].pointerValue();
811     if (numBuckets <= 0 || !bucketArray)
812         return SymbolGroupValueVector();
813     void *bucketPointers = readPointerArray(bucketArray, numBuckets, v.context());
814     if (!bucketPointers)
815         return SymbolGroupValueVector();
816     // Get list of buckets (starting elements of 'QHashData::Node')
817     const std::string dummyNodeType = QtInfo::get(v.context()).prependQtCoreModule("QHashData::Node");
818     const SymbolGroupValueVector buckets = SymbolGroupValue::pointerSize() == 8 ?
819         hashBuckets(v.node()->symbolGroup(), dummyNodeType,
820                     reinterpret_cast<const ULONG64 *>(bucketPointers), numBuckets,
821                     ePtr, v.module(), v.context()) :
822         hashBuckets(v.node()->symbolGroup(), dummyNodeType,
823                     reinterpret_cast<const ULONG32 *>(bucketPointers), numBuckets,
824                     ULONG32(ePtr), v.module(), v.context());
825     delete [] bucketPointers ;
826     // Generate the list 'QHashData::Node *' by iterating over the linked list of
827     // nodes starting at each bucket. Using the 'QHashData::Node *' instead of
828     // the 'QHashNode<K,T>' is much faster. Each list has a trailing, unused
829     // dummy element. The initial element as such is skipped due to the pointer/value
830     // duality (since its 'next' element is identical to it when using typecast<> later on).
831     SymbolGroupValueVector dummyNodeList;
832     dummyNodeList.reserve(count);
833     bool notEnough = true;
834     const SymbolGroupValueVector::const_iterator ncend = buckets.end();
835     for (SymbolGroupValueVector::const_iterator it = buckets.begin(); notEnough && it != ncend; ++it) {
836         for (SymbolGroupValue l = *it; notEnough && l ; ) {
837             const SymbolGroupValue next = l["next"];
838             if (next && next.pointerValue()) { // Stop at trailing dummy element
839                 dummyNodeList.push_back(next);
840                 if (dummyNodeList.size() >= count) // Stop at maximum count
841                     notEnough = false;
842                 if (SymbolGroupValue::verbose > 1)
843                     DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next;
844                 l = next;
845             } else {
846                 break;
847             }
848         }
849     }
850     // Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive)
851     const std::string nodeType = qHashNodeType(v, "Node");
852     if (SymbolGroupValue::verbose)
853         DebugPrint() << "Converting into " << nodeType;
854     SymbolGroupValueVector nodeList;
855     nodeList.reserve(count);
856     const SymbolGroupValueVector::const_iterator dcend = dummyNodeList.end();
857     for (SymbolGroupValueVector::const_iterator it = dummyNodeList.begin(); it != dcend; ++it) {
858         if (const SymbolGroupValue n = (*it).typeCast(nodeType.c_str())) {
859             nodeList.push_back(n);
860         }  else {
861             return SymbolGroupValueVector();
862         }
863     }
864     return nodeList;
865 }
866
867 // QSet<>: Contains a 'QHash<key, QHashDummyValue>' as member 'q_hash'.
868 // Just dump the keys as an array.
869 static inline AbstractSymbolGroupNodePtrVector
870     qSetChildList(const SymbolGroupValue &v, int count)
871 {
872     const SymbolGroupValue qHash = v["q_hash"];
873     AbstractSymbolGroupNodePtrVector rc;
874     if (!count || !qHash)
875         return rc;
876     const SymbolGroupValueVector nodes = qHashNodes(qHash, count);
877     if (nodes.size() != VectorIndexType(count))
878         return rc;
879     rc.reserve(count);
880     for (int i = 0; i < count; i++) {
881         if (const SymbolGroupValue key = nodes.at(i)["key"]) {
882             rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, key.node()));
883         } else {
884             return AbstractSymbolGroupNodePtrVector();
885         }
886     }
887     return rc;
888 }
889
890 // QHash<>: Add with fake map nodes.
891 static inline AbstractSymbolGroupNodePtrVector
892     qHashChildList(const SymbolGroupValue &v, int count)
893 {
894     AbstractSymbolGroupNodePtrVector rc;
895     if (!count)
896         return rc;
897     const SymbolGroupValueVector nodes = qHashNodes(v, count);
898     if (nodes.size() != count)
899         return rc;
900     rc.reserve(count);
901     for (int i = 0; i < count; i++) {
902         const SymbolGroupValue &mapNode = nodes.at(i);
903         const SymbolGroupValue key = mapNode["key"];
904         const SymbolGroupValue value = mapNode["value"];
905         if (!key || !value)
906             return AbstractSymbolGroupNodePtrVector();
907         rc.push_back(MapNodeSymbolGroupNode::create(i, mapNode.address(),
908                                                     mapNode.type(), key.node(), value.node()));
909     }
910     return rc;
911 }
912
913 // QMap<>: Return the list of QMapData::Node
914 static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, VectorIndexType count)
915 {
916     const SymbolGroupValue e = v["e"];
917     const ULONG64 ePtr = e.pointerValue();
918     if (SymbolGroupValue::verbose)
919         DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
920     if (!ePtr)
921         return SymbolGroupValueVector();
922     if (SymbolGroupValue::verbose)
923         DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
924     SymbolGroupValueVector rc;
925     rc.reserve(count);
926     SymbolGroupValue n = e["forward"][unsigned(0)];
927     for (VectorIndexType i = 0; i < count && n && n.pointerValue() != ePtr; i++) {
928         rc.push_back(n);
929         n = n["forward"][unsigned(0)];
930     }
931     return rc;
932 }
933
934 // QMap<>: Add with fake map nodes.
935 static inline AbstractSymbolGroupNodePtrVector
936     qMapChildList(const SymbolGroupValue &v, VectorIndexType count)
937 {
938     if (SymbolGroupValue::verbose)
939         DebugPrint() << v.type() << "," << count;
940
941     if (!count)
942         return AbstractSymbolGroupNodePtrVector();
943     // Get node type: 'class namespace::QMap<K,T>'
944     // ->'QtCored4!namespace::QMapNode<K,T>'
945     // Note: Any types QMapNode<> will not be found without modules!
946     const std::string mapNodeType = qHashNodeType(v, "Node");
947     const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode");
948     // Calculate the offset needed (see QMap::concrete() used by the iterator).
949     const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str());
950     if (SymbolGroupValue::verbose) {
951         DebugPrint() << v.type() << "," << mapNodeType << ':'
952                      << mapPayloadNodeType << ':' << payloadNodeSize
953                      << ", pointerSize=" << SymbolGroupValue::pointerSize();
954     }
955     if (!payloadNodeSize)
956         return AbstractSymbolGroupNodePtrVector();
957     const ULONG64 payLoad  = payloadNodeSize - SymbolGroupValue::pointerSize();
958     // Get the value offset. Manually determine the alignment to be able
959     // to retrieve key/value without having to deal with QMapNode<> (see below).
960     // Subtract the 2 trailing pointers of the node.
961     const std::vector<std::string> innerTypes = v.innerTypes();
962     if (innerTypes.size() != 2u)
963         return AbstractSymbolGroupNodePtrVector();
964     const std::string keyType = fixInnerType(innerTypes.front(), v);
965     const std::string valueType = fixInnerType(innerTypes.at(1), v);
966     const unsigned valueSize = SymbolGroupValue::sizeOf(valueType.c_str());
967     const unsigned valueOffset = SymbolGroupValue::fieldOffset(mapNodeType.c_str(), "value");
968     if (SymbolGroupValue::verbose)
969         DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ','
970                      << innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize;
971     if (!valueOffset || !valueSize)
972         return AbstractSymbolGroupNodePtrVector();
973     // Get the children.
974     const SymbolGroupValueVector childNodes = qMapNodes(v, count);
975     if (SymbolGroupValue::verbose)
976         DebugPrint() << "children: " << childNodes.size() << " of " << count;
977     // Deep  expansion of the forward[0] sometimes fails. In that case,
978     // take what we can get.
979     if (childNodes.size() != count)
980         count = childNodes.size();
981     // The correct way of doing this would be to construct additional symbols
982     // '*(QMapNode<K,V> *)(node_address)'. However, when doing this as of
983     // 'CDB 6.12.0002.633' (21.12.2010) IDebugSymbolGroup::AddSymbol()
984     // just fails, returning DEBUG_ANY_ID without actually doing something. So,
985     // we circumvent the map nodes and directly create key and values at their addresses.
986     AbstractSymbolGroupNodePtrVector rc;
987     rc.reserve(count);
988     std::string errorMessage;
989     SymbolGroup *sg = v.node()->symbolGroup();
990     for (VectorIndexType i = 0; i < count ; i++) {
991         const ULONG64 nodePtr = childNodes.at(i).pointerValue();
992         if (!nodePtr)
993             return AbstractSymbolGroupNodePtrVector();
994         const ULONG64 keyAddress = nodePtr - payLoad;
995         const std::string keyExp = SymbolGroupValue::pointedToSymbolName(keyAddress, keyType);
996         const std::string valueExp = SymbolGroupValue::pointedToSymbolName(keyAddress + valueOffset, valueType);
997         if (SymbolGroupValue::verbose) {
998             DebugPrint() << '#' << i << '/' << count << ' ' << std::hex << ",node=0x" << nodePtr <<
999                   ',' <<keyExp << ',' << valueExp;
1000         }
1001         // Create the nodes
1002         SymbolGroupNode *keyNode = sg->addSymbol(v.module(), keyExp, std::string(), &errorMessage);
1003         SymbolGroupNode *valueNode = sg->addSymbol(v.module(), valueExp, std::string(), &errorMessage);
1004         if (!keyNode || !valueNode)
1005             return AbstractSymbolGroupNodePtrVector();
1006         rc.push_back(MapNodeSymbolGroupNode::create(int(i), keyAddress,
1007                                                     mapNodeType, keyNode, valueNode));
1008     }
1009     return rc;
1010 }
1011
1012 /*! Determine children of containers \ingroup qtcreatorcdbext */
1013 AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int type,
1014                                                    int size, const SymbolGroupValueContext &ctx)
1015 {
1016     if (SymbolGroupValue::verbose) {
1017         DebugPrint dp;
1018         dp << "containerChildren " << node->name() << '/' << node->iName() << '/' << node->type()
1019            << " at 0x" << std::hex << node->address() << std::dec
1020            << " count=" << size << ",knowntype=" << type << " [";
1021         formatKnownTypeFlags(dp, static_cast<KnownType>(type));
1022         dp << ']';
1023     }
1024     if (!size)
1025         return AbstractSymbolGroupNodePtrVector();
1026     if (size > 100)
1027         size = 100;
1028     switch (type) {
1029     case KT_QVector:
1030         return qVectorChildList(node, size, ctx);
1031     case KT_StdVector:
1032         return stdVectorChildList(node, size, ctx);
1033     case KT_QLinkedList:
1034         return qLinkedListChildList(node, size, ctx);
1035     case KT_QList:
1036         return qListChildList(SymbolGroupValue(node, ctx), size);
1037     case KT_QQueue:
1038         if (const SymbolGroupValue qList = SymbolGroupValue(node, ctx)[unsigned(0)])
1039             return qListChildList(qList, size);
1040         break;
1041     case KT_QStack:
1042         if (const SymbolGroupValue qVector = SymbolGroupValue(node, ctx)[unsigned(0)])
1043             return qVectorChildList(qVector.node(), size, ctx);
1044         break;
1045     case KT_QHash:
1046         return qHashChildList(SymbolGroupValue(node, ctx), size);
1047     case KT_QMultiHash:
1048         if (const SymbolGroupValue hash = SymbolGroupValue(node, ctx)[unsigned(0)])
1049             return qHashChildList(hash, size);
1050         break;
1051     case KT_QSet:
1052         return qSetChildList(SymbolGroupValue(node, ctx), size);
1053     case KT_QMap:
1054         return qMapChildList(SymbolGroupValue(node, ctx), size);
1055     case KT_QMultiMap:
1056         if (const SymbolGroupValue qmap = SymbolGroupValue(node, ctx)[unsigned(0)])
1057             return qMapChildList(qmap, size);
1058         break;
1059     case KT_QStringList:
1060         if (const SymbolGroupValue qList = SymbolGroupValue(node, ctx)[unsigned(0)])
1061             return qListChildList(qList, size);
1062         break;
1063     case KT_StdList:
1064         return stdListChildList(node, size , ctx);
1065     case KT_StdDeque:
1066         return stdDequeChildList(SymbolGroupValue(node, ctx), size);
1067     case KT_StdStack:
1068         if (const SymbolGroupValue deque = SymbolGroupValue(node, ctx)[unsigned(0)])
1069             return stdDequeChildList(deque, size);
1070         break;
1071     case KT_StdSet:
1072         return stdSetChildList(SymbolGroupValue(node, ctx), size);
1073     case KT_StdMap:
1074     case KT_StdMultiMap:
1075         return stdMapChildList(SymbolGroupValue(node, ctx), size);
1076     }
1077     return AbstractSymbolGroupNodePtrVector();
1078 }