If I have std::vector<int>* variable, the summary string provided by frame variable vp doesn’t have the raw pointer value, because it’s disabled for libcxx and libstdcxx. Though users can still see the raw pointer value with -R option, it would be nice if the raw pointer value is shown along with the summary string.
Is there a specific reason to set hiding the value for libcxx and libstdcxx type summary? Should we flip the flag?
You register the formatter against the std::vector type, and when constructing the summary of a std::vector you definitely don’t want to show the value. That would be all the actual fields of the std::vector class, which users don’t want to see, they want to see the number of elements of the vector.
But the same summary formatter also will format pointers to std::vector, and in that case, while you still don’t want to show the value of the formatted type, just the size, you do want to see the pointer value.
However, that seems to be what we do. I haven’t gone to look at where we do this in code, but when I stop in a frame with a std::vector *, I do see the pointer value:
(lldb) run
Process 50298 launched: '/tmp/vectors' (arm64)
Process 50298 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00000001000004f8 vectors`take_vector(vec_ptr=0x000000016fdfedd8 size=4) at vectors.cpp:6:18
3
4 void
5 take_vector(std::vector<int> *vec_ptr) {
-> 6 printf("%d\n", vec_ptr->size());
7 }
8
9 int
(lldb) v vec_ptr
(std::vector<int> *) vec_ptr = 0x000000016fdfedd8 size=4
This seems to be a libc++ vs. libstdc++ issue. I’m not sure why though as both formatters seems to be registered with the same flags. The main difference is that the libstdc++ formatter is written in python.
I feel like this should really controlled by the flag eTypeOptionHideValue. For pointer type, it means if we should hide the raw pointer value not the dereferenced type value. For non-pointer type, it means if we should print the value content in summary.
Ah, so the libc++ version explicitly detects pointer types and augments the summary. Yeah, asking each summary provider to remember to do this (I suppose some may choose not to do this, but I think most will) doesn’t sound very ergonomic.
I think that having a way for this to happen automatically would be nice. Using eTypeOptionHideValueseems reasonable, but I can’t say I understand the full implication of that. Jim said something about that showing all the (raw) vector contents, but that doesn’t sound right, as I think we have eTypeOptionHideChildren for that.
What would eTypeOptionHideValue mean in the case of a scalar type that we add a summary formatter to, setting “skip-pointer” to false? If we have a pointer to the type, its value is the pointer value, if we have the type, its value is the scalar value of whatever the type is. What if we want to print the pointer value in the pointer case, but not the scalar value - since that’s in the summary string.
Would we have a way to do that?
Internally, the DumpValueObjectOptions class makes a distinction between HideValue and HidePointerValue, though it doesn’t seem to be much used. I think you’d need that distinction to disambiguate this case.
What would eTypeOptionHideValue mean in the case of a scalar type that we add a summary formatter to, setting “skip-pointer” to false? If we have a pointer to the type, its value is the pointer value, if we have the type, its value is the scalar value of whatever the type is. What if we want to print the pointer value in the pointer case, but not the scalar value - since that’s in the summary string.
Do you mean just print the pointer value of T* but not the content of the scalar value as part of the summary string? Can you give an example?
I think the formatter writer should be aware of this and either set eTypeOptionHideValue to true to hide raw pointer value or not include the scalar value as part of the summary string.
I think the problem is that if the summary formatter for a scalar type sets eTypeOptionHideValue:=false (because it wants to format the value itself), then this will also hide the pointer value (even though that might be a reasonable thing to show). OTOH, if it sets the flag to true, then you get the pointer value when printing a pointer, but you also get the scalar value when printing the value itself.
These are two different things, so separate flags might make sense, but another way to split this hair might be to say that eTypeOptionHideValue only affects the printing of the value for which the formatter is registered. So, if the formatter matches T, then this suppresses the value of T, but not of T*, even though the formatter will be used for T*. If you want to suppress the pointer value as well (not sure why you’d want that, maybe because this isn’t a real pointer and you’re just storing some values in its bits?), you need to register the formatter for T*.
This might make the most sense in conjunction with the idea of automatically dereferencing any pointer values before passing them to the formatter we were discussing in the other thread (as in that case, the formatter wouldn’t even know whether it’s printing a pointer or not).
(The reason why I think it’s good to not have too many flags is because it increases the number of situations that formatter author needs to consider (if he’s even aware the flag exists). I suspect most authors don’t test the formatters extensively (even we didn’t consider the double pointer case) and they just make sure they’re “good enough”. This is why I think it’s important to have good defaults. Showing the T* value for a T formatter seems like a good default to me.)
Either way (explicit flag or binding the meaning of value to the exact type the formatter was registered to regardless of the --skip-pointer & --skip-reference settings) would work. I’m not sure the latter is easier to explain than the explicit flag, but if it mostly just does what people want, we wouldn’t have to?
All I’m suggesting is remove the raw pointer value printing in libc++ container summary provider and flip the hide value flag for libcxx and libstdcxx. The changes are in the formatter side.
–skip-pointer option only affects whether or a formatter for T should be used for T* or not. eTypeOptionHideValue option is only effective when formatter is applied. If --skip-pointer is set, printing T* will not use T’s formatter and it’s printed as raw pointer value regardless eTypeOptionHideValue’s truth value. If --skip-pointer is not set, printing T* will use T’s formatter and it’s only printed with the raw pointer value if eTypeOptionHideValue is false.
What I think you’re saying is that we could remove the eTypeOptionHideValue flag from the existing lib(std)c++ data formatter (even though the flag currently causes lldb to print the value of scalar types) because none of the c++ types we are currently printing are scalar types. Does that sound right?