Search variables based on clang::DeclContext and clang::Decl tree

Summary: SymbolFileDWARF now creates VarDecl and BlockDecl and adds them to the Decl tree. Then, in ClangExpressionDeclMap it uses the Decl tree to search for a variable. This fixes lots of variable scoping problems.

Reviewers: sivachandra, chaoren, spyffe, clayborg

Subscribers: tberghammer, jingham, lldb-commits

Differential Revision: http://reviews.llvm.org/D12658

llvm-svn: 247746
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
index 2825243..11d231d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
@@ -12,6 +12,7 @@
 
 #include "DWARFDefines.h"
 #include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/CompilerDecl.h"
 #include "lldb/Symbol/CompilerDeclContext.h"
 
 class DWARFDIE;
@@ -27,7 +28,6 @@
                         lldb_private::Log *log,
                         bool *type_is_new_ptr) = 0;
 
-
     virtual lldb_private::Function *
     ParseFunctionFromDWARF (const lldb_private::SymbolContext& sc,
                             const DWARFDIE &die) = 0;
@@ -37,12 +37,14 @@
                            lldb_private::Type *type,
                            lldb_private::CompilerType &clang_type) = 0;
 
+    virtual lldb_private::CompilerDecl
+    GetDeclForUIDFromDWARF (const DWARFDIE &die) = 0;
+
     virtual lldb_private::CompilerDeclContext
     GetDeclContextForUIDFromDWARF (const DWARFDIE &die) = 0;
 
     virtual lldb_private::CompilerDeclContext
     GetDeclContextContainingUIDFromDWARF (const DWARFDIE &die) = 0;
-
 };
 
 #endif  // SymbolFileDWARF_DWARFASTParser_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index cf33d29..29c31ed 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -111,7 +111,6 @@
     }
 };
 
-
 TypeSP
 DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc,
                                          const DWARFDIE &die,
@@ -2040,6 +2039,15 @@
     return false;
 }
 
+CompilerDecl
+DWARFASTParserClang::GetDeclForUIDFromDWARF (const DWARFDIE &die)
+{
+    clang::Decl *clang_decl = GetClangDeclForDIE(die);
+    if (clang_decl != nullptr)
+        return CompilerDecl(&m_ast, clang_decl);
+    return CompilerDecl();
+}
+
 CompilerDeclContext
 DWARFASTParserClang::GetDeclContextForUIDFromDWARF (const DWARFDIE &die)
 {
@@ -2202,7 +2210,6 @@
 };
 #endif
 
-
 Function *
 DWARFASTParserClang::ParseFunctionFromDWARF (const SymbolContext& sc,
                                              const DWARFDIE &die)
@@ -3175,6 +3182,101 @@
     }
 }
 
+Type *
+DWARFASTParserClang::GetTypeForDIE (const DWARFDIE &die)
+{
+    if (die)
+    {
+        SymbolFileDWARF *dwarf = die.GetDWARF();
+        DWARFAttributes attributes;
+        const size_t num_attributes = die.GetAttributes(attributes);
+        if (num_attributes > 0)
+        {
+            DWARFFormValue type_die_form;
+            for (size_t i = 0; i < num_attributes; ++i)
+            {
+                dw_attr_t attr = attributes.AttributeAtIndex(i);
+                DWARFFormValue form_value;
+                
+                if (attr == DW_AT_type && attributes.ExtractFormValueAtIndex(i, form_value))
+                    return dwarf->ResolveTypeUID(DIERef(form_value).GetUID());
+            }
+        }
+    }
+
+    return nullptr;
+}
+
+clang::Decl *
+DWARFASTParserClang::GetClangDeclForDIE (const DWARFDIE &die)
+{
+    if (!die)
+        return nullptr;
+
+    clang::Decl *decl = m_die_to_decl[die.GetDIE()];
+    if (decl != nullptr)
+        return decl;
+
+    switch (die.Tag())
+    {
+        case DW_TAG_variable:
+        case DW_TAG_constant:
+        case DW_TAG_formal_parameter:
+        {
+            SymbolFileDWARF *dwarf = die.GetDWARF();
+            Type *type = GetTypeForDIE(die);
+            const char *name = die.GetName();
+            clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID()));
+            decl = m_ast.CreateVariableDeclaration(
+                decl_context,
+                name,
+                ClangASTContext::GetQualType(type->GetForwardCompilerType()));
+            break;
+        }
+        case DW_TAG_imported_declaration:
+        {
+            SymbolFileDWARF *dwarf = die.GetDWARF();
+            lldb::user_id_t imported_uid = die.GetAttributeValueAsReference(DW_AT_import, DW_INVALID_OFFSET);
+
+            if (dwarf->UserIDMatches(imported_uid))
+            {
+                CompilerDecl imported_decl = dwarf->GetDeclForUID(imported_uid);
+                if (imported_decl)
+                {
+                    clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID()));
+                    if (clang::NamedDecl *clang_imported_decl = llvm::dyn_cast<clang::NamedDecl>((clang::Decl *)imported_decl.GetOpaqueDecl()))
+                        decl = m_ast.CreateUsingDeclaration(decl_context, clang_imported_decl); 
+                }
+            }
+            break;
+        }
+        case DW_TAG_imported_module:
+        {
+            SymbolFileDWARF *dwarf = die.GetDWARF();
+            lldb::user_id_t imported_uid = die.GetAttributeValueAsReference(DW_AT_import, DW_INVALID_OFFSET);
+
+            if (dwarf->UserIDMatches(imported_uid))
+            {
+                CompilerDeclContext imported_decl = dwarf->GetDeclContextForUID(imported_uid);
+                if (imported_decl)
+                {
+                    clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID()));
+                    if (clang::NamespaceDecl *clang_imported_decl = llvm::dyn_cast<clang::NamespaceDecl>((clang::DeclContext *)imported_decl.GetOpaqueDeclContext()))
+                        decl = m_ast.CreateUsingDirectiveDeclaration(decl_context, clang_imported_decl);
+                }
+            }
+            break;
+        }
+        default:
+            break;
+    }
+
+    m_die_to_decl[die.GetDIE()] = decl;
+    m_decl_to_die[decl].insert(die.GetDIE());
+
+    return decl;
+}
+
 clang::DeclContext *
 DWARFASTParserClang::GetClangDeclContextForDIE (const DWARFDIE &die)
 {
@@ -3197,6 +3299,11 @@
                 try_parsing_type = false;
                 break;
 
+            case DW_TAG_lexical_block:
+                decl_ctx = (clang::DeclContext *)ResolveBlockDIE(die);
+                try_parsing_type = false;
+                break;
+
             default:
                 break;
         }
@@ -3217,6 +3324,28 @@
     return nullptr;
 }
 
+clang::BlockDecl *
+DWARFASTParserClang::ResolveBlockDIE (const DWARFDIE &die)
+{
+    if (die && die.Tag() == DW_TAG_lexical_block)
+    {
+        clang::BlockDecl *decl = llvm::cast_or_null<clang::BlockDecl>(m_die_to_decl_ctx[die.GetDIE()]);
+        
+        if (!decl)
+        {
+            DWARFDIE decl_context_die;
+            clang::DeclContext *decl_context = GetClangDeclContextContainingDIE(die, &decl_context_die);
+            decl = m_ast.CreateBlockDeclaration(decl_context);
+
+            if (decl)
+                LinkDeclContextToDIE((clang::DeclContext *)decl, die);
+        }
+
+        return decl;
+    }
+    return nullptr;
+}
+
 clang::NamespaceDecl *
 DWARFASTParserClang::ResolveNamespaceDIE (const DWARFDIE &die)
 {
@@ -3285,10 +3414,6 @@
     return m_ast.GetTranslationUnitDecl();
 }
 
-
-
-
-
 clang::DeclContext *
 DWARFASTParserClang::GetCachedClangDeclContextForDIE (const DWARFDIE &die)
 {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 0ce260a..1bfeace 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -48,6 +48,9 @@
                            lldb_private::Type *type,
                            lldb_private::CompilerType &clang_type) override;
 
+    virtual lldb_private::CompilerDecl
+    GetDeclForUIDFromDWARF (const DWARFDIE &die) override;
+
     virtual lldb_private::CompilerDeclContext
     GetDeclContextForUIDFromDWARF (const DWARFDIE &die) override;
 
@@ -83,6 +86,9 @@
         llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
     };
 
+    clang::BlockDecl *
+    ResolveBlockDIE (const DWARFDIE &die);
+
     clang::NamespaceDecl *
     ResolveNamespaceDIE (const DWARFDIE &die);
 
@@ -136,6 +142,12 @@
                            uint32_t enumerator_byte_size,
                            const DWARFDIE &parent_die);
 
+    lldb_private::Type *
+    GetTypeForDIE (const DWARFDIE &die);
+
+    clang::Decl *
+    GetClangDeclForDIE (const DWARFDIE &die);
+
     clang::DeclContext *
     GetClangDeclContextForDIE (const DWARFDIE &die);
 
@@ -156,11 +168,18 @@
     LinkDeclContextToDIE (clang::DeclContext *decl_ctx,
                           const DWARFDIE &die);
 
+    void
+    LinkDeclToDIE (clang::Decl *decl, const DWARFDIE &die);
+
     typedef llvm::SmallPtrSet<const DWARFDebugInfoEntry *, 4> DIEPointerSet;
     typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap;
     typedef llvm::DenseMap<const clang::DeclContext *, DIEPointerSet> DeclContextToDIEMap;
+    typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::Decl *> DIEToDeclMap;
+    typedef llvm::DenseMap<const clang::Decl *, DIEPointerSet> DeclToDIEMap;
 
     lldb_private::ClangASTContext &m_ast;
+    DIEToDeclMap m_die_to_decl;
+    DeclToDIEMap m_decl_to_die;
     DIEToDeclContextMap m_die_to_decl_ctx;
     DeclContextToDIEMap m_decl_ctx_to_die;
     RecordDeclToLayoutMap m_record_decl_to_layout_map;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h
index 5d8b013..7857fc5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h
@@ -51,6 +51,12 @@
         return lldb_private::CompilerDeclContext();
     }
 
+    virtual lldb_private::CompilerDecl
+    GetDeclForUIDFromDWARF (const DWARFDIE &die) override
+    {
+        return lldb_private::CompilerDecl();
+    }
+
   private:
     size_t ParseChildParameters(const lldb_private::SymbolContext &sc, const DWARFDIE &parent_die, bool &is_variadic,
                                 std::vector<lldb_private::CompilerType> &function_param_types);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index caf95b7..2764902 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -48,6 +48,8 @@
 #include "lldb/Interpreter/OptionValueProperties.h"
 
 #include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/CompilerDecl.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -1391,6 +1393,26 @@
     return false;
 }
 
+CompilerDecl
+SymbolFileDWARF::GetDeclForUID (lldb::user_id_t type_uid)
+{
+    if (UserIDMatches(type_uid))
+    {
+        DWARFDebugInfo* debug_info = DebugInfo();
+        if (debug_info)
+        {
+            DWARFDIE die = debug_info->GetDIE(DIERef(type_uid));
+            if (die)
+            {
+                DWARFASTParser *dwarf_ast = die.GetDWARFParser();
+                if (dwarf_ast)
+                    return dwarf_ast->GetDeclForUIDFromDWARF(die);
+            }
+        }
+    }
+    return CompilerDecl();
+}
+
 CompilerDeclContext
 SymbolFileDWARF::GetDeclContextForUID (lldb::user_id_t type_uid)
 {
@@ -3057,6 +3079,8 @@
                     case DW_TAG_structure_type:
                     case DW_TAG_union_type:
                     case DW_TAG_class_type:
+                    case DW_TAG_lexical_block:
+                    case DW_TAG_subprogram:
                         return die;
                         
                     default:
@@ -3741,6 +3765,7 @@
     {
         DWARFAttributes attributes;
         const size_t num_attributes = die.GetAttributes(attributes);
+        DWARFDIE spec_die;
         if (num_attributes > 0)
         {
             const char *name = NULL;
@@ -3862,7 +3887,13 @@
                             }
                         }
                         break;
-
+                    case DW_AT_specification:
+                    {
+                        DWARFDebugInfo* debug_info = DebugInfo();
+                        if (debug_info)
+                            spec_die = debug_info->GetDIE(DIERef(form_value));
+                        break;
+                    }
                     case DW_AT_artificial:      is_artificial = form_value.Boolean(); break;
                     case DW_AT_accessibility:   break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
                     case DW_AT_declaration:
@@ -3874,7 +3905,6 @@
                     default:
                     case DW_AT_abstract_origin:
                     case DW_AT_sibling:
-                    case DW_AT_specification:
                         break;
                     }
                 }
@@ -4078,6 +4108,8 @@
         // (missing location due to optimization, etc)) so we don't re-parse
         // this DIE over and over later...
         GetDIEToVariable()[die.GetDIE()] = var_sp;
+        if (spec_die)
+            GetDIEToVariable()[spec_die.GetDIE()] = var_sp;
     }
     return var_sp;
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 5dacfcc..7985f5a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -152,6 +152,9 @@
     ResolveType (const DWARFDIE &die,
                  bool assert_not_being_parsed = true);
 
+    lldb_private::CompilerDecl
+    GetDeclForUID (lldb::user_id_t uid) override;
+
     lldb_private::CompilerDeclContext
     GetDeclContextForUID (lldb::user_id_t uid) override;