ClangASTImporter.h revision 344779
1//===-- ClangASTImporter.h --------------------------------------*- C++ -*-===//
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#ifndef liblldb_ClangASTImporter_h_
11#define liblldb_ClangASTImporter_h_
12
13#include <map>
14#include <memory>
15#include <set>
16#include <vector>
17
18#include "clang/AST/ASTImporter.h"
19#include "clang/AST/CharUnits.h"
20#include "clang/AST/Decl.h"
21#include "clang/AST/DeclCXX.h"
22#include "clang/Basic/FileManager.h"
23#include "clang/Basic/FileSystemOptions.h"
24
25#include "lldb/Symbol/CompilerDeclContext.h"
26#include "lldb/lldb-types.h"
27
28#include "llvm/ADT/DenseMap.h"
29
30namespace lldb_private {
31
32class ClangASTMetrics {
33public:
34  static void DumpCounters(Log *log);
35  static void ClearLocalCounters() { local_counters = {0, 0, 0, 0, 0, 0}; }
36
37  static void RegisterVisibleQuery() {
38    ++global_counters.m_visible_query_count;
39    ++local_counters.m_visible_query_count;
40  }
41
42  static void RegisterLexicalQuery() {
43    ++global_counters.m_lexical_query_count;
44    ++local_counters.m_lexical_query_count;
45  }
46
47  static void RegisterLLDBImport() {
48    ++global_counters.m_lldb_import_count;
49    ++local_counters.m_lldb_import_count;
50  }
51
52  static void RegisterClangImport() {
53    ++global_counters.m_clang_import_count;
54    ++local_counters.m_clang_import_count;
55  }
56
57  static void RegisterDeclCompletion() {
58    ++global_counters.m_decls_completed_count;
59    ++local_counters.m_decls_completed_count;
60  }
61
62  static void RegisterRecordLayout() {
63    ++global_counters.m_record_layout_count;
64    ++local_counters.m_record_layout_count;
65  }
66
67private:
68  struct Counters {
69    uint64_t m_visible_query_count;
70    uint64_t m_lexical_query_count;
71    uint64_t m_lldb_import_count;
72    uint64_t m_clang_import_count;
73    uint64_t m_decls_completed_count;
74    uint64_t m_record_layout_count;
75  };
76
77  static Counters global_counters;
78  static Counters local_counters;
79
80  static void DumpCounters(Log *log, Counters &counters);
81};
82
83class ClangASTImporter {
84public:
85  struct LayoutInfo {
86    LayoutInfo()
87        : bit_size(0), alignment(0), field_offsets(), base_offsets(),
88          vbase_offsets() {}
89    uint64_t bit_size;
90    uint64_t alignment;
91    llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
92    llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
93    llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
94        vbase_offsets;
95  };
96
97  ClangASTImporter() : m_file_manager(clang::FileSystemOptions()) {}
98
99  clang::QualType CopyType(clang::ASTContext *dst_ctx,
100                           clang::ASTContext *src_ctx, clang::QualType type);
101
102  lldb::opaque_compiler_type_t CopyType(clang::ASTContext *dst_ctx,
103                                        clang::ASTContext *src_ctx,
104                                        lldb::opaque_compiler_type_t type);
105
106  CompilerType CopyType(ClangASTContext &dst, const CompilerType &src_type);
107
108  clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx,
109                        clang::Decl *decl);
110
111  lldb::opaque_compiler_type_t DeportType(clang::ASTContext *dst_ctx,
112                                          clang::ASTContext *src_ctx,
113                                          lldb::opaque_compiler_type_t type);
114
115  clang::Decl *DeportDecl(clang::ASTContext *dst_ctx,
116                          clang::ASTContext *src_ctx, clang::Decl *decl);
117
118  void InsertRecordDecl(clang::RecordDecl *decl, const LayoutInfo &layout);
119
120  bool LayoutRecordType(
121      const clang::RecordDecl *record_decl, uint64_t &bit_size,
122      uint64_t &alignment,
123      llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
124      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
125          &base_offsets,
126      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
127          &vbase_offsets);
128
129  bool CanImport(const CompilerType &type);
130
131  bool Import(const CompilerType &type);
132
133  bool CompleteType(const CompilerType &compiler_type);
134
135  void CompleteDecl(clang::Decl *decl);
136
137  bool CompleteTagDecl(clang::TagDecl *decl);
138
139  bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
140
141  bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
142
143  bool CompleteAndFetchChildren(clang::QualType type);
144
145  bool RequireCompleteType(clang::QualType type);
146
147  bool ResolveDeclOrigin(const clang::Decl *decl, clang::Decl **original_decl,
148                         clang::ASTContext **original_ctx) {
149    DeclOrigin origin = GetDeclOrigin(decl);
150
151    if (original_decl)
152      *original_decl = origin.decl;
153
154    if (original_ctx)
155      *original_ctx = origin.ctx;
156
157    return origin.Valid();
158  }
159
160  void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
161
162  ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
163
164  //
165  // Namespace maps
166  //
167
168  typedef std::vector<std::pair<lldb::ModuleSP, CompilerDeclContext>>
169      NamespaceMap;
170  typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
171
172  void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
173                            NamespaceMapSP &namespace_map);
174
175  NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
176
177  void BuildNamespaceMap(const clang::NamespaceDecl *decl);
178
179  //
180  // Completers for maps
181  //
182
183  class MapCompleter {
184  public:
185    virtual ~MapCompleter();
186
187    virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
188                                      const ConstString &name,
189                                      NamespaceMapSP &parent_map) const = 0;
190  };
191
192  void InstallMapCompleter(clang::ASTContext *dst_ctx,
193                           MapCompleter &completer) {
194    ASTContextMetadataSP context_md;
195    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
196
197    if (context_md_iter == m_metadata_map.end()) {
198      context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
199      m_metadata_map[dst_ctx] = context_md;
200    } else {
201      context_md = context_md_iter->second;
202    }
203
204    context_md->m_map_completer = &completer;
205  }
206
207  void ForgetDestination(clang::ASTContext *dst_ctx);
208  void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
209
210private:
211  struct DeclOrigin {
212    DeclOrigin() : ctx(nullptr), decl(nullptr) {}
213
214    DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
215        : ctx(_ctx), decl(_decl) {}
216
217    DeclOrigin(const DeclOrigin &rhs) {
218      ctx = rhs.ctx;
219      decl = rhs.decl;
220    }
221
222    void operator=(const DeclOrigin &rhs) {
223      ctx = rhs.ctx;
224      decl = rhs.decl;
225    }
226
227    bool Valid() { return (ctx != nullptr || decl != nullptr); }
228
229    clang::ASTContext *ctx;
230    clang::Decl *decl;
231  };
232
233  typedef std::map<const clang::Decl *, DeclOrigin> OriginMap;
234
235  class Minion : public clang::ASTImporter {
236  public:
237    Minion(ClangASTImporter &master, clang::ASTContext *target_ctx,
238           clang::ASTContext *source_ctx)
239        : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx,
240                             master.m_file_manager, true /*minimal*/),
241          m_decls_to_deport(nullptr), m_decls_already_deported(nullptr),
242          m_master(master), m_source_ctx(source_ctx) {}
243
244    // A call to "InitDeportWorkQueues" puts the minion into deport mode.
245    // In deport mode, every copied Decl that could require completion is
246    // recorded and placed into the decls_to_deport set.
247    //
248    // A call to "ExecuteDeportWorkQueues" completes all the Decls that
249    // are in decls_to_deport, adding any Decls it sees along the way that it
250    // hasn't already deported.  It proceeds until decls_to_deport is empty.
251    //
252    // These calls must be paired.  Leaving a minion in deport mode or trying
253    // to start deport minion with a new pair of queues will result in an
254    // assertion failure.
255
256    void
257    InitDeportWorkQueues(std::set<clang::NamedDecl *> *decls_to_deport,
258                         std::set<clang::NamedDecl *> *decls_already_deported);
259    void ExecuteDeportWorkQueues();
260
261    void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
262
263    clang::Decl *Imported(clang::Decl *from, clang::Decl *to) override;
264
265    clang::Decl *GetOriginalDecl(clang::Decl *To) override;
266
267    std::set<clang::NamedDecl *> *m_decls_to_deport;
268    std::set<clang::NamedDecl *> *m_decls_already_deported;
269    ClangASTImporter &m_master;
270    clang::ASTContext *m_source_ctx;
271  };
272
273  typedef std::shared_ptr<Minion> MinionSP;
274  typedef std::map<clang::ASTContext *, MinionSP> MinionMap;
275  typedef std::map<const clang::NamespaceDecl *, NamespaceMapSP>
276      NamespaceMetaMap;
277
278  struct ASTContextMetadata {
279    ASTContextMetadata(clang::ASTContext *dst_ctx)
280        : m_dst_ctx(dst_ctx), m_minions(), m_origins(), m_namespace_maps(),
281          m_map_completer(nullptr) {}
282
283    clang::ASTContext *m_dst_ctx;
284    MinionMap m_minions;
285    OriginMap m_origins;
286
287    NamespaceMetaMap m_namespace_maps;
288    MapCompleter *m_map_completer;
289  };
290
291  typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
292  typedef std::map<const clang::ASTContext *, ASTContextMetadataSP>
293      ContextMetadataMap;
294
295  ContextMetadataMap m_metadata_map;
296
297  ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
298    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
299
300    if (context_md_iter == m_metadata_map.end()) {
301      ASTContextMetadataSP context_md =
302          ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
303      m_metadata_map[dst_ctx] = context_md;
304      return context_md;
305    } else {
306      return context_md_iter->second;
307    }
308  }
309
310  ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
311    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
312
313    if (context_md_iter != m_metadata_map.end())
314      return context_md_iter->second;
315    else
316      return ASTContextMetadataSP();
317  }
318
319  MinionSP GetMinion(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx) {
320    ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
321
322    MinionMap &minions = context_md->m_minions;
323    MinionMap::iterator minion_iter = minions.find(src_ctx);
324
325    if (minion_iter == minions.end()) {
326      MinionSP minion = MinionSP(new Minion(*this, dst_ctx, src_ctx));
327      minions[src_ctx] = minion;
328      return minion;
329    } else {
330      return minion_iter->second;
331    }
332  }
333
334  DeclOrigin GetDeclOrigin(const clang::Decl *decl);
335
336  clang::FileManager m_file_manager;
337  typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
338      RecordDeclToLayoutMap;
339
340  RecordDeclToLayoutMap m_record_decl_to_layout_map;
341};
342
343} // namespace lldb_private
344
345#endif // liblldb_ClangASTImporter_h_
346