Note that completing types is a bit more complex with clang::ASTContext based
types because of it often uses the clang::Decl to do the type completion so we
need to maintain that mapping. It might not be that hard in Go as you could
just do:
CompilerType my_type = ...;
if (my_type.GetCompleteType())
{
...
}
And this could just call down into your SymbolFile. But in clang we often get
to the point where we are playing around with types from a pure
clang::ASTContext stand point (like in the expression parser) and the clang
expression parser knows how to complete types via clang::ExternalASTSource, so
the expression parser when playing around with clang::Decl objects can cause
them to complete themselves. This allows us to hand the clang expression parser
a forward decl to a "Foo" type and let the expression parser complete the type
only if it needs to. If the expression parser just has a "Foo *" that it uses
and it just passed that to a function, it never needs to complete "Foo", but if
you do "Foo *foo = ...; foo->m_int" then you would need to complete it. So we
make all struct, unions, and classes able to lazily complete themselves for
performance reasons.
Greg
> On Sep 2, 2015, at 4:07 PM, Greg Clayton <[email protected]> wrote:
>
> Also: lldb_private::TypeSystem has a "SymbolFile *" registered with it:
>
> virtual SymbolFile *
> GetSymbolFile () const
> {
> return m_sym_file;
> }
>
> // Returns true if the symbol file changed during the set accessor.
> virtual void
> SetSymbolFile (SymbolFile *sym_file)
> {
> m_sym_file = sym_file;
> }
>
> So it can use the:
>
> bool
> SymbolFile::CompleteType (CompilerType &clang_type);
>
> This is what ClangASTContext::CompleteTagDecl() uses:
>
> void
> ClangASTContext::CompleteTagDecl (void *baton, clang::TagDecl *decl)
> {
> ClangASTContext *ast = (ClangASTContext *)baton;
> SymbolFile *sym_file = ast->GetSymbolFile();
> if (sym_file)
> {
> CompilerType clang_type = GetTypeForDecl (decl);
> if (clang_type)
> sym_file->CompleteType (clang_type);
> }
> }
>
>
>> On Sep 2, 2015, at 3:48 PM, Greg Clayton via lldb-dev
>> <[email protected]> wrote:
>>
>>>
>>> On Sep 2, 2015, at 3:15 PM, Ryan Brown via lldb-dev
>>> <[email protected]> wrote:
>>>
>>> I'm trying to implement a DWARFASTParser for go, and have hit an issue with
>>> fields for structs.
>>> As I understand it, DWARFASTParserClang loads minimal type info for structs
>>> at first, and registers the type in SymbolFileDWARF's
>>> m_forward_decl_clang_type_to_die.
>>> Then later when you call type.GetFullCompilerType() it calls back into the
>>> DWARFASTParser to complete the type.
>>>
>>> But it seems like the SBValue's in the python API only get Forward types,
>>> and never complete them. For example, I do:
>>> var = frame.FindVariable('theStruct')
>>> self.assertEqual(2, var.GetNumChildren())
>>>
>>> But I get 0 children, because the type is incomplete and there doesn't seem
>>> to be any way to complete it.
>>> ValueObject::GetNumChildren goes through
>>> ValueObject::MaybeCalculateCompleteType, which seems promising. But it only
>>> completes the type for objc.
>>> Would a clang variable already have a full type at this point for some
>>> reason? If so, how do I arrange that for go?
>>>
>>> Also, TypeSystem has a GetCompleteType method. I don't understand when this
>>> would be called or how I can implement it without a reference to
>>> SymbolFileDWARF.
>>
>> The story goes:
>>
>> lldb_private::ClangASTContext inherits from lldb_private::TypeSystem so it
>> is the type system. The ClangASTContext also signs up to be a
>> clang::ExternalASTSource so that it can complete types via:
>>
>> ClangASTContext::CompleteTagDecl()
>> ClangASTContext::CompleteObjCInterfaceDecl()
>>
>> ClangASTContext::CompleteTagDecl() completes C and C++ structs, unions and
>> classes.
>>
>> ClangASTContext::CompleteObjCInterfaceDecl() completes Objective C stuff.
>>
>> The function that actually figures out how many children will be routed
>> through "CompilerType::GetNumChildren(bool)" with code like this:
>>
>> size_t
>> ValueObjectVariable::CalculateNumChildren()
>> {
>> CompilerType type(GetCompilerType());
>>
>> if (!type.IsValid())
>> return 0;
>>
>> const bool omit_empty_base_classes = true;
>> return type.GetNumChildren(omit_empty_base_classes);
>> }
>>
>>
>> CompilerType passes the ball back to the TypeSystem class (ClangASTContext
>> in this case):
>>
>> uint32_t
>> CompilerType::GetNumChildren (bool omit_empty_base_classes) const
>> {
>> if (!IsValid())
>> return 0;
>> return m_type_system->GetNumChildren(m_type, omit_empty_base_classes);
>> }
>>
>>
>> Down in ClangASTContext it does:
>>
>>
>> uint32_t
>> ClangASTContext::GetNumChildren (void* type, bool omit_empty_base_classes)
>> {
>> if (!type)
>> return 0;
>>
>> uint32_t num_children = 0;
>> clang::QualType qual_type(GetQualType(type));
>> const clang::Type::TypeClass type_class = qual_type->getTypeClass();
>> switch (type_class)
>> {
>> ...
>> case clang::Type::Record:
>> if (GetCompleteQualType (getASTContext(), qual_type))
>> {
>>
>>
>>
>>
>> So it is a static function named GetCompleteQualType() in
>> ClangASTContext.cpp that completes the type if it needs to:
>>
>>
>> static bool
>> GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type, bool
>> allow_completion = true)
>> {
>> const clang::Type::TypeClass type_class = qual_type->getTypeClass();
>> switch (type_class)
>> {
>> ...
>> case clang::Type::Record:
>> case clang::Type::Enum:
>> {
>> const clang::TagType *tag_type =
>> llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
>> if (tag_type)
>> {
>> clang::TagDecl *tag_decl = tag_type->getDecl();
>> if (tag_decl)
>> {
>> if (tag_decl->isCompleteDefinition())
>> return true;
>>
>> if (!allow_completion)
>> return false;
>>
>> if (tag_decl->hasExternalLexicalStorage())
>> {
>> if (ast)
>> {
>> clang::ExternalASTSource *external_ast_source =
>> ast->getExternalSource();
>> if (external_ast_source)
>> {
>> external_ast_source->CompleteType(tag_decl);
>>
>>
>>
>> So it will ask the clang::ExternalASTSource to complete the type which
>> should call ClangASTContext::CompleteTagDecl() to complete your type.
>>
>> So this is how it would work if you used DWARFASTParserClang. Are you using
>> that? Or are you using your own DWARFASTParserGo? If so, then you need to
>> implement this type completion in your own TypeSystem. Your type system
>> subclass is required to implement many different function for type
>> introspection, one of which is:
>>
>> class TypeSystem {
>>
>> virtual uint32_t
>> GetNumChildren (void *type, bool omit_empty_base_classes) = 0;
>>
>> };
>>
>> So the clang version in ClangASTContext::GetNumChildren() knows to complete
>> the type if it a forward declaration. If you have a GoASTContext class that
>> inherits from TypeSystem, then all function that might need to know about
>> the contents of a class or struct, will need to know to complete the type.
>> Or, you can fully parse the structs/unions/classes as you parse the DWARF
>> and not worry about implementing lazy type completion for Go.
>>
>> So the main questions I have for you are:
>> - Do you have a GoASTContext that inherits from TypeSystem?
>> - If you do, in order for DWARF to parse Go types that use the GoASTContext,
>> you will need to write a DWARFASTParser subclass that constructs Go types
>> from DWARF. Then your TypeSystem subclass will need to implement:
>>
>> TypeSystem {
>>
>> virtual DWARFASTParser *
>> GetDWARFParser ();
>>
>> };
>>
>>
>> _______________________________________________
>> lldb-dev mailing list
>> [email protected]
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev