[PDB] Restore AST from PDB symbols

Summary:
This patch adds an implementation of retrieving of declarations and declaration
contexts based on PDB symbols.

PDB has different type symbols for const-qualified types, and this
implementation ensures that only one declaration was created for both const
and non-const types, but creates different compiler types for them.

The implementation also processes the case when there are two symbols
corresponding to a variable. It's possible e.g. for class static variables,
they has one global symbol and one symbol belonging to a class.

PDB has no info about namespaces, so this implementation parses the full symbol
name and tries to figure out if the symbol belongs to namespace or not,
and then creates nested namespaces if necessary.

Reviewers: asmith, zturner, labath

Reviewed By: asmith

Subscribers: aleksandr.urakov, teemperor, lldb-commits, stella.stamenova

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D51162

llvm-svn: 341782
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index f52aa98..228de6f 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -551,8 +551,7 @@
       llvm::dyn_cast_or_null<ClangASTContext>(type_system);
   if (!clang_type_system)
     return nullptr;
-  PDBASTParser *pdb =
-      llvm::dyn_cast<PDBASTParser>(clang_type_system->GetPDBParser());
+  PDBASTParser *pdb = clang_type_system->GetPDBParser();
   if (!pdb)
     return nullptr;
 
@@ -579,8 +578,7 @@
   if (!clang_ast_ctx)
     return false;
 
-  PDBASTParser *pdb =
-      llvm::dyn_cast<PDBASTParser>(clang_ast_ctx->GetPDBParser());
+  PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
   if (!pdb)
     return false;
 
@@ -588,24 +586,83 @@
 }
 
 lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) {
-  return lldb_private::CompilerDecl();
+  ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
+      GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
+  if (!clang_ast_ctx)
+    return CompilerDecl();
+
+  PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+  if (!pdb)
+    return CompilerDecl();
+
+  auto symbol = m_session_up->getSymbolById(uid);
+  if (!symbol)
+    return CompilerDecl();
+
+  auto decl = pdb->GetDeclForSymbol(*symbol);
+  if (!decl)
+    return CompilerDecl();
+
+  return CompilerDecl(clang_ast_ctx, decl);
 }
 
 lldb_private::CompilerDeclContext
 SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) {
-  // PDB always uses the translation unit decl context for everything.  We can
-  // improve this later but it's not easy because PDB doesn't provide a high
-  // enough level of type fidelity in this area.
-  return *m_tu_decl_ctx_up;
+  ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
+      GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
+  if (!clang_ast_ctx)
+    return CompilerDeclContext();
+
+  PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+  if (!pdb)
+    return CompilerDeclContext();
+
+  auto symbol = m_session_up->getSymbolById(uid);
+  if (!symbol)
+    return CompilerDeclContext();
+
+  auto decl_context = pdb->GetDeclContextForSymbol(*symbol);
+  if (!decl_context)
+    return GetDeclContextContainingUID(uid);
+
+  return CompilerDeclContext(clang_ast_ctx, decl_context);
 }
 
 lldb_private::CompilerDeclContext
 SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
-  return *m_tu_decl_ctx_up;
+  ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
+      GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
+  if (!clang_ast_ctx)
+    return CompilerDeclContext();
+
+  PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+  if (!pdb)
+    return CompilerDeclContext();
+
+  auto symbol = m_session_up->getSymbolById(uid);
+  if (!symbol)
+    return CompilerDeclContext();
+
+  auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol);
+  assert(decl_context);
+
+  return CompilerDeclContext(clang_ast_ctx, decl_context);
 }
 
 void SymbolFilePDB::ParseDeclsForContext(
-    lldb_private::CompilerDeclContext decl_ctx) {}
+    lldb_private::CompilerDeclContext decl_ctx) {
+  ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
+      GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
+  if (!clang_ast_ctx)
+    return;
+
+  PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+  if (!pdb)
+    return;
+
+  pdb->ParseDeclsForDeclContext(
+      static_cast<clang::DeclContext *>(decl_ctx.GetOpaqueDeclContext()));
+}
 
 uint32_t
 SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr,
@@ -876,7 +933,7 @@
   if (scope == eValueTypeVariableLocal) {
     if (sc.function) {
       context_scope = sc.function->GetBlock(true).FindBlockByID(
-          pdb_data.getClassParentId());
+          pdb_data.getLexicalParentId());
       if (context_scope == nullptr)
         context_scope = sc.function;
     }
@@ -973,14 +1030,14 @@
     const lldb_private::ConstString &name,
     const lldb_private::CompilerDeclContext *parent_decl_ctx,
     uint32_t max_matches, lldb_private::VariableList &variables) {
+  if (!parent_decl_ctx)
+    parent_decl_ctx = m_tu_decl_ctx_up.get();
   if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
     return 0;
   if (name.IsEmpty())
     return 0;
 
-  auto results =
-      m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(),
-                                      PDB_NameSearchFlags::NS_CaseSensitive);
+  auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
   if (!results)
     return 0;
 
@@ -1000,6 +1057,15 @@
     if (sc.comp_unit == nullptr)
       continue;
 
+    if (!name.GetStringRef().equals(
+            PDBASTParser::PDBNameDropScope(pdb_data->getName())))
+      continue;
+
+    auto actual_parent_decl_ctx =
+        GetDeclContextContainingUID(result->getSymIndexId());
+    if (actual_parent_decl_ctx != *parent_decl_ctx)
+      continue;
+
     ParseVariables(sc, *pdb_data, &variables);
     matches = variables.GetSize() - old_size;
   }
@@ -1275,7 +1341,7 @@
   std::string name_str = name.AsCString();
 
   // There is an assumption 'name' is not a regex
-  FindTypesByName(name_str, max_matches, types);
+  FindTypesByName(name_str, parent_decl_ctx, max_matches, types);
 
   return types.GetSize();
 }
@@ -1335,14 +1401,16 @@
   }
 }
 
-void SymbolFilePDB::FindTypesByName(const std::string &name,
-                                    uint32_t max_matches,
-                                    lldb_private::TypeMap &types) {
+void SymbolFilePDB::FindTypesByName(
+    const std::string &name,
+    const lldb_private::CompilerDeclContext *parent_decl_ctx,
+    uint32_t max_matches, lldb_private::TypeMap &types) {
+  if (!parent_decl_ctx)
+    parent_decl_ctx = m_tu_decl_ctx_up.get();
   std::unique_ptr<IPDBEnumSymbols> results;
   if (name.empty())
     return;
-  results = m_global_scope_up->findChildren(PDB_SymType::None, name,
-                                            PDB_NameSearchFlags::NS_Default);
+  results = m_global_scope_up->findAllChildren(PDB_SymType::None);
   if (!results)
     return;
 
@@ -1351,6 +1419,11 @@
   while (auto result = results->getNext()) {
     if (max_matches > 0 && matches >= max_matches)
       break;
+
+    if (PDBASTParser::PDBNameDropScope(result->getRawSymbol().getName()) !=
+        name)
+      continue;
+
     switch (result->getSymTag()) {
     case PDB_SymType::Enum:
     case PDB_SymType::UDT:
@@ -1367,6 +1440,11 @@
     if (!ResolveTypeUID(result->getSymIndexId()))
       continue;
 
+    auto actual_parent_decl_ctx =
+        GetDeclContextContainingUID(result->getSymIndexId());
+    if (actual_parent_decl_ctx != *parent_decl_ctx)
+      continue;
+
     auto iter = m_types.find(result->getSymIndexId());
     if (iter == m_types.end())
       continue;
@@ -1477,7 +1555,27 @@
     const lldb_private::SymbolContext &sc,
     const lldb_private::ConstString &name,
     const lldb_private::CompilerDeclContext *parent_decl_ctx) {
-  return lldb_private::CompilerDeclContext();
+  auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+  auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
+  if (!clang_type_system)
+    return CompilerDeclContext();
+
+  PDBASTParser *pdb = clang_type_system->GetPDBParser();
+  if (!pdb)
+    return CompilerDeclContext();
+
+  clang::DeclContext *decl_context = nullptr;
+  if (parent_decl_ctx)
+    decl_context = static_cast<clang::DeclContext *>(
+        parent_decl_ctx->GetOpaqueDeclContext());
+
+  auto namespace_decl =
+      pdb->FindNamespaceDecl(decl_context, name.GetStringRef());
+  if (!namespace_decl)
+    return CompilerDeclContext();
+
+  return CompilerDeclContext(type_system,
+                             static_cast<clang::DeclContext *>(namespace_decl));
 }
 
 lldb_private::ConstString SymbolFilePDB::GetPluginName() {