clayborg created this revision.
clayborg added reviewers: labath, teemperor, aprantl.
Herald added subscribers: usaxena95, arphaman.
clayborg requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This allows us to see the contents of the SmallVector just like std::vector and 
also adds a summary string that shows the size of the array.

For llvm::Optional, the value will show as llvm::None when it has no value, or 
it will show the value of the type T.

For llvm::Error or, it will show the std::error_code as a structure or the 
value if it has a value.

For llvm::Expected, it will show the dynamic classname of the contained error, 
or the value.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D116113

Files:
  clang/utils/ClangDataFormat.py

Index: clang/utils/ClangDataFormat.py
===================================================================
--- clang/utils/ClangDataFormat.py
+++ clang/utils/ClangDataFormat.py
@@ -22,140 +22,408 @@
 import lldb
 
 def __lldb_init_module(debugger, internal_dict):
-	debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
-	debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType")
-	debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.Optional_summary -x 'llvm::Optional<.*>'")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.SmallVector_summary -x 'llvm::SmallVector<.*>'")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.Expected_summary -x 'llvm::Expected<.*>'")
+    debugger.HandleCommand("type summary add -F ClangDataFormat.ErrorOr_summary -x 'llvm::ErrorOr<.*>'")
+    debugger.HandleCommand("type synthetic add -l ClangDataFormat.Optional -x 'llvm::Optional<.*>'")
+    debugger.HandleCommand("type synthetic add -l ClangDataFormat.SmallVector -x 'llvm::SmallVector<.*>'")
+    debugger.HandleCommand("type synthetic add -l ClangDataFormat.Expected -x 'llvm::Expected<.*>'")
+    debugger.HandleCommand("type synthetic add -l ClangDataFormat.ErrorOr -x 'llvm::ErrorOr<.*>'")
 
-def SourceLocation_summary(srcloc, internal_dict):
-	return SourceLocation(srcloc).summary()
+def SourceLocation_summary(valobj, internal_dict):
+    return SourceLocation(valobj).summary()
 
-def QualType_summary(qualty, internal_dict):
-	return QualType(qualty).summary()
+def QualType_summary(valobj, internal_dict):
+    return QualType(valobj).summary()
 
-def StringRef_summary(strref, internal_dict):
-	return StringRef(strref).summary()
+def StringRef_summary(valobj, internal_dict):
+    return StringRef(valobj).summary()
+
+def Optional_summary(valobj, internal_dict):
+    return Optional(valobj, internal_dict).summary()
+
+def SmallVector_summary(valobj, internal_dict):
+    return SmallVector(valobj, internal_dict).summary()
+
+def Expected_summary(valobj, internal_dict):
+    return Expected(valobj, internal_dict).summary()
+
+def ErrorOr_summary(valobj, internal_dict):
+    return ErrorOr(valobj, internal_dict).summary()
 
 class SourceLocation(object):
-	def __init__(self, srcloc):
-		self.srcloc = srcloc
-		self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned()
-		self.frame = srcloc.GetFrame()
-	
-	def offset(self):
-		return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
-
-	def isInvalid(self):
-		return self.ID == 0
-
-	def isMacro(self):
-		return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
-
-	def isLocal(self, srcmgr_path):
-		return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned()
-
-	def getPrint(self, srcmgr_path):
-		print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
-		return print_str.GetSummary()
-
-	def summary(self):
-		if self.isInvalid():
-			return "<invalid loc>"
-		srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame)
-		if srcmgr_path:
-			return "%s (offset: %d, %s, %s)" % (self.getPrint(srcmgr_path), self.offset(), "macro" if self.isMacro() else "file", "local" if self.isLocal(srcmgr_path) else "loaded")
-		return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
+    def __init__(self, srcloc):
+        self.srcloc = srcloc
+        self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned()
+        self.frame = srcloc.GetFrame()
+
+    def offset(self):
+        return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
+
+    def isInvalid(self):
+        return self.ID == 0
+
+    def isMacro(self):
+        return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
+
+    def isLocal(self, srcmgr_path):
+        return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned()
+
+    def getPrint(self, srcmgr_path):
+        print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
+        return print_str.GetSummary()
+
+    def summary(self):
+        if self.isInvalid():
+            return "<invalid loc>"
+        srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame)
+        if srcmgr_path:
+            return "%s (offset: %d, %s, %s)" % (self.getPrint(srcmgr_path), self.offset(), "macro" if self.isMacro() else "file", "local" if self.isLocal(srcmgr_path) else "loaded")
+        return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
 
 class QualType(object):
-	def __init__(self, qualty):
-		self.qualty = qualty
+    def __init__(self, qualty):
+        self.qualty = qualty
 
-	def getAsString(self):
-		std_str = getValueFromExpression(self.qualty, ".getAsString()")
-		return std_str.GetSummary()
+    def getAsString(self):
+        std_str = getValueFromExpression(self.qualty, ".getAsString()")
+        return std_str.GetSummary()
 
-	def summary(self):
-		desc = self.getAsString()
-		if desc == '"NULL TYPE"':
-			return "<NULL TYPE>"
-		return desc
+    def summary(self):
+        desc = self.getAsString()
+        if desc == '"NULL TYPE"':
+            return "<NULL TYPE>"
+        return desc
 
 class StringRef(object):
-	def __init__(self, strref):
-		self.strref = strref
-		self.Data_value = strref.GetChildAtIndex(0)
-		self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned()
-
-	def summary(self):
-		if self.Length == 0:
-			return '""'
-		data = self.Data_value.GetPointeeData(0, self.Length)
-		error = lldb.SBError()
-		string = data.ReadRawData(error, 0, data.GetByteSize())
-		if error.Fail():
-			return None
-		return '"%s"' % string
+    def __init__(self, strref):
+        self.strref = strref
+        self.Data_value = strref.GetChildAtIndex(0)
+        self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned()
 
+    def summary(self):
+        if self.Length == 0:
+            return '""'
+        data = self.Data_value.GetPointeeData(0, self.Length)
+        error = lldb.SBError()
+        string = data.ReadRawData(error, 0, data.GetByteSize())
+        if error.Fail():
+            return None
+        return '"%s"' % string
 
 # Key is a (function address, type name) tuple, value is the expression path for
 # an object with such a type name from inside that function.
 FramePathMapCache = {}
 
 def findObjectExpressionPath(typename, frame):
-	func_addr = frame.GetFunction().GetStartAddress().GetFileAddress()
-	key = (func_addr, typename)
-	try:
-		return FramePathMapCache[key]
-	except KeyError:
-		#print "CACHE MISS"
-		path = None
-		obj = findObject(typename, frame)
-		if obj:
-			path = getExpressionPath(obj)
-		FramePathMapCache[key] = path
-		return path
+    func_addr = frame.GetFunction().GetStartAddress().GetFileAddress()
+    key = (func_addr, typename)
+    try:
+        return FramePathMapCache[key]
+    except KeyError:
+        #print "CACHE MISS"
+        path = None
+        obj = findObject(typename, frame)
+        if obj:
+            path = getExpressionPath(obj)
+        FramePathMapCache[key] = path
+        return path
 
 def findObject(typename, frame):
-	def getTypename(value):
-		# FIXME: lldb should provide something like getBaseType
-		ty = value.GetType()
-		if ty.IsPointerType() or ty.IsReferenceType():
-			return ty.GetPointeeType().GetName()
-		return ty.GetName()
-
-	def searchForType(value, searched):
-		tyname = getTypename(value)
-		#print "SEARCH:", getExpressionPath(value), value.GetType().GetName()
-		if tyname == typename:
-			return value
-		ty = value.GetType()
-		if not (ty.IsPointerType() or
-		        ty.IsReferenceType() or
-				# FIXME: lldb should provide something like getCanonicalType
-		        tyname.startswith("llvm::IntrusiveRefCntPtr<") or
-		        tyname.startswith("llvm::OwningPtr<")):
-			return None
-		# FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead,
-		# and not the canonical one unfortunately.
-		if tyname in searched:
-			return None
-		searched.add(tyname)
-		for i in range(value.GetNumChildren()):
-			child = value.GetChildAtIndex(i, 0, False)
-			found = searchForType(child, searched)
-			if found:
-				return found
-
-	searched = set()
-	value_list = frame.GetVariables(True, True, True, True)
-	for val in value_list:
-		found = searchForType(val, searched)
-		if found:
-			return found if not found.TypeIsPointerType() else found.Dereference()
+    def getTypename(value):
+        # FIXME: lldb should provide something like getBaseType
+        ty = value.GetType()
+        if ty.IsPointerType() or ty.IsReferenceType():
+            return ty.GetPointeeType().GetName()
+        return ty.GetName()
+
+    def searchForType(value, searched):
+        tyname = getTypename(value)
+        #print "SEARCH:", getExpressionPath(value), value.GetType().GetName()
+        if tyname == typename:
+            return value
+        ty = value.GetType()
+        if not (ty.IsPointerType() or
+                ty.IsReferenceType() or
+                # FIXME: lldb should provide something like getCanonicalType
+                tyname.startswith("llvm::IntrusiveRefCntPtr<") or
+                tyname.startswith("llvm::OwningPtr<")):
+            return None
+        # FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead,
+        # and not the canonical one unfortunately.
+        if tyname in searched:
+            return None
+        searched.add(tyname)
+        for i in range(value.GetNumChildren()):
+            child = value.GetChildAtIndex(i, 0, False)
+            found = searchForType(child, searched)
+            if found:
+                return found
+
+    searched = set()
+    value_list = frame.GetVariables(True, True, True, True)
+    for val in value_list:
+        found = searchForType(val, searched)
+        if found:
+            return found if not found.TypeIsPointerType() else found.Dereference()
 
 def getValueFromExpression(val, expr):
-	return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr)
+    return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr)
 
 def getExpressionPath(val):
-	stream = lldb.SBStream()
-	val.GetExpressionPath(stream)
-	return stream.GetData()
+    stream = lldb.SBStream()
+    val.GetExpressionPath(stream)
+    return stream.GetData()
+
+class Optional(object):
+    def __init__(self, valobj, internal_dict):
+        # We use this class for both the synthetic children and for the summary.
+        # For the summary, we will be given the synthetic lldb.SBValue so we
+        # must make sure to get the non-synthetic lldb.SBValue.
+        self.valobj = valobj.GetNonSyntheticValue()
+        self.update()
+
+    def summary(self):
+        self.update()
+        if not self.hasVal:
+            return "llvm::None"
+        summary = self.value.GetSummary()
+        if summary:
+            return summary
+        return ""
+
+    def update(self):
+        storage = self.valobj.GetChildMemberWithName('Storage')
+        self.hasVal = storage.GetChildMemberWithName('hasVal').GetValueAsUnsigned(0)
+        self.value = storage.GetChildMemberWithName('value')
+        # Return false to make sure we always update this object every time we
+        # stop. If we return True, then the value will never update again.
+        return False
+
+    def num_children(self):
+        # If we have a value we get the number of children from our contained
+        # value, else we have no children.
+        if self.hasVal:
+            return self.value.GetNumChildren()
+        return 0
+
+    def get_child_index(self, name):
+        if self.hasVal:
+            result = self.value.GetIndexOfChildWithName(name)
+            return None if result == 4294967295 else result
+        return None
+
+    def get_child_at_index(self, index):
+        if self.hasVal:
+            return self.value.GetChildAtIndex(index)
+        return None
+
+    def has_children(self):
+        return self.value.MightHaveChildren()
+
+    def get_value(self):
+        # this call can return an SBValue to be presented as the value of the
+        # synthetic value under consideration.[3]
+        if self.hasVal:
+            return self.value
+        return None
+
+class SmallVector(object):
+    def __init__(self, valobj, internal_dict):
+        # We use this class for both the synthetic children and for the summary.
+        # For the summary, we will be given the synthetic lldb.SBValue so we
+        # must make sure to get the non-synthetic lldb.SBValue.
+        self.valobj = valobj.GetNonSyntheticValue()
+        type = self.valobj.GetType().GetUnqualifiedType()
+        if type.IsReferenceType():
+            type = type.GetDereferencedType()
+        if type.GetNumberOfTemplateArguments() > 0:
+            self.type = type.GetTemplateArgumentType(0)
+        else:
+            self.type = lldb.SBType()
+        self.element_size = self.type.GetByteSize()
+        self.ptr = lldb.SBValue()
+        self.size = 0
+        self.update()
+
+    def summary(self):
+        self.update()
+        return 'size=%u' % (self.size)
+
+    def update(self):
+        self.ptr = self.valobj.GetChildMemberWithName('BeginX')
+        self.size = self.valobj.GetChildMemberWithName('Size').GetValueAsUnsigned()
+        # Return false to make sure we always update this object every time we
+        # stop. If we return True, then the value will never update again.
+        return False
+
+    def num_children(self):
+        return self.size
+
+    def get_child_index(self, name):
+        try:
+            return int(name.lstrip('[').rstrip(']'))
+        except:
+            return -1
+
+    def get_child_at_index(self, index):
+        return self.ptr.CreateChildAtOffset( '[' + str(index) + ']', self.element_size * index, self.type)
+
+    def has_children(self):
+        return True
+
+class Expected(object):
+    def __init__(self, valobj, internal_dict):
+        # We use this class for both the synthetic children and for the summary.
+        # For the summary, we will be given the synthetic lldb.SBValue so we
+        # must make sure to get the non-synthetic lldb.SBValue.
+        self.valobj = valobj.GetNonSyntheticValue()
+        value_type = self.valobj.GetType().GetUnqualifiedType()
+        if value_type.IsReferenceType():
+            value_type = value_type.GetDereferencedType()
+        if value_type.GetNumberOfTemplateArguments() > 0:
+            self.value_type = value_type.GetTemplateArgumentType(0)
+        else:
+            self.value_type = lldb.SBType()
+        self.error_type = valobj.GetTarget().FindFirstType('llvm::ErrorInfoBase').GetPointerType()
+        self.hasError = lldb.SBValue()
+        self.value = lldb.SBValue()
+        self.update()
+
+    def summary(self):
+        # If we have an error the value for "self.value" will return the
+        # llvm::ErrorInfoBase pointer as the value so we append the error
+        # typename which will be dynamically figured out at runtime. So the
+        # value and the summary will look like:
+        #
+        #   0x0000600001705880 (llvm::StringError *)
+        #
+        # If we have no error, then we still will display the typename in parens
+        # after the value if the type T has a value or alone if it doesn't.
+        self.update()
+        return "(%s)" % (self.value.GetType().GetDisplayTypeName())
+
+    def update(self):
+        # Here we figure out if we have an error here and then we cast the value
+        # in the "ErrorStorage.buffer" to the error type, or we cast the
+        # "TStorage.buffer" to the value type and set "self.value" to the
+        # correct value.
+        self.hasError = self.valobj.GetChildMemberWithName('HasError').GetValueAsUnsigned() != 0
+        if self.hasError:
+            self.value = self.valobj.GetChildMemberWithName('ErrorStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Error', 0, self.error_type)
+        else:
+            self.value = self.valobj.GetChildMemberWithName('TStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Value', 0, self.value_type)
+        # Return false to make sure we always update this object every time we
+        # stop. If we return True, then the value will never update again.
+        return False
+
+    def num_children(self):
+        # We compute the right value to use as the lldb.SBValue to use in
+        # self.value in the update() method so we can just use that object to
+        # get our asnwers
+        return self.value.GetNumChildren()
+
+    def get_child_index(self, name):
+        # We compute the right value to use as the lldb.SBValue to use in
+        # self.value in the update() method so we can just use that object to
+        # get our asnwers
+        result = self.value.GetIndexOfChildWithName(name)
+        return None if result == 4294967295 else result
+
+    def get_child_at_index(self, index):
+        # We compute the right value to use as the lldb.SBValue to use in
+        # self.value in the update() method so we can just use that object to
+        # get our asnwers
+        return self.value.GetChildAtIndex(index)
+
+    def has_children(self):
+        # We always return true to ensure we can expand this variable as the
+        # Expected<T> might start out uninitialized and then change to be
+        # initialized. If the T value can be expanded, the user can try. If the
+        # object contains an error, then we can always expand this item to show
+        # its children.
+        return self.value.MightHaveChildren()
+
+    def get_value(self):
+        # We compute the right value to use as the lldb.SBValue to display in
+        # self.value in the update() method so we can just return that here.
+        return self.value
+
+
+class ErrorOr(object):
+    def __init__(self, valobj, internal_dict):
+        # We use this class for both the synthetic children and for the summary.
+        # For the summary, we will be given the synthetic lldb.SBValue so we
+        # must make sure to get the non-synthetic lldb.SBValue.
+        self.valobj = valobj.GetNonSyntheticValue()
+        value_type = self.valobj.GetType().GetUnqualifiedType()
+        if value_type.IsReferenceType():
+            value_type = value_type.GetDereferencedType()
+        if value_type.GetNumberOfTemplateArguments() > 0:
+            self.value_type = value_type.GetTemplateArgumentType(0)
+        else:
+            self.value_type = lldb.SBType()
+        target = valobj.GetTarget()
+        self.error_type = target.FindFirstType('std::__1::error_code')
+        if not self.error_type.IsValid():
+            self.error_type = target.FindFirstType('std::error_code').GetPointerType()
+        self.hasError = lldb.SBValue()
+        self.value = lldb.SBValue()
+        self.update()
+
+    def summary(self):
+        # Display the typename for the std::error_code or for the value in
+        # parens so we can tell the difference between an ErroOr object in an
+        # error state of when it contains a value.
+        self.update()
+        return "(%s)" % (self.value.GetType().GetDisplayTypeName())
+
+    def update(self):
+        # Here we figure out if we have an error here and then we cast the value
+        # in the "ErrorStorage.buffer" to the error type, or we cast the
+        # "TStorage.buffer" to the value type and set "self.value" to the
+        # correct value.
+        self.hasError = self.valobj.GetChildMemberWithName('HasError').GetValueAsUnsigned() != 0
+        if self.hasError:
+            self.value = self.valobj.GetChildMemberWithName('ErrorStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Error', 0, self.error_type)
+        else:
+            self.value = self.valobj.GetChildMemberWithName('TStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Value', 0, self.value_type)
+        # Return false to make sure we always update this object every time we
+        # stop. If we return True, then the value will never update again.
+        return False
+
+    def num_children(self):
+        # We compute the right value to use as the lldb.SBValue to use in
+        # self.value in the update() method so we can just use that object to
+        # get our asnwers
+        return self.value.GetNumChildren()
+
+    def get_child_index(self, name):
+        # We compute the right value to use as the lldb.SBValue to use in
+        # self.value in the update() method so we can just use that object to
+        # get our asnwers
+        result = self.value.GetIndexOfChildWithName(name)
+        return None if result == 4294967295 else result
+
+    def get_child_at_index(self, index):
+        # We compute the right value to use as the lldb.SBValue to use in
+        # self.value in the update() method so we can just use that object to
+        # get our asnwers
+        return self.value.GetChildAtIndex(index)
+
+    def has_children(self):
+        # We always return true to ensure we can expand this variable as the
+        # Expected<T> might start out uninitialized and then change to be
+        # initialized. If the T value can be expanded, the user can try. If the
+        # object contains an error, then we can always expand this item to show
+        # its children.
+        return self.value.MightHaveChildren()
+
+    def get_value(self):
+        # We compute the right value to use as the lldb.SBValue to display in
+        # self.value in the update() method so we can just return that here.
+        return self.value
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to