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