From d37e890a1de14e2d730027f7163edaaf46f7fdb6 Mon Sep 17 00:00:00 2001
From: hjk <hjk121@nokiamail.com>
Date: Tue, 28 Jan 2014 23:23:01 +0100
Subject: [PATCH] Debugger: Show name also for QObject subclasses without
 Q_OBJECT macro

Change-Id: Ifabf3cc68751a06c15fc1a5a05cad5e5a64c8775
Reviewed-by: hjk <hjk121@nokiamail.com>
---
 share/qtcreator/debugger/dumper.py    |  8 ++--
 share/qtcreator/debugger/gdbbridge.py | 61 +++++++++++++++++----------
 share/qtcreator/debugger/qttypes.py   |  2 +-
 tests/auto/debugger/tst_dumpers.cpp   |  2 +-
 4 files changed, 43 insertions(+), 30 deletions(-)

diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index cd57ad04332..d78a535ccee 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -312,8 +312,9 @@ class DumperBase:
         # This keeps canonical forms of the typenames, without array indices etc.
         self.cachedFormats = {}
 
-        self.knownQObjectTypes = set()
-        self.knownNonQObjectTypes = set()
+        # Maps type names to static metaobjects. If a type is known
+        # to not be QObject derived, it contains a 0 value.
+        self.knownStaticMetaObjects = {}
 
 
     def stripForFormat(self, typeName):
@@ -854,8 +855,6 @@ class DumperBase:
                     self.putItem(value.dereference())
 
     def putQObjectNameValue(self, value):
-        if str(value.type) in self.knownNonQObjectTypes:
-            return
         try:
             intSize = self.intSize()
             ptrSize = self.ptrSize()
@@ -910,7 +909,6 @@ class DumperBase:
 
         except:
             #warn("NO QOBJECT: %s" % value.type)
-            #self.knownNonQObjectTypes.add(str(value.type))
             pass
 
 
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index 41795ab32ef..a0b1d21753d 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -970,32 +970,48 @@ class Dumper(DumperBase):
     def dereferenceValue(self, value):
         return toInteger(value.cast(self.voidPtrType()))
 
-    def isQObject(self, value):
-        typeName = str(value.type)
-        if typeName in self.knownQObjectTypes:
-            return True
-        if typeName in self.knownNonQObjectTypes:
-            return False
+    def extractStaticMetaObjectHelper(self, typeobj):
+        """
+        Checks whether type has a Q_OBJECT macro.
+        Returns the staticMetaObject, or 0.
+        """
+        typeName = str(typeobj)
+        result = self.knownStaticMetaObjects.get(typeName, None)
+        if result is not None: # Is 0 or the static metaobject.
+            return result
 
-        smo = typeName + "::staticMetaObject"
+        staticMetaObjectName = typeName + "::staticMetaObject"
         try:
-            result = gdb.lookup_global_symbol(smo)
-            if result:
-                self.knownQObjectTypes.add(typeName)
-            else:
-                self.knownNonQObjectTypes.add(typeName)
+            result = gdb.lookup_global_symbol(staticMetaObjectName)
+            result = result.value() if result else 0
+            self.knownStaticMetaObjects[typeName] = result
             return result
         except:
             pass
 
         # Older GDB...
         try:
-            gdb.parse_and_eval(smo)
-            self.knownQObjectTypes.add(typeName)
-            return True
+            result = gdb.parse_and_eval(staticMetaObjectName)
+            self.knownStaticMetaObjects[typeName] = result
+            return result
         except:
-            self.knownNonQObjectTypes.add(typeName)
-            return False
+            self.knownStaticMetaObjects[typeName] = 0
+            return 0
+
+    def extractStaticMetaObject(self, typeobj):
+        """
+        Checks recursively whether a type derives from QObject.
+        """
+        result = self.extractStaticMetaObjectHelper(typeobj)
+        if result:
+            return result
+        fields = typeobj.fields()
+        if not len(fields):
+            return 0
+        if not fields[0].is_base_class:
+            return 0
+        return self.extractStaticMetaObject(fields[0].type)
+
 
     def put(self, value):
         self.output.append(value)
@@ -1401,9 +1417,9 @@ class Dumper(DumperBase):
         #warn("INAME: %s " % self.currentIName)
         #warn("INAMES: %s " % self.expandedINames)
         #warn("EXPANDED: %s " % (self.currentIName in self.expandedINames))
-        isQObject = self.isQObject(value)
-        if isQObject:
-            self.putQObjectNameValue(value)  # Is this too expensive?
+        staticMetaObject = self.extractStaticMetaObject(value.type)
+        if staticMetaObject:
+            self.putQObjectNameValue(value)
         self.putType(typeName)
         self.putEmptyValue()
         self.putNumChild(len(type.fields()))
@@ -1412,9 +1428,8 @@ class Dumper(DumperBase):
             innerType = None
             with Children(self, 1, childType=innerType):
                 self.putFields(value)
-                if isQObject:
-                    smo = value["staticMetaObject"]
-                    self.putQObjectGuts(value, smo)
+                if staticMetaObject:
+                    self.putQObjectGuts(value, staticMetaObject)
 
 
     def putPlainChildren(self, value):
diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py
index d8148ab9cb9..7bb6256e660 100644
--- a/share/qtcreator/debugger/qttypes.py
+++ b/share/qtcreator/debugger/qttypes.py
@@ -1136,7 +1136,7 @@ def qdump__QMetaObject(d, value):
             d.putIntItem("flags", d.extractInt(data + 48))
             d.putIntItem("signalCount", d.extractInt(data + 52))
 
-def qdump__QObject(d, value):
+def _qdump__QObject(d, value):
     d.putQObjectNameValue(value)
     ns = d.qtNamespace()
 
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index 926d4acdde3..c0cf5a45b29 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -5048,7 +5048,7 @@ void tst_Dumpers::dumper_data()
                 "file.setObjectName(\"A file\");\n")
          % CoreProfile()
          % QtVersion(50000)
-         % Check("file", "", "MyFile")
+         % Check("file", "\"A file\"", "MyFile")
          % Check("file.@1", "[@QFile]", "\"/tmp/tt\"", "@QFile");
         // FIXME: The classname in the iname is sub-optimal.
          //% Check("file.@1.[QFileDevice]", "[@QFileDevice]", "\"A file\"", "@QFileDevice");
-- 
GitLab