<rdar://problem/12523238> Commit 1 of 3
This commit enables the new HasChildren() feature for synthetic children providers
Namely, it hooks up the required bits and pieces so that individual synthetic children providers can implement a new (optional) has_children call
Default implementations have been provided where necessary so that any existing providers continue to work and behave correctly

Next steps are:
2) writing smart implementations of has_children for our providers whenever possible
3) make a test case



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@166495 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/scripts/Python/python-wrapper.swig b/scripts/Python/python-wrapper.swig
index a3aeefb..199cc63 100644
--- a/scripts/Python/python-wrapper.swig
+++ b/scripts/Python/python-wrapper.swig
@@ -418,12 +418,76 @@
         Py_RETURN_NONE;
 }
 
-/*
-these four calls below are meant to support
-Python-based synthetic children providers
-they essentially mimic the four pure virtual
-method calls provided by the frontend class
-*/
+// wrapper that calls an optional instance member of an object taking no arguments
+static PyObject*
+LLDBSwigPython_CallOptionalMember
+(
+    PyObject* self,
+    char* callee_name,
+    PyObject* ret_if_not_found = Py_None,
+    bool* was_found = NULL
+)
+{
+    if (self == NULL || self == Py_None)
+    {
+        if (was_found)
+            *was_found = false;
+        Py_XINCREF(ret_if_not_found);
+        return ret_if_not_found;
+    }
+
+    PyObject* pmeth  = PyObject_GetAttrString(self, callee_name);
+
+    if (PyErr_Occurred())
+    {
+        PyErr_Clear();
+    }
+
+    if (pmeth == NULL || pmeth == Py_None)
+    {
+        if (was_found)
+            *was_found = false;
+        Py_XDECREF(pmeth);
+        Py_XINCREF(ret_if_not_found);
+        return ret_if_not_found;
+    }
+
+    if (PyCallable_Check(pmeth) == 0)
+    {
+        if (PyErr_Occurred())
+        {
+            PyErr_Clear();
+        }
+
+        Py_XDECREF(pmeth);
+        if (was_found)
+            *was_found = false;
+        Py_XINCREF(ret_if_not_found);
+        return ret_if_not_found;
+    }
+
+    if (was_found)
+        *was_found = true;
+
+    if (PyErr_Occurred())
+    {
+        PyErr_Clear();
+    }
+
+    Py_XDECREF(pmeth);
+
+    // right now we know this function exists and is callable..
+    PyObject* py_return = PyObject_CallMethod(self, callee_name, NULL);
+    
+    // if it fails, print the error but otherwise go on
+    if (PyErr_Occurred())
+    {
+        PyErr_Print();
+        PyErr_Clear();
+    }
+    
+    return py_return;
+}
 
 SWIGEXPORT uint32_t
 LLDBSwigPython_CalculateNumChildren
@@ -431,33 +495,27 @@
     PyObject *implementor
 )
 {
+    uint32_t ret_val = UINT32_MAX;
 
     static char callee_name[] = "num_children";
 
-    if (implementor == NULL || implementor == Py_None)
-        return 0;
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
-    if (PyErr_Occurred())
-    {
-        PyErr_Print();
-        PyErr_Clear();
-    }
+    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name, NULL);
 
-    if (py_return == NULL || py_return == Py_None)
-    {
-        Py_XDECREF(py_return);
-        return UINT32_MAX;
-    }
-    long retval = PyInt_AsLong(py_return);
-    Py_DECREF(py_return);
-    if (retval >= 0)
-        return (uint32_t)retval;
+    if (!py_return)
+        return ret_val;
+
+    if (PyInt_Check(py_return))
+        ret_val = PyInt_AsLong(py_return);
+
+    Py_XDECREF(py_return);
+    
     if (PyErr_Occurred())
     {
         PyErr_Print();
         PyErr_Clear();
     }
-    return 0;
+    
+    return ret_val;
 }
 
 SWIGEXPORT PyObject*
@@ -542,64 +600,38 @@
     PyObject *implementor
 )
 {
-
     bool ret_val = false;
 
     static char callee_name[] = "update";
 
-    if (implementor == NULL || implementor == Py_None)
-        return ret_val;
+    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name);
 
-    // all this code is here because update is optional, so we don't want to bother trying to call it unless it's been def:ined for us
-    // other synth provider calls are mandatory, so we want to fail in a very obvious way if they are missing!
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-
-    if (PyErr_Occurred())
-    {
-        PyErr_Clear();
-    }
-
-    if (pmeth == NULL || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
-        return ret_val;
-    }
-
-    if (PyCallable_Check(pmeth) == 0)
-    {
-        if (PyErr_Occurred())
-        {
-            PyErr_Clear();
-        }
-
-        Py_XDECREF(pmeth);
-        return ret_val;
-    }
-
-    if (PyErr_Occurred())
-    {
-        PyErr_Clear();
-    }
-
-    Py_XDECREF(pmeth);
-
-    // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
-    
-    // if it fails, print the error but otherwise go on
-    if (PyErr_Occurred())
-    {
-        PyErr_Print();
-        PyErr_Clear();
-    }
-    
     if (py_return == Py_True)
         ret_val = true;
 
     Py_XDECREF(py_return);
     
     return ret_val;
+}
 
+SWIGEXPORT bool
+LLDBSwigPython_MightHaveChildrenSynthProviderInstance
+(
+    PyObject *implementor
+)
+{
+    bool ret_val = false;
+
+    static char callee_name[] = "has_children";
+
+    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name, Py_True);
+
+    if (py_return == Py_True)
+        ret_val = true;
+
+    Py_XDECREF(py_return);
+    
+    return ret_val;
 }
 
 SWIGEXPORT void*