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 <gclay...@apple.com> 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 
>> <lldb-dev@lists.llvm.org> wrote:
>> 
>>> 
>>> On Sep 2, 2015, at 3:15 PM, Ryan Brown via lldb-dev 
>>> <lldb-dev@lists.llvm.org> 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
>> lldb-dev@lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
> 

_______________________________________________
lldb-dev mailing list
lldb-dev@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev

Reply via email to