asmith updated this revision to Diff 155904.
asmith added a comment.

Adding missing inputs


https://reviews.llvm.org/D49410

Files:
  lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
  lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
  lit/SymbolFile/PDB/class-layout.test
  lit/SymbolFile/PDB/pointers.test
  source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
  source/Plugins/SymbolFile/PDB/PDBASTParser.h
  source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp

Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -45,7 +45,7 @@
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
 
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" // For IsCPPMangledName
 #include "Plugins/SymbolFile/PDB/PDBASTParser.h"
 #include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h"
 
@@ -557,9 +557,37 @@
   if (pdb_type == nullptr)
     return nullptr;
 
+  // Parse base classes and nested UDTs first.
+  switch (pdb_type->getSymTag()) {
+  case PDB_SymType::UDT:
+  case PDB_SymType::BaseClass: {
+    if (auto base_classes =
+            pdb_type->findAllChildren<PDBSymbolTypeBaseClass>()) {
+      while (auto base_class = base_classes->getNext())
+        ResolveTypeUID(base_class->getSymIndexId());
+    }
+    if (pdb_type->getRawSymbol().hasNestedTypes()) {
+      if (auto nested_udts = pdb_type->findAllChildren<PDBSymbolTypeUDT>()) {
+        while (auto nested = nested_udts->getNext())
+          ResolveTypeUID(nested->getSymIndexId());
+      }
+    }
+  } break;
+  default:
+    break;
+  }
+
   lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type);
   if (result) {
     m_types.insert(std::make_pair(type_uid, result));
+
+    // Complete the type for UDT & BaseClass symbol immediately. BaseClass is
+    // parsed by its type which might have been completed before. Make sure we
+    // only do this once.
+    if (result->GetID() == type_uid) {
+      pdb->CompleteRecordTypeForPDBSymbol(*pdb_type, result);
+    }
+
     auto type_list = GetTypeList();
     if (type_list)
       type_list->Insert(result);
Index: source/Plugins/SymbolFile/PDB/PDBASTParser.h
===================================================================
--- source/Plugins/SymbolFile/PDB/PDBASTParser.h
+++ source/Plugins/SymbolFile/PDB/PDBASTParser.h
@@ -31,6 +31,7 @@
 class PDBSymbol;
 class PDBSymbolData;
 class PDBSymbolTypeBuiltin;
+class PDBSymbolTypeUDT;
 } // namespace pdb
 } // namespace llvm
 
@@ -41,10 +42,17 @@
 
   lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type);
 
+  bool CompleteRecordTypeForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol,
+                                      lldb::TypeSP type_sp);
+
 private:
   bool AddEnumValue(lldb_private::CompilerType enum_type,
                     const llvm::pdb::PDBSymbolData &data) const;
 
+  bool
+  AddMembersToRecordType(const lldb_private::CompilerType &udt_compiler_type,
+                         const llvm::pdb::PDBSymbolTypeUDT &pdb_udt);
+
   lldb_private::ClangASTContext &m_ast;
   lldb_private::ClangASTImporter m_ast_importer;
 };
Index: source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
===================================================================
--- source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclCXX.h"
 
 #include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h" // For ClangASTMetadata
 #include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/Declaration.h"
 #include "lldb/Symbol/SymbolFile.h"
@@ -175,6 +176,28 @@
   return compiler_type.GetTypeName();
 }
 
+AccessType TranslateMemberAccess(PDB_MemberAccess access) {
+  if (access == PDB_MemberAccess::Public)
+    return lldb::eAccessPublic;
+  if (access == PDB_MemberAccess::Private)
+    return lldb::eAccessPrivate;
+  if (access == PDB_MemberAccess::Protected)
+    return lldb::eAccessProtected;
+  return lldb::eAccessNone;
+}
+
+AccessType GetDefaultAccessibilityForUdtKind(PDB_UdtType udt_kind) {
+  if (udt_kind == PDB_UdtType::Class)
+    return lldb::eAccessPrivate;
+  if (udt_kind == PDB_UdtType::Struct)
+    return lldb::eAccessPublic;
+  if (udt_kind == PDB_UdtType::Union)
+    return lldb::eAccessPublic;
+  if (udt_kind == PDB_UdtType::Interface)
+    return lldb::eAccessPrivate;
+  return lldb::eAccessNone;
+}
+
 bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) {
   auto &raw_sym = symbol.getRawSymbol();
   auto first_line_up = raw_sym.getSrcLineOnTypeDefn();
@@ -216,29 +239,84 @@
   Declaration decl;
 
   switch (type.getSymTag()) {
+  case PDB_SymType::BaseClass: {
+    auto ty =
+        m_ast.GetSymbolFile()->ResolveTypeUID(type.getRawSymbol().getTypeId());
+    return ty ? ty->shared_from_this() : nullptr;
+  } break;
   case PDB_SymType::UDT: {
     auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type);
     assert(udt);
-    AccessType access = lldb::eAccessPublic;
+
+    // Note that, unnamed UDT being typedef-ed is generated as a UDT symbol
+    // other than a Typedef symbol in PDB. For example,
+    //    typedef union { short Row; short Col; } Union;
+    // is generated as a named UDT in PDB:
+    //    union Union { short Row; short Col; }
+    // Such symbols will be handled here.
+
+    // Some UDT with trival ctor has zero length. Just ignore.
+    if (udt->getLength() == 0)
+      return nullptr;
+
+    // Ignore unnamed-tag UDTs.
+    if (udt->getName().empty())
+      return nullptr;
+
     PDB_UdtType udt_kind = udt->getUdtKind();
     auto tag_type_kind = TranslateUdtKind(udt_kind);
-    if (tag_type_kind == -1)
-      return nullptr;
+    assert(tag_type_kind != -1);
+
+    AccessType access = TranslateMemberAccess(udt->getAccess());
+    if (access == lldb::eAccessNone && udt->isNested() &&
+        udt->getClassParent()) {
+      access = GetDefaultAccessibilityForUdtKind(udt_kind);
+    }
 
-    if (udt_kind == PDB_UdtType::Class)
-      access = lldb::eAccessPrivate;
+    ClangASTMetadata metadata;
+    metadata.SetUserID(type.getSymIndexId());
+    metadata.SetIsDynamicCXXType(false);
+
+    // We defer resolving UDTs since some symbol like doubly linked list could
+    // result in endless recursion.
+    Type::ResolveStateTag type_resolve_state_tag = Type::eResolveStateForward;
 
     CompilerType clang_type = m_ast.CreateRecordType(
         tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind,
-        lldb::eLanguageTypeC_plus_plus, nullptr);
+        lldb::eLanguageTypeC_plus_plus, &metadata);
+    assert(clang_type.IsValid());
+
+    m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false);
+
+    if (udt->isConstType())
+      clang_type = clang_type.AddConstModifier();
+
+    if (udt->isVolatileType())
+      clang_type = clang_type.AddVolatileModifier();
+
+    auto children = udt->findAllChildren();
+    if (!children || children->getChildCount() == 0) {
+      // PDB does not have symbol of forwarder. We assume we get an udt w/o any
+      // fields. Just complete it at this point.
+      if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) {
+        ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
+        type_resolve_state_tag = lldb_private::Type::eResolveStateFull;
+      } else {
+        // We are not able to complete udt type.
+        return nullptr;
+      }
+    }
 
     m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
 
-    return std::make_shared<lldb_private::Type>(
+    GetDeclarationForSymbol(type, decl);
+    auto type_sp = std::make_shared<lldb_private::Type>(
         type.getSymIndexId(), m_ast.GetSymbolFile(),
         ConstString(udt->getName()), udt->getLength(), nullptr,
         LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type,
-        lldb_private::Type::eResolveStateForward);
+        type_resolve_state_tag);
+
+    return type_sp;
   } break;
   case PDB_SymType::Enum: {
     auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
@@ -441,6 +519,26 @@
     if (!pointee_type)
       return nullptr;
 
+    if (pointer_type->isPointerToDataMember() ||
+        pointer_type->isPointerToMemberFunction()) {
+      auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId();
+      auto class_parent_type =
+          m_ast.GetSymbolFile()->ResolveTypeUID(class_parent_uid);
+      assert(class_parent_type);
+
+      CompilerType pointer_ast_type;
+      pointer_ast_type = ClangASTContext::CreateMemberPointerType(
+          class_parent_type->GetLayoutCompilerType(),
+          pointee_type->GetForwardCompilerType());
+      assert(pointer_ast_type);
+
+      return std::make_shared<lldb_private::Type>(
+          pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(),
+          pointer_type->getLength(), nullptr, LLDB_INVALID_UID,
+          lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type,
+          lldb_private::Type::eResolveStateForward);
+    }
+
     CompilerType pointer_ast_type;
     pointer_ast_type = pointee_type->GetFullCompilerType();
     if (pointer_type->isReference())
@@ -513,3 +611,165 @@
       enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(),
       raw_value, byte_size * 8);
 }
+
+bool PDBASTParser::AddMembersToRecordType(const CompilerType &udt_compiler_type,
+                                          const PDBSymbolTypeUDT &pdb_udt) {
+  auto members = pdb_udt.findAllChildren();
+  if (!members)
+    return false;
+
+  llvm::SmallVector<clang::CXXBaseSpecifier *, 8> base_classes;
+
+  while (auto member = members->getNext()) {
+    if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(member.get())) {
+      if (pdb_data->isCompilerGenerated())
+        continue;
+      auto data_type = pdb_data->getType();
+      if (!data_type)
+        continue;
+      auto type_sp =
+          m_ast.GetSymbolFile()->ResolveTypeUID(data_type->getSymIndexId());
+      if (!type_sp)
+        continue;
+
+      auto access = TranslateMemberAccess(pdb_data->getAccess());
+      assert(access != lldb::eAccessNone);
+
+      auto loc_type = pdb_data->getLocationType();
+      uint32_t bitfield_bit_size = 0;
+      if (loc_type == PDB_LocType::BitField)
+        bitfield_bit_size = pdb_data->getLength();
+
+      auto member_name = pdb_data->getName();
+      auto data_kind = pdb_data->getDataKind();
+      if (data_kind == PDB_DataKind::Member) {
+        auto member_ast_type = type_sp->GetLayoutCompilerType();
+        if (!member_ast_type.IsCompleteType())
+          member_ast_type.GetCompleteType();
+        // CXX class type member must be parsed and complete ahead.
+        if (ClangASTContext::IsCXXClassType(member_ast_type) &&
+            member_ast_type.GetCompleteType() == false) {
+          if (ClangASTContext::StartTagDeclarationDefinition(member_ast_type)) {
+            ClangASTContext::CompleteTagDeclarationDefinition(member_ast_type);
+          } else {
+            // We are not able to start definition.
+            continue;
+          }
+        }
+        assert(member_ast_type.IsCompleteType());
+
+        if (!member_name.empty()) {
+          ClangASTContext::AddFieldToRecordType(
+              udt_compiler_type, member_name.c_str(), member_ast_type, access,
+              bitfield_bit_size);
+        } else {
+          // For now PDB does not generate symbol for unnamed bitfiled. We
+          // handle it anyway.
+          assert(pdb_data->getSymTag() == PDB_SymType::BuiltinType);
+          ClangASTContext::AddFieldToRecordType(udt_compiler_type, NULL,
+                                                member_ast_type, access,
+                                                pdb_data->getLength());
+        }
+      } else if (data_kind == PDB_DataKind::StaticMember) {
+        ClangASTContext::AddVariableToRecordType(
+            udt_compiler_type, member_name.c_str(),
+            type_sp->GetLayoutCompilerType(), access);
+      } else {
+        llvm_unreachable("Unhandled data kind!");
+      }
+    } else if (auto pdb_base_class =
+                   llvm::dyn_cast<PDBSymbolTypeBaseClass>(member.get())) {
+      auto base_class_type_sp = m_ast.GetSymbolFile()->ResolveTypeUID(
+          pdb_base_class->getSymIndexId());
+      if (!base_class_type_sp)
+        continue;
+
+      // Base class type must be parsed and complete ahead.
+      auto base_ast_type = base_class_type_sp->GetFullCompilerType();
+      assert(base_ast_type && base_ast_type.IsCompleteType());
+
+      auto access = TranslateMemberAccess(pdb_base_class->getAccess());
+      assert(access != lldb::eAccessNone);
+
+      auto base_spec = m_ast.CreateBaseClassSpecifier(
+          base_ast_type.GetOpaqueQualType(), access,
+          pdb_base_class->isVirtualBaseClass(), /*base_of_class*/ true);
+      base_classes.push_back(base_spec);
+
+    } else if (auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(member.get())) {
+      auto method_type_sp =
+          m_ast.GetSymbolFile()->ResolveTypeUID(pdb_func->getSymIndexId());
+      // MSVC specific __vecDelDtor.
+      if (!method_type_sp)
+        break;
+
+      auto method_ast_type = method_type_sp->GetFullCompilerType();
+      assert(method_ast_type.IsCompleteType());
+      // TODO: get mangled name for the method.
+      m_ast.AddMethodToCXXRecordType(
+          udt_compiler_type.GetOpaqueQualType(), pdb_func->getName().c_str(),
+          /*mangled_name*/ nullptr, method_ast_type,
+          TranslateMemberAccess(pdb_func->getAccess()), pdb_func->isVirtual(),
+          pdb_func->isStatic(), pdb_func->hasInlineAttribute(),
+          /*is_explicit*/ false, // FIXME: Need this field in CodeView.
+          /*is_attr_used*/ false,
+          /*is_artificial*/ pdb_func->isCompilerGenerated());
+
+    } else if (auto pdb_nested_udt =
+                   llvm::dyn_cast<PDBSymbolTypeUDT>(member.get())) {
+      // TODO: to handle nested UDTs, need to get correct decl context for UDT.
+    } else {
+      // Unhandled nested types: typedef etc.
+    }
+  }
+
+  if (!base_classes.empty()) {
+    bool result = m_ast.SetBaseClassesForClassType(
+        udt_compiler_type.GetOpaqueQualType(), &base_classes.front(),
+        base_classes.size());
+    assert(result);
+    ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(),
+                                               base_classes.size());
+  }
+
+  return true;
+}
+
+bool PDBASTParser::CompleteRecordTypeForPDBSymbol(const PDBSymbol &pdb_symbol,
+                                                  TypeSP type_sp) {
+  switch (pdb_symbol.getSymTag()) {
+  case PDB_SymType::BaseClass:
+  case PDB_SymType::UDT: {
+    auto clang_type = type_sp->GetForwardCompilerType();
+    const PDBSymbolTypeUDT *pdb_udt;
+    if (auto base_class = llvm::dyn_cast<PDBSymbolTypeBaseClass>(&pdb_symbol))
+      pdb_udt =
+          llvm::dyn_cast<PDBSymbolTypeUDT>(base_class->getType().release());
+    else
+      pdb_udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&pdb_symbol);
+    assert(pdb_udt);
+
+    if (!ClangASTContext::StartTagDeclarationDefinition(clang_type)) {
+      // We are not able to start definition.
+      return false;
+    }
+
+    AddMembersToRecordType(clang_type, *pdb_udt);
+
+    ClangASTContext::BuildIndirectFields(clang_type);
+    ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
+    // Reset the type with a fully resolved compiler type.
+    type_sp.reset(new Type(type_sp->GetID(), m_ast.GetSymbolFile(),
+                           type_sp->GetName(), type_sp->GetByteSize(), nullptr,
+                           LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID,
+                           type_sp->GetDeclaration(), clang_type,
+                           lldb_private::Type::eResolveStateFull));
+    return true;
+  } break;
+
+  default:
+    return false;
+  }
+
+  return false;
+}
\ No newline at end of file
Index: lit/SymbolFile/PDB/pointers.test
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/pointers.test
@@ -0,0 +1,33 @@
+REQUIRES: windows
+RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/PointerTypeTest.cpp /o %T/PointerTypeTest.cpp.obj
+RUN: link %T/PointerTypeTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/PointerTypeTest.cpp.exe
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck %s
+
+CHECK: Module [[MOD:.*]]
+CHECK-DAG:  name = "main::ST::f"
+CHECK-SAME: decl = PointerTypeTest.cpp:10
+CHECK-SAME: compiler_type = {{.*}} int (int)
+
+CHECK-DAG:  name = "main::ST", size = 4, decl = PointerTypeTest.cpp:8, compiler_type = {{.*}} struct main::ST {
+CHECK-NEXT: int a;
+CHECK-NEXT: int {{.*}}f(int);
+CHECK-NEXT:}
+
+CHECK-DAG: {{^[0-9A-F]+}}:   CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\PointerTypeTest.cpp'
+CHECK-DAG:   Function{[[FID1:.*]]}, mangled = _main
+CHECK-NEXT:  Block{[[FID1]]}
+CHECK-DAG:     Variable{{.*}}, name = "array_pointer"
+CHECK-SAME:    (int (*)[2][4]), scope = local
+CHECK-DAG:     Variable{{.*}}, name = "p_int"
+CHECK-SAME:    (int *), scope = local
+CHECK-DAG:     Variable{{.*}}, name = "p_member_field"
+CHECK-SAME:    (int main::ST::*), scope = local
+CHECK-DAG:     Variable{{.*}}, name = "p_member_method"
+CHECK-SAME:    (int (main::ST::*)(int)), scope = local
+
+CHECK-DAG:   Function{[[FID2:.*]]}, demangled = {{.*}}f(int)
+CHECK-NEXT:  Block{[[FID2]]}
+CHECK-DAG:     Variable{{.*}}, name = "this"
+CHECK-SAME:    (main::ST *), scope = parameter, artificial
+CHECK-DAG:     Variable{{.*}}, name = "x"
+CHECK-SAME:    (int), scope = parameter, decl = PointerTypeTest.cpp:10
Index: lit/SymbolFile/PDB/class-layout.test
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/class-layout.test
@@ -0,0 +1,83 @@
+REQUIRES: windows
+RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/ClassLayoutTest.cpp /o %T/ClassLayoutTest.cpp.obj
+RUN: link %T/ClassLayoutTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/ClassLayoutTest.cpp.exe
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck %s
+
+CHECK: Module [[MOD:.*]]
+CHECK-DAG: {{^[0-9A-F]+}}: SymbolVendor ([[MOD]])
+CHECK-DAG:  name = "Enum", size = 4,  decl = ClassLayoutTest.cpp:4
+CHECK-SAME: enum Enum {
+CHECK-DAG:    RED,
+CHECK-DAG:    GREEN,
+CHECK-DAG:    BLUE
+CHECK-DAG:}
+
+CHECK-DAG:  name = "MemberTest::Base", size = 4,  decl = ClassLayoutTest.cpp:56
+CHECK-SAME: class MemberTest::Base {
+CHECK-DAG:    int a;
+CHECK-DAG:    void {{.*}}Base();
+CHECK-DAG:    {{.*}}~Base();
+CHECK-DAG:    int {{.*}}Get();
+CHECK-DAG:}
+
+CHECK-DAG:  name = "Union", size = 4, decl = ClassLayoutTest.cpp:8
+CHECK-SAME: union Union {
+CHECK-DAG:    short Row;
+CHECK-DAG:    unsigned short Col;
+CHECK-DAG:    int Line : 16;
+CHECK-DAG:    long Table;
+CHECK-DAG:}
+
+CHECK-DAG:  name = "Struct", size = 64, decl = ClassLayoutTest.cpp:21
+CHECK-SAME: struct Struct {
+CHECK-DAG:    bool A;
+CHECK-DAG:    unsigned char UCharVar;
+CHECK-DAG:    unsigned int UIntVar;
+CHECK-DAG:    long long LongLongVar;
+CHECK-DAG:    Enum EnumVar;
+CHECK-DAG:    int array[10];
+CHECK-DAG:}
+
+CHECK-DAG:  name = "_List", size = 12, decl = ClassLayoutTest.cpp:44
+CHECK-SAME: struct _List {
+CHECK-DAG:    _List *current;
+CHECK-DAG:    _List *previous;
+CHECK-DAG:    _List *next;
+CHECK-DAG:}
+
+CHECK-DAG:  name = "Complex", size = 368, decl = ClassLayoutTest.cpp:32
+CHECK-SAME: struct Complex {
+CHECK-DAG:    _List *array[90];
+CHECK-DAG:    int x;
+CHECK-DAG:    int a;
+CHECK-DAG:    float b;
+CHECK-DAG:}
+
+CHECK-DAG:  name = "MemberTest::Friend", size = 1, decl = ClassLayoutTest.cpp:66
+CHECK-SAME: class MemberTest::Friend {
+CHECK-DAG:    int f();
+CHECK-DAG: }
+
+CHECK-DAG:  name = "MemberTest::Class", size = 88, decl = ClassLayoutTest.cpp:70
+CHECK-SAME: class MemberTest::Class : public MemberTest::Base {
+CHECK-DAG:    static int m_static;
+CHECK-DAG:    int m_public;
+CHECK-DAG:    Struct m_struct;
+CHECK-DAG:    Union m_union;
+CHECK-DAG:    int m_private;
+CHECK-DAG:    int m_protected;
+CHECK-DAG:    void Class();
+CHECK-DAG:    void Class(int);
+CHECK-DAG:    ~MemberTest::Class();
+CHECK-DAG:    static int {{.*}}StaticMemberFunc(int, ...);
+CHECK-DAG:    int Get();
+CHECK-DAG:    int f(MemberTest::Friend);
+CHECK-DAG:    bool operator==(const MemberTest::Class &)
+CHECK-DAG:}
+
+CHECK-DAG:  name = "UnnamedStruct", size = 4, decl = ClassLayoutTest.cpp:51
+CHECK-SAME: struct UnnamedStruct {
+CHECK-DAG:   int a;
+CHECK-DAG:}
+
+CHECK-DAG: {{^[0-9A-F]+}}:   CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\ClassLayoutTest.cpp'
Index: lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
@@ -0,0 +1,25 @@
+
+int main() {
+
+  // Test pointer to array.
+  int array[2][4];
+  int (*array_pointer)[2][4] = &array;
+
+  struct ST {
+    int a;
+    int f(int x) { return 1; }
+  };
+
+  ST s = { 10 };
+
+  // Test pointer to a local.
+  int *p_int = &s.a;
+
+  // Test pointer to data member.
+  int ST:: *p_member_field = &ST::a;
+
+  // Test pointer to member function.
+  int (ST::*p_member_method)(int) = &ST::f;
+
+  return 0;
+}
Index: lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
===================================================================
--- /dev/null
+++ lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
@@ -0,0 +1,103 @@
+// To avoid linking MSVC specific libs, we don't test virtual/override methods that needs vftable support in this file.
+
+// Enum.
+enum Enum { RED, GREEN, BLUE };
+Enum EnumVar;
+
+// Union.
+union Union {
+  short Row;
+  unsigned short Col;
+  int Line : 16;  // Test named bitfield.
+  short : 8;      // Unnamed bitfield symbol won't be generated in PDB.
+  long Table;
+};
+Union UnionVar;
+
+// Struct.
+struct Struct;
+typedef Struct StructTypedef;
+
+struct Struct {
+  bool A;
+  unsigned char UCharVar;
+  unsigned int UIntVar;
+  long long LongLongVar;
+  Enum EnumVar; // Test struct has UDT member.
+  int array[10];
+};
+struct Struct StructVar;
+
+struct _List; // Forward declaration.
+struct Complex {
+  struct _List*  array[90];
+  struct { // Test unnamed struct. MSVC treats it as `int x`
+    int x;
+  };
+  union {  // Test unnamed union. MSVC treats it as `int a; float b;`
+    int a;
+    float b;
+  };
+};
+struct Complex c;
+
+struct _List { // Test doubly linked list.
+  struct _List* current;
+  struct _List* previous;
+  struct _List* next;
+};
+struct _List ListVar;
+
+typedef struct { int a; } UnnamedStruct; // Test unnamed typedef-ed struct.
+UnnamedStruct UnnanmedVar;
+
+// Class.
+namespace MemberTest {
+class Base {
+  public:
+    Base() {}
+    ~Base() {}
+
+  public:
+    int Get() { return 0; }
+  protected:
+    int a;
+};
+  class Friend {
+    public:
+      int f() { return 3; }
+  };
+  class Class : public Base { // Test base class.
+  friend Friend;
+  static int m_static;  // Test static member variable.
+  public:
+    Class() : m_public(), m_private(), m_protected() {}
+    explicit Class(int a) { m_public = a; } // Test first reference of m_public.
+    ~Class() {}
+
+    static int StaticMemberFunc(int a, ...) { return 1; } // Test static member function.
+    int Get() { return 1; }
+    int f(Friend c) { return c.f(); }
+    inline bool operator == (const Class &rhs) const // Test operator.
+    {
+      return ( m_public == rhs.m_public);
+    }
+
+  public:
+    int m_public;
+    struct Struct m_struct;
+  private:
+    Union m_union;
+    int m_private;
+  protected:
+    friend class Friend;
+    int m_protected;
+  };
+}
+
+int main() {
+  MemberTest::Base B1;
+  B1.Get();
+  MemberTest::Class::StaticMemberFunc(1,10,2);
+  return 0;
+}
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to