1 //===- tools/dsymutil/DeclContext.cpp - Declaration context ---------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "DeclContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
13 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
14 
15 namespace llvm {
16 namespace dsymutil {
17 
18 /// Set the last DIE/CU a context was seen in and, possibly invalidate the
19 /// context if it is ambiguous.
20 ///
21 /// In the current implementation, we don't handle overloaded functions well,
22 /// because the argument types are not taken into account when computing the
23 /// DeclContext tree.
24 ///
25 /// Some of this is mitigated byt using mangled names that do contain the
26 /// arguments types, but sometimes (e.g. with function templates) we don't have
27 /// that. In that case, just do not unique anything that refers to the contexts
28 /// we are not able to distinguish.
29 ///
30 /// If a context that is not a namespace appears twice in the same CU, we know
31 /// it is ambiguous. Make it invalid.
setLastSeenDIE(CompileUnit & U,const DWARFDie & Die)32 bool DeclContext::setLastSeenDIE(CompileUnit &U, const DWARFDie &Die) {
33   if (LastSeenCompileUnitID == U.getUniqueID()) {
34     DWARFUnit &OrigUnit = U.getOrigUnit();
35     uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE);
36     U.getInfo(FirstIdx).Ctxt = nullptr;
37     return false;
38   }
39 
40   LastSeenCompileUnitID = U.getUniqueID();
41   LastSeenDIE = Die;
42   return true;
43 }
44 
getChildDeclContext(DeclContext & Context,const DWARFDie & DIE,CompileUnit & U,UniquingStringPool & StringPool,bool InClangModule)45 PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
46     DeclContext &Context, const DWARFDie &DIE, CompileUnit &U,
47     UniquingStringPool &StringPool, bool InClangModule) {
48   unsigned Tag = DIE.getTag();
49 
50   // FIXME: dsymutil-classic compat: We should bail out here if we
51   // have a specification or an abstract_origin. We will get the
52   // parent context wrong here.
53 
54   switch (Tag) {
55   default:
56     // By default stop gathering child contexts.
57     return PointerIntPair<DeclContext *, 1>(nullptr);
58   case dwarf::DW_TAG_module:
59     break;
60   case dwarf::DW_TAG_compile_unit:
61     return PointerIntPair<DeclContext *, 1>(&Context);
62   case dwarf::DW_TAG_subprogram:
63     // Do not unique anything inside CU local functions.
64     if ((Context.getTag() == dwarf::DW_TAG_namespace ||
65          Context.getTag() == dwarf::DW_TAG_compile_unit) &&
66         !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0))
67       return PointerIntPair<DeclContext *, 1>(nullptr);
68     LLVM_FALLTHROUGH;
69   case dwarf::DW_TAG_member:
70   case dwarf::DW_TAG_namespace:
71   case dwarf::DW_TAG_structure_type:
72   case dwarf::DW_TAG_class_type:
73   case dwarf::DW_TAG_union_type:
74   case dwarf::DW_TAG_enumeration_type:
75   case dwarf::DW_TAG_typedef:
76     // Artificial things might be ambiguous, because they might be created on
77     // demand. For example implicitly defined constructors are ambiguous
78     // because of the way we identify contexts, and they won't be generated
79     // every time everywhere.
80     if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0))
81       return PointerIntPair<DeclContext *, 1>(nullptr);
82     break;
83   }
84 
85   const char *Name = DIE.getName(DINameKind::LinkageName);
86   const char *ShortName = DIE.getName(DINameKind::ShortName);
87   StringRef NameRef;
88   StringRef ShortNameRef;
89   StringRef FileRef;
90 
91   if (Name)
92     NameRef = StringPool.internString(Name);
93   else if (Tag == dwarf::DW_TAG_namespace)
94     // FIXME: For dsymutil-classic compatibility. I think uniquing within
95     // anonymous namespaces is wrong. There is no ODR guarantee there.
96     NameRef = StringPool.internString("(anonymous namespace)");
97 
98   if (ShortName && ShortName != Name)
99     ShortNameRef = StringPool.internString(ShortName);
100   else
101     ShortNameRef = NameRef;
102 
103   if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&
104       Tag != dwarf::DW_TAG_union_type &&
105       Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty())
106     return PointerIntPair<DeclContext *, 1>(nullptr);
107 
108   unsigned Line = 0;
109   unsigned ByteSize = std::numeric_limits<uint32_t>::max();
110 
111   if (!InClangModule) {
112     // Gather some discriminating data about the DeclContext we will be
113     // creating: File, line number and byte size. This shouldn't be necessary,
114     // because the ODR is just about names, but given that we do some
115     // approximations with overloaded functions and anonymous namespaces, use
116     // these additional data points to make the process safer.
117     //
118     // This is disabled for clang modules, because forward declarations of
119     // module-defined types do not have a file and line.
120     ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size),
121                                  std::numeric_limits<uint64_t>::max());
122     if (Tag != dwarf::DW_TAG_namespace || !Name) {
123       if (unsigned FileNum =
124               dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) {
125         if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
126                 &U.getOrigUnit())) {
127           // FIXME: dsymutil-classic compatibility. I'd rather not
128           // unique anything in anonymous namespaces, but if we do, then
129           // verify that the file and line correspond.
130           if (!Name && Tag == dwarf::DW_TAG_namespace)
131             FileNum = 1;
132 
133           if (LT->hasFileAtIndex(FileNum)) {
134             Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0);
135             // Cache the resolved paths based on the index in the line table,
136             // because calling realpath is expansive.
137             StringRef ResolvedPath = U.getResolvedPath(FileNum);
138             if (!ResolvedPath.empty()) {
139               FileRef = ResolvedPath;
140             } else {
141               std::string File;
142               bool FoundFileName = LT->getFileNameByIndex(
143                   FileNum, U.getOrigUnit().getCompilationDir(),
144                   DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
145                   File);
146               (void)FoundFileName;
147               assert(FoundFileName && "Must get file name from line table");
148               // Second level of caching, this time based on the file's parent
149               // path.
150               FileRef = PathResolver.resolve(File, StringPool);
151               U.setResolvedPath(FileNum, FileRef);
152             }
153           }
154         }
155       }
156     }
157   }
158 
159   if (!Line && NameRef.empty())
160     return PointerIntPair<DeclContext *, 1>(nullptr);
161 
162   // We hash NameRef, which is the mangled name, in order to get most
163   // overloaded functions resolve correctly.
164   //
165   // Strictly speaking, hashing the Tag is only necessary for a
166   // DW_TAG_module, to prevent uniquing of a module and a namespace
167   // with the same name.
168   //
169   // FIXME: dsymutil-classic won't unique the same type presented
170   // once as a struct and once as a class. Using the Tag in the fully
171   // qualified name hash to get the same effect.
172   unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef);
173 
174   // FIXME: dsymutil-classic compatibility: when we don't have a name,
175   // use the filename.
176   if (Tag == dwarf::DW_TAG_namespace && NameRef == "(anonymous namespace)")
177     Hash = hash_combine(Hash, FileRef);
178 
179   // Now look if this context already exists.
180   DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context);
181   auto ContextIter = Contexts.find(&Key);
182 
183   if (ContextIter == Contexts.end()) {
184     // The context wasn't found.
185     bool Inserted;
186     DeclContext *NewContext =
187         new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef,
188                                     Context, DIE, U.getUniqueID());
189     std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
190     assert(Inserted && "Failed to insert DeclContext");
191     (void)Inserted;
192   } else if (Tag != dwarf::DW_TAG_namespace &&
193              !(*ContextIter)->setLastSeenDIE(U, DIE)) {
194     // The context was found, but it is ambiguous with another context
195     // in the same file. Mark it invalid.
196     return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1);
197   }
198 
199   assert(ContextIter != Contexts.end());
200   // FIXME: dsymutil-classic compatibility. Union types aren't
201   // uniques, but their children might be.
202   if ((Tag == dwarf::DW_TAG_subprogram &&
203        Context.getTag() != dwarf::DW_TAG_structure_type &&
204        Context.getTag() != dwarf::DW_TAG_class_type) ||
205       (Tag == dwarf::DW_TAG_union_type))
206     return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1);
207 
208   return PointerIntPair<DeclContext *, 1>(*ContextIter);
209 }
210 } // namespace dsymutil
211 } // namespace llvm
212